Tag Archives: old-computers

A “new” sound chip for 6502

UPDATE: 20240225

I’ve written about General Instrument AY-3-8910 before, here is some work I did today.

This sound chip i wanted to implement in my amiga, and now it’s a alternative for my 6502 computer. ( As an alternative setup for the SID chip. )
Btw this is the same kind of chip used in the Atari ST.

A clean setup … I’ve got the sound chip and a Amplifier chip.

Above a Kicad drawing I made today, a little different from my design from the 90’s.

Below a movie clip I recorded today. Running a test setup using an Arduino nano and a sdcard reader.
The sound is bad, this is due to clipping and the absence of multiple resistors and capacitors.
Music is a register dump from a YM music file.
Amplifier is a bare LM386.

UPDATE: 20240225

I don’t like tying those three outputs together, and amplifying those.

So I’m going to use a LM324 i’ve got left from my 8085 interface, and make a 3-channel amplifier.

Something like this

Soldering a 6502 PCB

A while ago I started a soldering a 6502 bare SBC.

Note pin 1 is not connected, VPB (vector pull is not supported on this PCB. But i’m planning to design a new one anyway.)

I got it running now.

It has an EPROM with Wozmon and Basic for now.
I have to redo the address decoder, but I like the simple serial interface by Geoffrey. (I hate the PIC18F15Q41, made by Microchip, but still the best minimal option .. for now)

Probably the last time i’ve used a pic was in 1998


I’ve posted in the past something about pl/m.
Today i got this running again in a dosbox.

The PL/M programming language (an acronym of Programming Language for Microcomputers) is a high-level language conceived and developed by Gary Kildall in 1973 for Intel’s microprocessors.

A link to information about Gary, and ebook (pdf) he wrote.

We learned to program PL/M at school (MTS)

Below the compiler and lib files


Example program Tic Tac Toe I wrote in 1990

Compiling a PLM source code


Tic Tac Toe in PLM

/*DOEL:                                              */
/*Dit programma is boter kaas en eieren voor twee    */
/*spelers, er wordt gecontroleerd of iemand gewonnen */
/*heeft. (Je speelt niet tegen de computer)          */
/*UPDATE:12/2/90,15/2/90,18/2/90  RELDATE:19/2/90    */
/*PROGRAMMER:H.M.Aanstoot                            */
/*UPDATE 5/3/90 1:13:23                              */
/*De volgende 4 regels zorgen ervoor dat de compiler */
/*de PLM  DOS,UTIL routines die op disk staan        */
/*meestuurt naar de linker                           */
/* bla bla 2de versie met STRINGS!! eindelijk gelukt */

dcl naam(3)           pointer;
dcl plaats(9)         word;
dcl teken(2)          pointer;
dcl aanzet            word;
dcl loop              word;
dcl a                 word;
dcl winnaar           word;
dcl nummer            word;
dcl item              word;
dcl error_status      word;

call dsso(naam(aanzet));
call dsso(@(', geef een getal: $'));
if nummer<1 or nummer>9 then goto invoer;
if plaats(nummer)<>0 then goto invoer;
call dso(nummer+48);
end spelerzet;

call dsso(@(cr,lf,'+-----+-----+-----+',cr,lf,eos));
call dsso(@('|     |     |     |',cr,lf,eos));
call dso(124);call zet;call dso(124);call zet;call dso(124);call zet;
 call dsso(@(124,cr,lf,eos));
call dsso(@('|     |     |     |',cr,lf,eos));
call dsso(@('+-----+-----+-----+',cr,lf,eos));
call dsso(@('|     |     |     |',cr,lf,eos));
call dso(124);call zet;call dso(124);call zet;call dso(124);call zet;
 call dsso(@(124,cr,lf,eos));
call dsso(@('|     |     |     |',cr,lf,eos));
call dsso(@('+-----+-----+-----+',cr,lf,eos));
call dsso(@('|     |     |     |',cr,lf,eos));
call dso(124);call zet;call dso(124);call zet;call dso(124);call zet;
 call dsso(@(124,cr,lf,eos));
call dsso(@('|     |     |     |',cr,lf,eos));
call dsso(@('+-----+-----+-----+',cr,lf,eos));

  call dsso(@('    1   2   3',cr,lf,eos));
  call dsso(@('    4   5   6',cr,lf,eos));
  call dsso(@('    7   8   9',cr,lf,eos));
