Tag Archives: retro

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

PL/M-86

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

https://media.henriaanstoot.nl/plm86.zip

Example program Tic Tac Toe I wrote in 1990

Compiling a PLM source code

PLM86 PROGRAM.PLM
LINK86 PROGRAM.OBJ, PLM\DOSLIBS.LIB, PLM\UTILS.LIB TO %1.LNK INITCODE
LINK PROGRAM.LNK;;;

Tic Tac Toe in PLM

bke:do;
/*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 */

$include(plm\doslibs.inc)
$include(plm\doslibs.dcl)
$include(plm\utils.dcl)
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;

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

update:procedure;
item=1;
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;


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

check:procedure;
   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;
end check;


hoofdprogramma:
winnaar=3;
naam(1)=@('Speler 1$');
naam(2)=@('Speler 2$');
naam(3)=@('Niemand$');
do a=1 to 9; plaats(a)=0; end;
teken(1)=@('kruisje$');
teken(2)=@('rondje$');
aanzet=1;

    do loop=1 to 9;
    call update;
    call check;
    if winnaar<>3 then goto gewonnen;
    call spelerzet;
    aanzet=3-aanzet;
    end;
    
call update;
gewonnen:
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);
end;

Went to HCC Retro Meeting. (SDK-85 Update)

UPDATE 20240104

I’ve met Dirk, he brought his SDK85.
And demo-ed a working cassette interface, using audio cables and a second laptop.

Saw a presentation about the MC14500B a weird little chip, robots, retro rebuilds using Raspberries.

Update 20240104 some soldering

Meanwhile .. my old MicroTapes are not using the Intel AP-29 method for data, so that needs some work also.

SDK-85 interface PCB soldered

Using spacers, I can use the existing holes in the SDK to hold the interface PCB in place. Now I have to move my information sheet. 🙂

My scope didn’t save the test capture .. Next time.
But I could see the clear ones and zeros.

You can faintly see the data, stop start of a program is visible.

Dirk cleaned up a OCR version of the program, which I cleaned up some more, and found some errors.
So that should be okay now.

Some old and some new demo stuff

A dentro (Combination of demo and intro.) from 1995

It using only background colors behind existing text to display the dentro text. There is (somewhere) a version with animations.

New work:

Booting from floppy, showing a flash screen in mode 13h.
Starting a trackloader, which loads a raw adlib file and plays it.
All sectors written to floppy using my new sector writer.
WOOT .. music at boot time!

Sector writer

use16
org 0100h
; 0 0 1
; bootblock with flashcode
	mov cl,1  ; start
	mov al,1  ; # sectors
	mov dh,0  ; head
	mov bx,bootblock
	call wrtsector

; flash image
	mov cl,8
	mov al,4
	mov dh,0
	mov bx,gfx
	call wrtsector

; Music loader
	mov cl,7  ; start
	mov al,1  ; # sectors
	mov dh,0  ; head
	mov bx,nextpart
	call wrtsector

; Music raw
	mov cl,13  ; start
	mov al,4  ; # sectors
	mov dh,0  ; head
	mov bx,musicraw
	call wrtsector

	jmp do_exit

printerror:
	push cs		; make ds same as cs
	pop ds
	MOV DX,TxtErr1	; error
	MOV AH,09h
	INT 21h
	mov ax,4c00h
	int 21h
do_exit:
	mov ax,4c00h
	int 21h
wrtsector:
;       On entry:      AH         03h
;                      AL         Number of sectors to write
;                      CH         Cylinder number (10-bit value; upper 2 bits
;                                 in CL)
;                      CL         Starting sector number
;                      DH         Head number
;                      DL         Drive number
;                      ES:BX      Address of memory buffer
; 
;       Returns:       AH         Status of operation (See Service 01h)
;                      AL         Number of sectors written
;                      CF         Set if error, else cleared

	cld
	mov ah, 3h    ; int13h function 2
	mov ch, 0     ; from cylinder number 0
	mov dl,0
	push cs 
	pop es
	int 13h
	jc printerror
