ctlQ equ 'Q'-'@'\r
ctlS equ 'S'-'@'\r
\r
-ccp equ 0100h ; Console Command Processor gets loaded\r
- ; into the TPA\r
+ccp equ 0100h ; Console Command Processor gets loaded\r
+ ; into the TPA\r
\r
- cseg ; GENCPM puts CSEG stuff in common memory\r
+ cseg ; GENCPM puts CSEG stuff in common memory\r
\r
\r
; variables in system data page\r
\r
; initialization\r
\r
- extrn hwinit,?init ; general initialization and signon\r
+ extrn hwinit,?init ; general initialization and signon\r
extrn ?ldccp,?rlccp ; load & reload CCP for BOOT & WBOOT\r
\r
; user defined character I/O routines\r
\r
; general utility routines\r
\r
- public ?pmsg,?pdec ; print message, print number from 0 to 65535\r
- public ?pderr ; print BIOS disk error message header\r
+ public ?pmsg ; print message\r
+ public pr.dec,pr.decl ; print 16 or 32 bit decimal number\r
+ public ?pderr ; print BIOS disk error message header\r
+ public pr.inln,pr.crlf ; print message inline\r
+ public phex4,phex2 ; print 4 digit hex (HL), or 2 digit hex (A)\r
+\r
+ extrn div32_16 ; divide 32 bit by 16 bit number\r
\r
include modebaud.inc ; define mode bits\r
\r
\r
; BIOS Jump vector.\r
\r
- ; All BIOS routines are invoked by calling these\r
- ; entry points.\r
-\r
-?boot: jp boot ; initial entry on cold start\r
-?wboot: jp wboot ; reentry on program exit, warm start\r
-\r
-?const: jp const ; return console input status\r
-?conin: jp conin ; return console input character\r
-?cono: jp conout ; send console output character\r
-?list: jp list ; send list output character\r
-?auxo: jp auxout ; send auxiliary output character\r
-?auxi: jp auxin ; return auxiliary input character\r
-\r
-?home: jp home ; set disks to logical home\r
-?sldsk: jp seldsk ; select disk drive, return disk parameter info\r
-?sttrk: jp settrk ; set disk track\r
-?stsec: jp setsec ; set disk sector\r
-?stdma: jp setdma ; set disk I/O memory address\r
-?read: jp read ; read physical block(s)\r
-?write: jp write ; write physical block(s)\r
-\r
-?lists: jp listst ; return list device status\r
-?sctrn: jp sectrn ; translate logical to physical sector\r
-\r
-?conos: jp conost ; return console output status\r
-?auxis: jp auxist ; return aux input status\r
-?auxos: jp auxost ; return aux output status\r
-?dvtbl: jp devtbl ; return address of device def table\r
-?devin: jp ?cinit ; change baud rate of device\r
-\r
-?drtbl: jp getdrv ; return address of disk drive table\r
-?mltio: jp multio ; set multiple record count for disk I/O\r
-?flush: jp flush ; flush BIOS maintained disk caching\r
-\r
-?mov: jp ?move ; block move memory to memory\r
-?tim: jp ?time ; Signal Time and Date operation\r
-?bnksl: jp bnksel ; select bank for code execution and default DMA\r
-?stbnk: jp setbnk ; select different bank for disk I/O DMA operations\r
-?xmov: jp ?xmove ; set source and destination banks for one operation\r
+ ; All BIOS routines are invoked by calling these\r
+ ; entry points.\r
+\r
+?boot: jp boot ; initial entry on cold start\r
+?wboot: jp wboot ; reentry on program exit, warm start\r
+\r
+?const: jp const ; return console input status\r
+?conin: jp conin ; return console input character\r
+?cono: jp conout ; send console output character\r
+?list: jp list ; send list output character\r
+?auxo: jp auxout ; send auxiliary output character\r
+?auxi: jp auxin ; return auxiliary input character\r
+\r
+?home: jp home ; set disks to logical home\r
+?sldsk: jp seldsk ; select disk drive, return disk parameter info\r
+?sttrk: jp settrk ; set disk track\r
+?stsec: jp setsec ; set disk sector\r
+?stdma: jp setdma ; set disk I/O memory address\r
+?read: jp read ; read physical block(s)\r
+?write: jp write ; write physical block(s)\r
+\r
+?lists: jp listst ; return list device status\r
+?sctrn: jp sectrn ; translate logical to physical sector\r
+\r
+?conos: jp conost ; return console output status\r
+?auxis: jp auxist ; return aux input status\r
+?auxos: jp auxost ; return aux output status\r
+?dvtbl: jp devtbl ; return address of device def table\r
+?devin: jp ?cinit ; change baud rate of device\r
+\r
+?drtbl: jp getdrv ; return address of disk drive table\r
+?mltio: jp multio ; set multiple record count for disk I/O\r
+?flush: jp flush ; flush BIOS maintained disk caching\r
+\r
+?mov: jp ?move ; block move memory to memory\r
+?tim: jp ?time ; Signal Time and Date operation\r
+?bnksl: jp bnksel ; select bank for code execution and default DMA\r
+?stbnk: jp setbnk ; select different bank for disk I/O DMA operations\r
+?xmov: jp ?xmove ; set source and destination banks for one operation\r
\r
jp 0 ; reserved for future expansion\r
jp 0 ; reserved for future expansion\r
; BOOT\r
; Initial entry point for system startup.\r
\r
- dseg ; this part can be banked\r
+ dseg ; this part can be banked\r
\r
boot:\r
ld sp,bs$stack\r
\r
- call hwinit ; first time hardware initialisation\r
+ call hwinit ; first time hardware initialisation\r
\r
- ld c,15 ; initialize all 16 character devices\r
+ ld bc,16*256 + 0 ; initialize all 16 character devices\r
c$init$loop:\r
push bc\r
call ?cinit\r
pop bc\r
- dec c\r
- jp p,c$init$loop\r
+ inc c\r
+ djnz c$init$loop\r
\r
- call ?init ; perform any additional system initialization\r
- ; and print signon message\r
+ call ?init ; perform any additional system initialization\r
+ ; and print signon message\r
\r
ld bc,16*256+0\r
- ld hl,@dtbl ; init all 16 logical disk drives\r
+ ld hl,@dtbl ; init all 16 logical disk drives\r
d$init$loop:\r
- push bc ; save remaining count and abs drive\r
+ push bc ; save remaining count and abs drive\r
ld e,(hl)\r
inc hl\r
ld d,(hl)\r
- inc hl ; grab @drv entry\r
+ inc hl ; grab @drv entry\r
ld a,e\r
or d\r
- jr z,d$init$next ; if null, no drive\r
- push hl ; save @drv pointer\r
+ jr z,d$init$next ; if null, no drive\r
+ push hl ; save @drv pointer\r
if 0\r
- ex de,hl ; XDPH address in <HL>\r
+ ex de,hl ; XDPH address in <HL>\r
dec hl\r
dec hl\r
- ld b,(hl) ; get relative drive code\r
- ld (@ADRV),bc ; save absolute and relative drive code\r
- dec hl ; point to init pointer\r
+ ld b,(hl) ; get relative drive code\r
+ ld (@ADRV),bc ; save absolute and relative drive code\r
+ dec hl ; point to init pointer\r
ld d,(hl)\r
dec hl\r
- ld e,(hl) ; get init pointer\r
+ ld e,(hl) ; get init pointer\r
ex de,hl\r
- call ipchl ; call init routine\r
+ call ipchl ; call init routine\r
else\r
push de\r
pop ix\r
ld b,(ix-2)\r
- ld (@ADRV),bc ; save absolute and relative drive code\r
+ ld (@ADRV),bc ; save absolute and relative drive code\r
ld l,(ix-4)\r
- ld h,(ix-3) ; get init pointer\r
- call ipchl ; call init routine\r
+ ld h,(ix-3) ; get init pointer\r
+ call ipchl ; call init routine\r
endif\r
- pop hl ; recover @drv pointer\r
+ pop hl ; recover @drv pointer\r
d$init$next:\r
- pop bc ; recover counter and drive #\r
+ pop bc ; recover counter and drive #\r
inc c\r
- djnz d$init$loop ; and loop for each drive\r
+ djnz d$init$loop ; and loop for each drive\r
jp boot$1\r
\r
cseg ; following in resident memory\r
\r
boot$1:\r
call set$jumps\r
- call ?ldccp ; fetch CCP for first time\r
+ call ?ldccp ; fetch CCP for first time\r
jp ccp\r
\r
\r
\r
wboot:\r
ld sp,bs$stack\r
- call set$jumps ; initialize page zero\r
- call ?rlccp ; reload CCP\r
- jp ccp ; then reset jmp vectors and exit to ccp\r
+ call set$jumps ; initialize page zero\r
+ call ?rlccp ; reload CCP\r
+ jp ccp ; then reset jmp vectors and exit to ccp\r
\r
\r
set$jumps:\r
ret\r
\r
\r
- ds 64\r
+ ds bs$stack$size\r
bs$stack equ $\r
\r
\r
or a\r
jp z,not$out$ready\r
pop bc\r
- push bc ; restore and resave the character and device\r
- call ?co ; if device selected, print it\r
+ push bc ; restore and resave the character and device\r
+ call ?co ; if device selected, print it\r
pop bc ; recover count and character\r
pop hl ; recover the rest of the vector\r
not$out$device:\r
inc b ; next device number\r
ld a,h\r
- or l ; see if any devices left\r
+ or l ; see if any devices left\r
jr nz,co$next ; and go find them...\r
ret\r
\r
add hl,hl ; check next bit\r
push hl ; save the vector\r
push bc ; save the count\r
- ld a,0FFh ; assume device ready\r
+ ld a,0FFh ; assume device ready\r
call c,coster ; check status for this device\r
pop bc ; recover count\r
pop hl ; recover bit vector\r
ret z ; if any not ready, return false\r
inc b ; drop device number\r
ld a,h\r
- or l ; see if any more selected devices\r
+ or l ; see if any more selected devices\r
jr nz,cos$next\r
- or 0FFh ; all selected were ready, return true\r
+ or 0FFh ; all selected were ready, return true\r
ret\r
\r
-coster: ; check for output device ready, including optional\r
- ; xon/xoff support\r
+ ; check for output device ready, including optional\r
+ ; xon/xoff support\r
+coster:\r
ld l,b\r
- ld h,0 ; make device code 16 bits\r
- push hl ; save it in stack\r
+ ld h,0 ; make device code 16 bits\r
+ push hl ; save it in stack\r
add hl,hl\r
add hl,hl\r
- add hl,hl ; create offset into device characteristics tbl\r
+ add hl,hl ; create offset into device characteristics tbl\r
ld de,@ctbl+6\r
- add hl,de ; make address of mode byte\r
+ add hl,de ; make address of mode byte\r
ld a,(hl)\r
and mb$xon$xoff\r
- pop hl ; recover console number in <HL>\r
+ pop hl ; recover console number in <HL>\r
jp z,?cost ; not a xon device, go get output status direct\r
ld de,xofflist\r
- add hl,de ; make pointer to proper xon/xoff flag\r
+ add hl,de ; make pointer to proper xon/xoff flag\r
call cist1 ; see if this keyboard has character\r
ld a,(hl)\r
- call nz,ci1 ; get flag or read key if any\r
+ call nz,ci1 ; get flag or read key if any\r
cp ctlq\r
jr nz,not$q ; if its a ctl-Q,\r
ld a,0FFh ; set the flag ready\r
jr nz,not$s ; if its a ctl-S,\r
ld a,00h ; clear the flag\r
not$s:\r
- ld (hl),a ; save the flag\r
+ ld (hl),a ; save the flag\r
call cost1 ; get the actual output status,\r
- and (hl) ; and mask with ctl-Q/ctl-S flag\r
+ and (hl) ; and mask with ctl-Q/ctl-S flag\r
ret ; return this as the status\r
\r
-cist1: ; get input status with <BC> and <HL> saved\r
+cist1: ; get input status with <BC> and <HL> saved\r
push bc\r
push hl\r
call ?cist\r
or a\r
ret\r
\r
-cost1: ; get output status, saving <BC> & <HL>\r
+cost1: ; get output status, saving <BC> & <HL>\r
push bc\r
push hl\r
call ?cost\r
or a\r
ret\r
\r
-ci1: ; get input, saving <BC> & <HL>\r
+ci1: ; get input, saving <BC> & <HL>\r
push bc\r
push hl\r
call ?ci\r
ret nz ; if any ready, return true\r
inc b ; next device number\r
ld a,h\r
- or l ; see if any more selected devices\r
+ or l ; see if any more selected devices\r
jr nz,cis$next\r
xor a ; all selected were not ready, return false\r
ret\r
jp ?ci\r
\r
\r
-; Utility Subroutines\r
+;-------------------------------------------------------------------------------\r
+; Utility Subroutines\r
\r
\r
ipchl: ; vectored CALL point\r
jp (hl)\r
\r
\r
-?pmsg: ; print message @<HL> up to a null\r
- ; saves <BC> & <DE>\r
+;-------------------------------------------------------------------------------\r
+; print message @<HL> up to a null\r
+; saves <BC> & <DE>\r
+\r
+?pmsg:\r
push bc\r
push de\r
pmsg$loop:\r
pop bc\r
ret\r
\r
-?pdec: ; print binary number 0-65535 from <HL>\r
- ld bc,table10\r
- ld de,-10000\r
-next:\r
- ld a,'0'-1\r
-pdecl:\r
+;-------------------------------------------------------------------------------\r
+; print message inline up to a null\r
+; saves all registers\r
+\r
+pr.inln:\r
+ ex (sp),hl\r
+ push af\r
+ call ?pmsg\r
+ pop af\r
+ ex (sp),hl\r
+ ret\r
+\r
+;-------------------------------------------------------------------------------\r
+; print <CR><LF>\r
+; saves all registers\r
+\r
+pr.crlf:\r
+ call pr.inln\r
+ db 13,10,0\r
+ ret\r
+\r
+;-------------------------------------------------------------------------------\r
+; print hl as a 4 digit hexadecimal number\r
+; saves all registers\r
+\r
+phex4:\r
+ ld a,h\r
+ call phex2\r
+ ld a,l\r
+ ; fall thru\r
+\r
+;-------------------------------------------------------------------------------\r
+; print a as a 2 digit hexadecimal number\r
+; saves all registers\r
+\r
+phex2:\r
+ push af\r
+ rra\r
+ rra\r
+ rra\r
+ rra\r
+ call print.digit\r
+ pop af\r
+\r
+print.digit:\r
push hl\r
- inc a\r
- add hl,de\r
- jp nc,stoploop\r
- inc sp\r
- inc sp\r
- jp pdecl\r
-stoploop:\r
push de\r
push bc\r
+ push af\r
+ and 00fh\r
+ cp 10\r
+ jr c,prd_1\r
+ add a,007h\r
+prd_1:\r
+ add a,'0'\r
+\r
ld c,a\r
call ?cono\r
+ pop af\r
pop bc\r
pop de\r
-nextdigit:\r
pop hl\r
- ld a,(bc)\r
+ ret\r
+\r
+\r
+;-------------------------------------------------------------------------------\r
+; print decimal 16 bit number from HL\r
+;\r
+; HL: unsigned binary number to print\r
+; C: minimum print field width\r
+; number is prined right-aligned\r
+; B: pad character, typically ' ' or '0'\r
+\r
+pr.dec:\r
+ push de\r
+ ld de,0\r
+ call pr.decl\r
+ pop de\r
+ ret\r
+\r
+;-------------------------------------------------------------------------------\r
+; print decimal 32 bit number from DEHL\r
+;\r
+; DEHL: unsigned binary number to print\r
+; C: minimum print field width\r
+; number is prined right-aligned\r
+; B: pad character, typically ' ' or '0'\r
+\r
+pr.decl:\r
+ push bc ;save width and fillchar\r
+ push bc\r
+ exx ;(alt)\r
+ ex (sp),hl ;save hl', get width and fill\r
+ push de ;save de'\r
+\r
+ xor a\r
+ ld d,a ;clear counter\r
ld e,a\r
- inc bc\r
- ld a,(bc)\r
- ld d,a\r
- inc bc\r
+ push af ; string terminator\r
+ inc sp\r
+\r
+prd_divloop: ;do\r
+ exx ; (main)\r
+ ld bc,10 ;\r
+ call div32_16 ; get a digit\r
+ ld a,c ;\r
+ add a,'0' ; make it printable\r
+ push af ;\r
+\r
+ ld a,h ;\r
+ or l ;\r
+ or d ;\r
+ or e ;\r
+ exx ; (alt)\r
+ inc sp ;\r
+ inc de ;\r
+ jr nz,prd_divloop ;\r
+\r
+prd_filloop: ;h=filler, l=field width\r
ld a,e\r
- or d\r
- jp nz,next\r
+ cp l\r
+ jr nc,prd_out\r
+ push hl\r
+ inc sp\r
+ inc de\r
+ jr prd_filloop\r
+prd_out:\r
+ ld hl,0\r
+ add hl,sp ;ptr to beginning of number string (hl==0 here)\r
+ call ?pmsg\r
+ ex de,hl\r
+ add hl,sp\r
+ ld sp,hl\r
+ inc sp ;remove string terminator\r
+ pop de\r
+ pop hl\r
+ exx ;(main)\r
+ pop bc\r
ret\r
\r
-table10:\r
- dw -1000,-100,-10,-1,0\r
\r
+;-------------------------------------------------------------------------------\r
+;\r
?pderr:\r
ld hl,drive$msg\r
- call ?pmsg ; error header\r
+ call ?pmsg ; error header\r
ld a,(@adrv)\r
add a,'A'\r
ld c,a\r
- call ?cono ; drive code\r
+ call ?cono ; drive code\r
ld hl,track$msg\r
- call ?pmsg ; track header\r
+ call ?pmsg ; track header\r
+ ld c,0\r
ld hl,(@trk)\r
- call ?pdec ; track number\r
+ call pr.dec ; track number\r
ld hl,sector$msg\r
- call ?pmsg ; sector header\r
+ call ?pmsg ; sector header\r
ld hl,(@sect)\r
- call ?pdec ; sector number\r
+ call pr.dec ; sector number\r
ret\r
\r
\r
; Bank Select. Select CPU bank for further execution.\r
\r
bnksel:\r
- ld (@cbnk),a ; remember current bank\r
- jp ?bank ; and go exit through users\r
- ; physical bank select routine\r
+ ld (@cbnk),a ; remember current bank\r
+ jp ?bank ; and go exit through users\r
+ ; physical bank select routine\r
\r
\r
xofflist:\r
; in <HL>\r
\r
seldsk:\r
- ld a,c ; save drive select code\r
+ ld a,c ; save drive select code\r
ld (@adrv),a\r
- ld b,0 ; create index from drive code\r
+ ld b,0 ; create index from drive code\r
ld hl,@dtbl\r
- add hl,bc ; get pointer to dispatch table\r
+ add hl,bc ; get pointer to dispatch table\r
add hl,bc\r
ld a,(hl)\r
inc hl\r
ld h,(hl)\r
- ld l,a ; point at disk descriptor\r
- ld (@xdph),hl ; save descriptor pointer\r
+ ld l,a ; point at disk descriptor\r
+ ld (@xdph),hl ; save descriptor pointer\r
or h\r
- ret z ; if no entry in table, no disk\r
+ ret z ; if no entry in table, no disk\r
\r
- ld a,e ; examine login bit\r
+ ld a,e ; examine login bit\r
and 1\r
ret nz\r
\r
push ix\r
ld ix,(@xdph)\r
ld a,(ix-2)\r
- ld (@RDRV),a ; get relative drive\r
- ld l,(ix-6) ; get address of LOGIN routine\r
+ ld (@RDRV),a ; get relative drive\r
+ ld l,(ix-6) ; get address of LOGIN routine\r
ld h,(ix-5)\r
ex (sp),ix\r
pop de\r
- call ipchl ; call LOGIN\r
- ld hl,(@xdph) ; recover DPH pointer\r
+ call ipchl ; call LOGIN\r
+ ld hl,(@xdph) ; recover DPH pointer\r
ret\r
\r
\r
; extended disk parameter header (XDPH).\r
\r
read:\r
- ld ix,(@xdph) ; get drive descriptor pointer\r
- ld l,(ix-8) ; get read routine entry\r
+ ld ix,(@xdph) ; get drive descriptor pointer\r
+ ld l,(ix-8) ; get read routine entry\r
ld h,(ix-7)\r
jp (hl)\r
\r
; extended disk parameter header (XDPH).\r
\r
write:\r
- ld ix,(@xdph) ; get drive descriptor pointer\r
- ld l,(ix-10) ; get write routine entry\r
+ ld ix,(@xdph) ; get drive descriptor pointer\r
+ ld l,(ix-10) ; get write routine entry\r
ld h,(ix- 9)\r
jp (hl)\r
\r
\r
flush:\r
xor a\r
- ret ; return with no error\r
+ ret ; return with no error\r
\r
\r
\r
@xdph: ds 2 ; pointer to currently selected drives dph\r
@adrv: ds 1 ; currently selected disk drive\r
@rdrv: ds 1 ; controller relative disk drive\r
-@cnt: db 0 ; record count for multisector transfer\r
@trk: ds 2 ; current track number\r
@sect: ds 2 ; current sector number\r
@dma: ds 2 ; current DMA address\r
@dbnk: db 0 ; bank for DMA operations\r
+@cnt: db 0 ; record count for multisector transfer\r
\r
\r
cseg ; common memory\r