end update;

if plaats(item)=0 then call dsso(@('     $'));
if plaats(item)=1 then call dsso(@('  X  $'));
if plaats(item)=2 then call dsso(@('  O  $'));
end zet;

   do a=1 to 2;
   if plaats(1)=a and plaats(2)=a and plaats(3)=a then winnaar=a;
   if plaats(4)=a and plaats(5)=a and plaats(6)=a then winnaar=a;
   if plaats(7)=a and plaats(8)=a and plaats(9)=a then winnaar=a;

   if plaats(1)=a and plaats(4)=a and plaats(7)=a then winnaar=a;
   if plaats(2)=a and plaats(5)=a and plaats(8)=a then winnaar=a;
   if plaats(3)=a and plaats(6)=a and plaats(9)=a then winnaar=a;

   if plaats(1)=a and plaats(5)=a and plaats(9)=a then winnaar=a;
   if plaats(3)=a and plaats(5)=a and plaats(7)=a then winnaar=a;
end check;

naam(1)=@('Speler 1$');
naam(2)=@('Speler 2$');
do a=1 to 9; plaats(a)=0; end;

    do loop=1 to 9;
    call update;
    call check;
    if winnaar<>3 then goto gewonnen;
    call spelerzet;
call update;
call dsso(naam(winnaar));
call dsso(@(' heeft gewonnen',cr,lf,eos));
if winnaar=3 then call dsso(@('Helaas, pindakaas!$'));
			 else call dsso(@('Gefeliciteerd ermee!$'));

call dexit(error_status);

Micro Adlib player in Assembly

Plays RAW adlib songs in 100 lines of code … kindda

Using information from here:

And using fasm to compile I can play captured raw songs.

But something is still off ?!?

It sounds a little different, and I need to implement a better timer routine. (Below my version and opencubicplayer)

This is a test for my bootloader, playing music from my bootblock!


org 0x100


	; set speed (Byte 8,9 from the raw file)
	mov ax,[tune+8]
	mov [clockspeed],ax
	; call player
	call rawreg
	; wait 0.5 sec for exit
	mov bx,6
	call waitmore
	jmp exit

	mov bx,tune+0ah		; start of song at offset ah

; order registerdata, register!
; Are there more control codes? ???

	mov cx,[bx]
; reg = 2 - check data
	cmp ch,2
	je checkreg2
; reg = 0 - cyclewait
	cmp ch,0
	je cyclewait
; data = FFFF - end song - end play routine
	cmp cx,0ffffh
	jne skipr

cyclewait:		; waits cl times waitroutine
	call waitlong
	dec cl
	jnz cylloop
	inc bx
	inc bx
	jmp lraw

; check low opl
	cmp cl,1
	jne checkh
	mov ch,0
	mov [highlow],ch
	jmp incandret
; check high opl
	cmp cl,2
	jne check00
	mov ch,1
	mov [highlow],ch
	jmp incandret
; set new speed
	cmp cl,0
	jne incandret
	inc bx
	inc bx
	mov ax,[bx]
	mov [clockspeed],ax
; next double byte in the song please
	inc bx     
	inc bx     
	jmp lraw

; sends data to the control and data registers
	mov dx,ctrlreg
	mov al,[highlow]
	cmp al,0
	je regokay
	inc dx
	inc dx
	mov al,ch
	out dx,al
;	call waitshort ; not needed for newer adlib cards
	mov dx,datareg
	mov al,[highlow]
	cmp al,0
	je regokay2
	inc dx
	inc dx
	mov al,cl
	out dx,al
	call waitlong
	inc bx
	inc bx
	jmp lraw

	push ax
	push cx
	push dx
	mov cx, 0      ;HIGH WORD.
	mov dx, 010h ;LOW WORD.
	mov ah, 86h    ;WAIT.
	int 15h
	pop dx
	pop cx
	pop ax

	push bx
	push ax
	push cx
	push dx
	mov cx, 0      ;HIGH WORD.
	mov dx, [clockspeed]
	shr dx,1
	mov ah, 86h    ;WAIT.
	int 15h
	pop dx
	pop cx
	pop ax
	pop bx