ret

TxtErr1:	 DB "Error!",7,10,13,"$"

bootblock:
	file 'flash_b.bin'
gfx:
	file 'flashgfx.raw'
nextpart:
	file 'nextpart.bin'
musicraw:
	file 'LVLINTRO.RAW' 

I wanted to know how a floppy differs from a floppy.
So i wrote below code to fill each sector on a floppy disk or image with information at the start of each sector.
(Head, Cylinder and Sector)

empty.bin was made using
dd if=/dev/zero of=empty.bin count=1 bs=512

use16
org 0100h

	mov ch,0  ; cyl
	mov cl,1  ; sector
	mov dh,0  ; head
nextsector:
	mov bx,empty
	mov [empty],dh
	mov [empty+1],ch
	mov [empty+2],cl
	push cx
	push ax
	push dx
	call printer
	call wrtsector
	pop dx
	pop ax
	pop ax
	inc cl
	cmp cl,19
	jnz nextsector
	mov cl,1
	inc ch
	cmp ch,79
	jnz nextsector
; other side
	mov dh,1
	mov ch,0
	mov cl,1

nextsector1:
	mov bx,empty
	mov [empty],dh
	mov [empty+1],ch
	mov [empty+2],cl
	push cx
	push ax
	push dx
	call wrtsector
	pop dx
	pop ax
	pop ax
	inc cl
	cmp cl,19
	jnz nextsector1
	mov cl,1
	inc ch
	cmp ch,79
	jnz nextsector1


	jmp do_exit

printerror:
	push cs		; make ds same as cs
	pop ds
	MOV AX,3	; default text mode 3
	INT 10h
	MOV DX,TxtErr1	; error
	MOV AH,09h
	INT 21h
	mov ax,4c00h
	int 21h


do_exit:
	mov ax,3
	int 10h
	mov ax,4c00h
	int 21h

printer:
	push cx
	push dx
	mov dl,dh
	mov ah, 02h
	add dl, 30h
	int 21h
	mov dl,ch
	add dl, 30h
	int 21h
	mov dl,cl 
	add dl, 30h
	int 21h
	mov dx,13
  mov ah,2
  int 21h  
  mov dx,10
  mov ah,2
  int 21h
	pop dx
	pop cx
	ret

wrtsector:
;       On entry:      AH         03h
;                      AL         Number of sectors to write
;                      CH         Cylinder number (10-bit value; upper 2 bits
;                                 in CL)
;                      CL         Starting sector number
;                      DH         Head number
;                      DL         Drive number
;                      ES:BX      Address of memory buffer
; 
;       Returns:       AH         Status of operation (See Service 01h)
;                      AL         Number of sectors written
;                      CF         Set if error, else cleared
;

	cld
	mov ah, 3h    ; int13h function 2
	mov al,1
	mov dl,0
	push cs 
	pop es
	int 13h
	jc printerror
ret

TxtErr1:	 DB "Error!",7,10,13,"$"

empty:
	file 'empty.bin'

Viewing the floppy image with ghex

Offset 7000 = Head 1, Cylinder 1 and sector 3

When doing
times 512 – ($-$$) db 0
to fill binaries to 512 bytes, you could cat the sectors to a disk/file with this knowledge.

80×86 boot demo generic work plus code optimalisation and tricks

Writing tools and effects for my new boot demo.

  • Started a generic sector read/writer
  • Some effects
  • A sin/cos data writer to include into your source
  • Working on a library of functions (sector loaders, color palette, vert/hor retrace functions)
  • Laying out a memory map for the demo

Below the output of the sin/cos generator ( see used in video below )
(It also shows a visual plot of the function)

Source code python script

# importing the required module
import matplotlib.pyplot as plt
import numpy as np
import math

# Change these
numberofdatapoints = 360
maxamp = 180
howmuchfromwave = 0.5
numberofharmonies = 1
# Number of harmonies are sin/cos additions in the calculation line below

# not here
step = 360/numberofdatapoints*howmuchfromwave
offset = maxamp
maxamp = maxamp / numberofharmonies
offset = 0


x = [ ]

for xv in range(numberofdatapoints):
    xvstep=xv * step
# Calculation line
#    datapoint=np.sin(math.radians(xvstep))
# Double harmony example
    datapoint=np.sin(math.radians(xvstep)) + (np.sin(math.radians(xvstep*3))/2)

    datapoint=datapoint * maxamp
    datapoint=datapoint + offset
    x.append(int(datapoint))

print("    db ", end="")
print(*x, sep = ",") 
  
# plotting the points 
plt.plot(x)
  
# naming the x axis
plt.xlabel('x - axis')
# naming the y axis
plt.ylabel('y - axis')
  
# giving a title to my graph
plt.title('Example')
  
# function to show the plot
plt.show()

Minimalistic very fast boot loader flash screen effect

Graffiti bouncher test (probably ends up bounching a 320×400 image)
This one uses the generated sintab (Using the python script above)

Test code for a text scroller

Code optimalisation/tricks

clear a (double) register?
xor ax,ax
is faster than
mov ax,0h

Want to make ds pointer same as cs?
Instead of
mov ax,cs
mov ds,ax
use
push cs
pop ds