; in bx == 12h is 1 sec
; destroys ax,bx,cx,dx
	push ax
	push bx
	push cx
	push dx
	mov ax,0h
	int 1ah
	add dx, bx
	mov bx,dx
	mov ax,0h
	int 1ah
	cmp bx,dx
	jnz waitloop
	pop dx
	pop cx
	pop bx
	pop ax

	mov dx,0388h
	mov al,0b0h
	out dx,al
	inc dx
	xor al,al
	out dx,al
	mov ax,04c00h
	int 21h

clockspeed: dw 0

highlow:	db 0


Rewrote 8086 bootblock trackloader

Loading a 320×200 image from 14 cilinders. There is no msdos on the floppy!

9 sectors, 14 cilinders, 1 head * sector size (512 bytes) = 64512 bytes

Mode 13h (320×200 265 colors)

Cuting the raw part from a BMP (see previous post)

root@battlestation:/mnt/# ls -la MAD.bmp
-rw-rw-r-- 1 fash fash 65078 Sep 14 15:57 MAD.bmp

I need 64000 bytes (320x200)
65078-64000 = 1078

root@battlestation:/mnt/# dd if=MAD.bmp of=mad.raw skip=1078 bs=1
64000+0 records in
64000+0 records out
64000 bytes (64 kB, 62 KiB) copied, 0.441618 s, 145 kB/s

I use debug to write to the sectors