self modifying code
mostly we just move data around, but you also can change the runtime code (instructions)

  • a – increment ax on line 103h
  • b – another part of the code/maybe in a interrupt
    10Fh load al with 48h (thats the opcode for decrement (see c)
    111h place the opcode in address 103h, which had 40h ..
    Now we changed the code to decrement next time

Speedcode/unrolled code

Populair on the C64 where resources are even more limited, you could use speedcode.
Most of the speedcode you generate, due to its repeating lines.
When looking at clock cycles you can save some extra cycles, by using a little more memory but saving on “expensive” loops.

Simple example

Left a funtion with a loop, right is the same but all instuctions sequencial

Left 15 bytes but 284 cycles

Right 39 bytes but only 102 cycles!

4
4
; below part 9 times
9
3
4
16 or 4
= 284 cycles

Speedcode
4
2 ; xor is faster
9
3 ; even 2 when you can use BX pair!
9
3
9
3
9
3
9
3
9
3
9
3
9
3
9
= 111 cycles (or 102 BX pair)

Moving memory blocks (No DMA)

;DS:(E)SI to address ES:(E)DI
    push cs          ; example to set es to code segment
    pop es
    mov si,1000      ; offset pointer source
    xor di,di        ; destination offset
    mov cx,320*100   ; number of transfers (See below words)
    mov ax,0a000h    ; Destination
    mov es,ax        ; destination segment 
    cld              ; Clear direction flag set SI and DI to auto-increment
    rep movsw        ; repeat mov words! until number of transfers is 0
;  

Short binary > bcd > dec (ascii) convert for numbers (0-99)

mov ax,01ch ; = 28 
mov bx,0ah ; = 10
div bl ; divide BL by AX
       ; AX = 0802 ; Remainder/Divider
xchg ah,al ; change around (dont use if you want to keep little endian)
add ax,3030h ; offset to ascii 30=0 31=1
             ; ax ends up with 3238 .. 28 

Melting effect in 8086, using only register manipulation

(NOTE, Dosbox can’t cope with the register speed, use real HW or PCem)

Effect using a edited photo I made from fireworks ..

Generating a RAW image and Palette, a in a new way

This bash script to convert BMP to Raw and a compiled colorpalette.
(Note: this converts to 8 bit depth, the assembly code in the final assemby program converts to 6 for VGA mode 13h

So this time, i won´t have to use the standard VGA palette as mentioned in previous posts.
(Gimp colors > indexed (255 colors) ; save as BMP, exclude colorspace information)

I’m using identify to extract the colorpalette, which i’m converting to DB entries for the fasm compiler

#!/bin/bash
if [ $# -lt 1 ] ; then
	echo "$0 filename"
	exit 0
fi
size=$(stat $1 | grep Size | awk '{ print $2 }')
skipsize=$(( $size - 64000))
dd if=$1 of=$1.raw skip=$skipsize bs=1

identify -verbose $1 | awk '/Colormap:/,/Rendering/' | grep -v Colormap | grep -v Rendering | awk '{ print $2 } ' | tr -d '()' | while read ; do echo "db $REPLY" ;done > data.asm
fasm data.asm

Code

use16
org 0x100

; variables
CRTC_INDEX = 0x03D4
CRTC_DATA = 0x03D5
INPUT_STATUS = 0x03DA
HRETRACE = 0x01
VRETRACE = 0x03 ; bit 3 =8 ?
MAXIMUM_SCAN_LINE = 0x09
LINE_OFFSET = 0x13

; bar
upperbar = 1
lowerbar = 399

jmp start
; memory locations for data
updown dw 1
direction DB 0
filename DB "firework.raw",0
oldline db 0


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

; clear screen routine, not really needed
clearscreen:
	push ax
	mov ax, 0a000h
	mov es, ax
	pop ax
	xor di, di
	inc ax
	mov cx, 64000 ; 320x200
	rep stosb
; set colors
; call file loader 
	call Loadfile
	call setpalette

; Move loaded file to Screen memory
	mov ax,0a000h
	mov es,ax
	mov ax,6000h
	mov ds,ax
	mov si,0
	mov di,0
	mov cx,320*200/2
	rep movsw

	push cs
	pop ds

;	store org effect2 values
	mov dx, CRTC_INDEX
	mov al,LINE_OFFSET
	out dx,al
	mov dx, CRTC_DATA
	in al,dx
	mov [oldline],al


; after displaying the image or displaying an error, wait for keypress to exit
waitforkeyloop:
	call effect 	; Calling the effect
	MOV AH,1
	INT 16h
	JZ waitforkeyloop
	XOR AH,AH
	INT 16h
Exit:
	MOV AX,3	; default text mode 3
	INT 10h
	MOV AX,4C00h	; exit to dos (terminate process)
	INT 21h
; loop ends here

; Loads raw 64000 bytes image to screen memory
Loadfile:
	push ds
	MOV DX,filename
	MOV AX,3D00h	; open filehandle
	INT 21h
	JC Err1
	MOV BX,AX   	; filehandle
	MOV CX,64000
	mov dx,06000h 	; destination 0000:a000h - Screen memory
	mov ds,dx
	MOV DX,0
	MOV AH,3Fh	; read from file
	INT 21h
	JC  Err1
	MOV AH,3Eh	; close filehandle
	INT 21h
	pop ds
RET

; print error
Err1:
	push cs		; make ds same as cs
	pop ds
	MOV AX,3	; default text mode 3
	INT 10h
	MOV DX,TxtErr1	; error
	MOV AH,09h
	INT 21h
	RET

effect:
	cli		; stop interrupts
	call waitvretrace	; wait for vertical retrace

; gets start scanline and direction
	mov ax,[updown]
	mov cl,[direction]
	cmp cl,0		; 0 move down
	jz	addcounter
	dec ax
	dec ax
	cmp ax,upperbar  	; reached upper bar ?
	jnz gohere ; jnz
	mov cl,0
	mov [direction],cl
	jmp gohere
addcounter:
	inc ax
	inc ax
	cmp ax,lowerbar		; reached bottom bar?
	jnz gohere 	;jnz
	mov cl,1		; change direction
	mov [direction],cl
gohere:
	mov [updown],ax		; store new location

; al = scanline, call wait for scanline
	call longwaithretrace
; other effect
        mov dx, CRTC_INDEX
        mov al, LINE_OFFSET
        out dx,al
        mov dx, CRTC_DATA
        mov al, 0
        out dx,al


; wait scanlines (height of bar)
	mov ax,400
	mov cx,[updown]
	sub ax,cx
	call longwaithretrace

; restore effect2
        mov dx, CRTC_INDEX
        mov al, LINE_OFFSET
        out dx, al
        mov dx, CRTC_DATA
        mov al, [oldline]
        out dx,al
		
	sti	; start interrupts again
	ret

; routine that fixes 8 to 6 bits and sets palette
setpalette:
	; 8 bits to 6 
	mov si,coltab
	mov cx,256*3
	rest:
		mov al,[si]
		shr al,2
		mov [si],al
		dec cx
		inc si
		cmp cx,0
		jnz rest
; now set colors
	mov dx,3c8h
	xor al,al
	out dx,al
	inc dx
	mov si,coltab
	mov cx,256*3
	rep outsb
ret


; this waits for vertical retrace
waitvretrace:
	mov dx,INPUT_STATUS
	waitv1:
		in al,dx
		test al,8
		jnz waitv1
	waitv2:
		in al,dx
		test al,8
		jz waitv2
ret

; routine that waits for horizontal retrace
waithretrace:
	mov cl,al
	mov dx,INPUT_STATUS
	waith1:
		in al,dx
		test al,1
		jnz waith1
	waith2:
		in al,dx
		test al,1
		jz waith2
		dec cl
		cmp cl,0
		jnz waith1
ret

longwaithretrace:
	mov cx,ax
	mov dx,INPUT_STATUS
	lwaith1:
		in al,dx
		test al,1
		jnz lwaith1
	lwaith2:
		in al,dx
		test al,1
		jz lwaith2
		dec cx
		cmp cx,0
		jnz lwaith1
ret
TxtErr1 DB "firework.raw not found!",7,10,13,"$"

coltab: 
include 'data.asm'

Micro Adlib player in Assembly

Plays RAW adlib songs in 100 lines of code … kindda

Using information from here:
https://moddingwiki.shikadi.net/wiki/RAW_Format_(Adlib)

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!

CODE

use16
org 0x100

ctrlreg=0388h
datareg=0389h


mainloop:
	; 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

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

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

lraw:
	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
	ret

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

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

skipr:
; sends data to the control and data registers
	mov dx,ctrlreg
	mov al,[highlow]
	cmp al,0
	je regokay
	inc dx
	inc dx
regokay:
	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
regokay2:
	mov al,cl
	out dx,al
	call waitlong
	inc bx
	inc bx
	jmp lraw

waitshort:
	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
	ret

waitlong:
	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
	ret

waitmore:
; 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
waitloop:
	mov ax,0h
	int 1ah
	cmp bx,dx
	jnz waitloop
	pop dx
	pop cx
	pop bx
	pop ax
	ret

exit:
	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

tune:
	file 'RAWSONG.RAW'

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

use16
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

loophere:
	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
    cld
    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

setpal:	
    mov dx,3c8h
    xor al,al
    mov di, ax
    out dx,al
    inc dx
    mov cx,256*3
    mov si,07e00h
    rep outsb
    ret
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 🙂

use16
org 0x100

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

; clear screen routine, not really needed
clearscreen:
	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
waitforkeyloop:
	MOV AH,1
	INT 16h
	JZ waitforkeyloop
	XOR AH,AH
	INT 16h
Exit:
	MOV AX,3	; default text mode 3
	INT 10h
	MOV AX,4C00h	; exit to dos (terminate process)
	INT 21h

Loadfile:
	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 DX,0
	MOV AH,3Fh	; read from file
	INT 21h
	JC  Err1
	MOV AH,3Eh	; close filehandle
	INT 21h

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

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

Tomorrow .. back to the track loader