debug mad.raw
-w100 0 9 7f
(write from address 100 drive=0 startsector=9 (cylinder 1) and 7f sectors long

Wrote a little sector viewer to debug/view data written.

  • r – read sector again
  • s – next sector (shift previous)
  • c – next cylinder (shift previous)
  • h – toggle head 0 – 1
  • p – load palette from current 2 sectors
  • l – clear screen
  • 1 – goto graphic mode
  • 2 – goto text mode and show sector,head and cylinder info
  • q – quit
  • -/+ tweak palette offset ( was needed for debugging

I will post the code after some code cleaning and adding some comments

Boot loader with image 320×200 256 colors.

This is a work in progress, below are my Lab notes.

I want to rewrite pieces we made for a demo, loading images and effects from a floppydisk bootloader.

Without looking at old code (which was written using Masm), I wanted to learn the steps using Fasm.

I started with a boot sector program, It should do the following.

  • Set graphic mode, and start a trackloader
  • Load sector 2 and 3 which contains the color palette for the image.
  • Next sectors, cylinders and heads contain the raw image

I got it working, half that is.
In the past I used real disks, and now a virtual disk, maybe thats the difference?

First Code

org 0x7c00

mov ah,0x0
mov al,0x13
int 10h

mov ax, 0a000h
mov es, ax
xor di, di
mov ax, 50
mov cx, 64000
rep stosb

	jmp loophere

times 510 - ($-$$) db 0

dw 0xaa55

Compiling and starting:

fasm mybootblock.asm
qemu-system-x86_64 --drive format=raw,file=mybootblock.bin

This works, it sets the graphical mode and clears the screen.

Second Code
Skipping the int 25h version

## Track read part
    xor ax, ax    ; DS = 0
    mov ds, ax
    mov ah, 2h    ; int13h function 2 track read
    mov al, 2     ; number of tracks ( should be 2 for reading only palette)
    mov ch, 0     ; from cylinder number 0
    mov cl, 2     ; the sector number 2 - second sector (starts from 1, not 0)
    mov dh, 0     ; head number 0
    xor bx, bx    ; BX = 0
    mov es, bx    ; ES = 0
    mov bx, 7e00h ; Offset from above
    int 13h

    call setpal

## End part with setpalette routine
## appending palette.colors
## and a raw image

    mov dx,3c8h
    xor al,al
    mov di, ax
    out dx,al
    inc dx
    mov cx,256*3
    mov si,07e00h
    rep outsb
times 510 - ($-$$) db 0

dw 0xaa55
include 'palette.colors'

times 2048 - ($-$$) db 0
file 'image.raw'

Seems there is still a header on the RAW file, lets look at how I made this.

NOTE! .. Below converts an image with a STANDARD VGA palette, not a custom one as used above

Looking with ghex at the file I saw that there was a header 0x415 bytes large.
(Probably still palette colors in there)

dd if=shoes.bmp of=cutshoe.bmp bs=1 skip=1078 (0x415h + 3?)
worked for me

Loading the extra tracks didn’t work for me?!?!
But how could I define tracks/sectors and heads on a virtual floppy?

I tried to write sectors using debug.com

start dosbox
imgmount a: /tmp/floppy.img -t floppy
debug.com bootsector.bin
-r bx 01 

-r cx 512
; set bx:cx for size
-w 100 0 0 1
; write from address 100, drive 0 (a), sector 0, number of sectors

; testing
-l 100 0 0 1
;load sector to addr 100 drive 0 sector 0 number of sectors 

This used to work with real disks on a real machine, not in dosbox ?!?!

my way to create a disk in linux

dd if=bootblock.bin of=disk1.img bs=512 count=1 seek=0
dd if=palette.col of=disk1.img bs=512 count=1 seek=1 # or 2?
dd if=shoes.raw of=disk1.img bs=512 count=10000 seek=17

It looks like I can’t read futher than 18 sectors on a virtual floppy.
What next? Head=1? Cylinder=1?
Below the info from a floppy image before altering.

DOS/MBR boot sector, code offset 0x3c+2, OEM-ID “MSDOS5.0”, root entries 224, sectors 2880 (volumes <=32 MB), sectors/FAT 9, sectors/track 18, serial number 0x1c2a0d0f, unlabeled, FAT (12 bit), followed by FAT

Appending the RAW to a executable gave me problems to.
(Without making a bootdisk)

Above and below weird data. Appending the data to the executable needs some work also.

At least for today let me display this image correctly 🙂

org 0x100

; set mode 320x200 256 colors palette
	mov ah,0x0
	mov al,13h
	int 10h

; clear screen routine, not really needed
	push ax
	mov ax, 0a000h
	mov es, ax
	pop ax
	xor di, di
	inc ax
	mov cx, 64000 ; 320x200
	rep stosb

; call file loader 
	call Loadfile

; after displaying the image or displaying an error, wait for keypress to exit
	INT 16h
	JZ waitforkeyloop
	INT 16h
	MOV AX,3	; default text mode 3
	INT 10h
	MOV AX,4C00h	; exit to dos (terminate process)
	INT 21h

	MOV DX,filename
	MOV AX,3D00h	; open filehandle
	INT 21h
	JC Err1
	MOV BX,AX   	; filehandle
	MOV CX,0FFFFh 	; size
	mov dx,0a000h 	; destination 0000:a000h - Screen memory
	mov ds,dx

	MOV AH,3Fh	; read from file
	INT 21h
	JC  Err1
	MOV AH,3Eh	; close filehandle
	INT 21h

; print error
	push cs		; make ds same as cs
	pop ds
	MOV DX,TxtErr1	; error
	MOV AH,09h
	INT 21h

filename DB "shoes.bmp",0
TxtErr1 DB "shoes.bmp not found!",7,10,13,"$"

Tomorrow .. back to the track loader

Mikrotik Wifi, 80386 and Lilygo streaming

Quiet days, I working on some art.

But here are the last ‘prutsen’

My current Wifi setup

I’ve got a Wifi outside of my network for guest and emergency. ( 2 SSIDs)

Then a main Wifi router in my livingroom, one in my workshop/studio and one in the Attic (Electronics Lab)

So three main Wifi AccessPoints. These all have the same SSID’s but on different frequencies. That way i’ve got roaming in and outside my house.
Also some virtual accesspoints are configured.
I’ve got a main, folkband, IOT, guest-inside all on 2.4Ghz and 5Ghz.

I watched a lot of YT presentations about Mikrotik Wifi.

So I ended up with DFS safe channels 20Mhz for 2.4 and 20/40Mhz Ce for 5Ghz. (subchannels for each after some frequency scanning)
(2.4 does a failback to 20Mhz whenever there is even one client detected which connects only on this band. Such as some old IOT stuff)
2.4 in only 1,6 and 11 no overlap, each on another device.
300Mbps is sufficient for my wifi 🙂

I’ve got accesslists in place and i’m going to read into kicking a client when the signal strenght is below -50dB

80386 (DX) Computer

Besides my 8088 and 8086 machines I needed a machine which could run our old demo’s. So I bought a new toy.

It has 8Mb Ram and runs at 40Mhz.

I’ve noticed that many of my VGA register manipulation code, can’t be run on a modern VGA monitor, I need to use a CRT for that .. Another thing to buy

Lilygo T-Display S3 Streaming

Not my code: https://github.com/Steve5451/esp32-stream-desktop
A very cool project!

Needed to fix arduino code, due to the TFT_eSPI library issues.
And I’ve got a S3 with another resolution, but that was an easy fix.
Then needed to reinstall nodejs with another version.
Had to modify the code because the tcp server would not start.
Weird errors logging, but in the end fixed … very cool

I probably end up designing a 3D printed case that looks like a monitor or tv.

My dosbox assembly directory

Below you can find the files in a zip for writing assemby machine code in dosbox.

I’ve got mine extracted in ~/projects/dos

To automount this i’ve edited

;-------- bottom part
# Lines in this section will be run at startup.
# You can put your MOUNT lines here.

mount c: /home/myusername/projects/dos

The files

  • A.BAT – Runs editor, masm,linker (start with a<space>progname
  • DEBUG.COM – msdos debugger
  • EXE2BIN.EXE – exe to com (if segments allow)
  • GFX.ASM – example template (see below)
  • LINK.EXE – masm linker
  • MASM.EXE – masm compiler
  • Q* – editor stuff
  • Q.EXE – editor
  • SR.EXE – sourcer
  • TASM.EXE – turbo assembler
  • TD.EXE – turbo debugger
  • TLINK.EXE – turbo linker


; everything in 64k CS, DS, and SS are the same
.model small
; start pointer
.stack 100h
	; set mode 13 (320x200 * 265 colors palette)
    mov ah,0	
    mov al,13h
    int 10h

    ; set pixel in the middle color 2 (cyan)
    mov ah,0ch
    mov al,2
    mov cx,160
    mov dx,100
    int 10h

	; wait key input
    mov ah,0
    int 16h

	; set mode back to text
    mov ah,0
    mov al,3
    int 10h

	; exit to dos
    mov ax,4c00h
    int 21h
end start


start dosbox
a gfx (edit gfx.asm example)
esc, q, e
gfx (run program)


Perviously i’ve posted about PCem

But I wanted to have a emulator which could load extension biosses also.
This for my own tinkering.

I was told to look at MartyPC and PCE/ibmpc

I don´t like it being written in Rust, but it does the job.

Running the Basic Extension Rom
Running one of my own roms. I knew it didn’t work, now i can use the buildin debug to see why!
Another of my test roms, which is working!

ROM config part i’ve got in martypc.toml

rom_override = [
    { path = "./roms/BIOS_5160_09MAY86_U19_62X0819_68X4370_27256_F000.BIN", address = 0xF0000, offset=0, org="Normal" },
    { path = "./roms/BIOS_5160_09MAY86_U18_59X7268_62X0890_27256_F800.BIN", address = 0xF8000, offset=0, org="Normal" },
    { path = "./roms/myromextension.bin", address = 0xF6000, offset=0, org="Normal" }

GLABios for Laser XT/3

In previous post :

I mentioned a 2 ROM setup because the 8086 is 16bits instead of 8.
So I was wondering that maybe a recompile was needed, or the data being split over two roms (odd/even)

The guy from GLABios was so kind to build me two interleaved roms.

So while working on a padded bench, I tested the ROMs.

Working outside .. on the padded bench

Back to the roms, it didn’t work!

But I missed a detail in the technical manual (the bold text)

In Turbo XT /2 and Turbo XT /3, there are two 28-pin sockets for ROM,
both of them are occupied by 2764 which stored the BIOS. The contents
of the two 2764 are identical.
One of them contribute the ODD Byte to the system and the other EVEN Byte. Together they support 16 Bit BIOS

I don’t know why this is how it works, but when I flashed two the same 28C64’s it worked!
(I also tought that is was strange that both original roms had the same markings.

It workes!

Only remarks/observations:

  • There was a longer wait time before the CF Card was detected/accessed
  • GLABios mentions 8088 in the splashscreen, but the machine is a 8086


GLABios was not updated for displaying 8086 yet.
Error 1701 was the (old spinning) harddisk not being connected.

Nice .. harddisk infomation like size, rom address and CHS