*.sym
*.map
*.rel
+*.hex
*.spr
cpm3.sys
-
SRC := bioskrnl.180 boot.180 chario.180 drvtbl.180
-SRC += move.180 misc.180 time.180 mm.180
+SRC += move.180 time.180 mm.180 misc.180 utils.180
SRC += msgbuf.180 conbuf.180 ascip.180 sdio.180
SRC += scb.180
\r
\r
;--------------------------------------------------------------\r
-;\r
-;\r
; TC = (f PHI /(2*baudrate*Clock_mode)) - 2\r
;\r
; Clock_mode == 16\r
; br150 = baudrate/150\r
; TC = (f PHI / (32 * 150 * br150)) - 2\r
; TC = (f PHI / (32 * 150 * br150)) - 2\r
-;\r
\r
- cseg\r
+\r
;\r
; Init Serial I/O for console input and output (ASCI1)\r
;\r
\r
+ dseg\r
+\r
as0init:\r
ld hl,initab0\r
jr as_init\r
\r
;--------------------------------------------------------------\r
\r
+ cseg\r
+\r
as0ista:\r
in0 a,(stat0)\r
and M_RDRF\r
; can be combined to support a particular system\r
; configuration.\r
\r
-cr equ 13\r
-lf equ 10\r
-bell equ 7\r
ctlQ equ 'Q'-'@'\r
ctlS equ 'S'-'@'\r
\r
\r
extrn ?time ; signal time operation\r
\r
- ; general utility routines\r
-\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
add hl,hl ; shift out next bit\r
jr nc,not$out$device\r
push hl ; save the vector\r
- push bc ; save the count and character\r
-not$out$ready:\r
- call coster\r
- or a\r
- jp z,not$out$ready\r
- pop bc\r
+; push bc ; save the count and character\r
+;not$out$ready:\r
+; call coster\r
+; or a\r
+; jr 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
pop bc ; recover count and character\r
jp (hl)\r
\r
\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
- ld a,(hl)\r
- or a\r
- jr z,pmsg$exit\r
- ld c,a\r
- push hl\r
- call ?cono\r
- pop hl\r
- inc hl\r
- jr pmsg$loop\r
-pmsg$exit:\r
- pop de\r
- pop bc\r
- ret\r
-\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
- 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
- pop hl\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
- 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
- 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
-\r
-;-------------------------------------------------------------------------------\r
-;\r
-?pderr:\r
- ld hl,drive$msg\r
- call ?pmsg ; error header\r
- ld a,(@adrv)\r
- add a,'A'\r
- ld c,a\r
- call ?cono ; drive code\r
- ld hl,track$msg\r
- call ?pmsg ; track header\r
- ld c,0\r
- ld hl,(@trk)\r
- call pr.dec ; track number\r
- ld hl,sector$msg\r
- call ?pmsg ; sector header\r
- ld hl,(@sect)\r
- call pr.dec ; sector number\r
- ret\r
-\r
\r
; BNKSEL\r
; Bank Select. Select CPU bank for further execution.\r
db -1,-1,-1,-1,-1,-1,-1,-1 ; ctl-s clears to zero\r
db -1,-1,-1,-1,-1,-1,-1,-1\r
\r
-\r
-\r
dseg ; following resides in banked memory\r
\r
-\r
-\r
; Disk I/O interface routines\r
\r
\r
ret ; return with no error\r
\r
\r
-\r
- ; error message components\r
-drive$msg: db cr,lf,bell,'BIOS Error on ',0\r
-track$msg: db ': T-',0\r
-sector$msg: db ', S-',0\r
-\r
-\r
; disk communication data items\r
; do not change order. sd driver depends on this\r
\r
ret\r
\r
?init:\r
- ld hl,0100000000000000b ; assign console to ASCI1:\r
+ ld hl,1000000000000000b ; assign console to AVRCON:\r
ld (@civec),hl\r
ld (@covec),hl\r
ld hl,0000000000000000b ; assign printer to nothing:\r
ld (@aovec),hl\r
\r
\r
- ld c,2\r
- call gs_rtc ; get time and date\r
call intinit ; setup interrupts and vectors\r
call prt0ini ; init timer\r
ei\r
+ ld c,2\r
+ call gs_rtc ; get time and date\r
\r
xor a\r
ld (@cbnk),a ; right now in bank 0\r
db 13,10,13,10,'CP/M Version 3.0, Z180-Stamp BIOS',13,10,0\r
\r
call pr.inln\r
- db 'CPU clock [Hz]: ',0\r
+ db 'Estimated CPU clock [Hz]: ',0\r
\r
ld hl,(f_cpu)\r
ld de,(f_cpu+2)\r
rl$1:\r
ld a,2\r
call ?bnksl ; select extra bank\r
- ld a,(hl)\r
- push af ; get a byte\r
+ ld a,(hl) ; get a byte\r
+ ex af,af'\r
ld a,tpa$bank\r
call ?bnksl ; select TPA\r
- pop af\r
+ ex af,af'\r
ld (hl),a ; save the byte\r
- inc hl\r
- dec bc ; bump pointer, drop count\r
- ld a,b\r
- or c ; test for done\r
- jp nz,rl$1\r
+ cpi ; bump pointer, drop count\r
+ jp pe,rl$1\r
ret\r
\r
\r
extrn ff.init,ff.ist,ff.in,ff.ost,ff.out\r
extrn as0init,as0ista,as0inp,as0osta,as0out\r
extrn as1init,as1ista,as1inp,as1osta,as1out\r
-\r
+ extrn _b0call\r
\r
include config.inc\r
include z180reg.inc\r
; c: device\r
\r
?cinit: ; init devices\r
+ b0call _cinit\r
+ ret\r
+\r
+ dseg\r
+_cinit:\r
ld b,c\r
call vector$io\r
dw ff.init\r
dw as1init\r
dw rret\r
\r
+ cseg\r
+\r
;--------------------------------------------------------------\r
; Character input\r
; b: device\r
\r
db 0 ; table terminator\r
\r
-;--------------------------------------------------------------\r
-\r
-\r
-\r
-\r
\r
end\r
endif\r
\r
\r
- cseg\r
-\r
mkbuf ci.fifo_id, ci.fifo, ci.fifo_len\r
mkbuf co.fifo_id, co.fifo, co.fifo_len\r
\r
\r
; Init Serial I/O for console input and output\r
;\r
-\r
+ dseg\r
ff.init:\r
ld a,(INIDONE)\r
cp INIDONEVAL\r
ret z\r
\r
ld ix,ci.fifo\r
- ld a,ci.fifo.mask\r
call bufinit\r
ld ix,co.fifo\r
- ld a,co.fifo.mask\r
jp bufinit\r
\r
;--------------------------------------------------------------\r
\r
+ cseg\r
ff.ist:\r
push ix\r
ld ix,(fifolst+ici) ;\r
- global add_hla,div32_16,div32_r
- global ioiniml,ioini1l
global intinit
global bufinit
global cpu_frq
global fifolst
- extrn ?pmsg
+ extrn div32_r,?pmsg
extrn msg.sm,msg.recv,hwl2phy
include config.inc
include z180reg.inc
-;--------------------------------------------------------------------
-; add a to hl
-;
-; return:
-; hl = hl + a
-; Flags undefined
-
- cseg ; (common. TODO: check for banked)
-
-add_hla:
- add a,l
- ld l,a
- ret nc
- inc h
- ret
-
-;--------------------------------------------------------------------
-; rounded div 32 by 16 bit
-;
-; HLDE: Dividend (x)
-; BC: Divisor (y)
-; return:
-; HLDE: Rounded Quotient (q)
-; BC: Remainder (r)
-
- dseg ;banked.
-
-div32_r:
- push bc
- srl b ;y/2
- rr c
- add hl,bc ;low x + y/2
- pop bc
- jr nc,div_r1
- inc hl
-div_r1:
- ;fall thru
-
-;--------------------------------------------------------------------
-; Divide 32 bit by 16
-;
-; DEHL: Dividend (x)
-; BC: Divisor (y)
-;
-; return:
-; DEHL: Quotient
-; BC: Reminder
-
- dseg ; same as above!
-div32_16:
- exx ;low
- push de ;save alternate registers (de,bc)
- push bc
- exx ;high
- push hl ;lx
- push bc ;ly
- ld bc,0 ;bc = hy = 0
- ld h,b ;hl = hr = 0
- ld l,c
- ;de = x, hl = r
- exx ;low
- pop bc ;bc' = ly
- ex (sp),hl ;hl' = lx, save alternate hl
- ld de,0 ;de' = lr = 0
- ex de,hl ;de = x, hl = r
- exx ;high
- ld a,32 ;count
-;
-; start:
-; de: x (de: hx, de': lx)
-; bc: y (bc: hy, bc': ly)
-; hl: 0
-;
-div_lp: ;do
- exx ; low
- ex de,hl ; x
- add hl,hl ; x <<= 1
- exx ; high
- ex de,hl ; x
- adc hl,hl ; x <<= 1
- exx ; low
- ex de,hl ; r
- adc hl,hl ; r <<= 1
- exx ; high
- ex de,hl ; r
- adc hl,hl ; r <<= 1
- exx ; low
- inc de ; x/q += 1
- or a ;
- sbc hl,bc ;
- exx ; high
- sbc hl,bc ;
- jr nc,div_no_restore
- exx ; low
- dec de ;
- add hl,bc ; r += y
- exx ; high
- adc hl,bc ;
-
-div_no_restore: ;
- dec a ;
- jr nz,div_lp ;while (--count)
-
-; result:
-; de: q (de: hq, de': lq)
-; hl: r (hl: hr, hl': lr)
-
- exx ;low
- ex de,hl ;hl = lq, de = lr
-
- ex (sp),hl ;lq
- push de ;lr
- exx ;high
- pop bc ;bc = lr
- pop hl ;de = lq
-
- exx ;low
- pop bc ;restore alternate registers
- pop de
- exx ;high
- ret
-
-;----------------------------------------------------------------------
-
- ; output bytes to consecutive portaddresses
- ;
- ; hl: table with following structure:
- ; db n, port1, val1, val2,... valn
- ; db m, port1, val1, val2,... valm
- ; ...
- ; db 0 ; Terminate table
-
-
- cseg ; (common for now)
-
-ioiniml:
- push bc
- xor a
-ioml_lp:
- ld b,(hl)
- inc hl
- cp b
- jr z,ioml_e
-
- ld c,(hl)
- inc hl
- otimr
- jr ioml_lp
-ioml_e:
- pop bc
- ret
-
-;----------------------------------------------------------------------
-
- ; output bytes to ports
- ;
- ; hl: tables of port,value pairs:
- ; db n, port1,val1, port2,val2,... portn,valn
- ; ...
- ; db 0 ; Terminate table
-
- cseg ; (common for now)
-
-ioini1l:
- push bc
- jr io1_nxt
-io1_lp:
- ld c,(hl) ;port address
- inc hl
- otim
- jr nz,io1_lp
-io1_nxt:
- ld b,(hl) ;count
- inc hl
- inc b
- djnz io1_lp
-
- pop bc
- ret
-
;----------------------------------------------------------------------
dseg
;
; ld hl,8192 ; 147456/18
- ld hl,10240 ; 184320/18
+ ld hl,(10240-100)*5 ; 184320/18
ld de,1
or a
dly_lp:
sbc hl,de ; 10
- jr nz,dly_lp ; 6/8 -> 18
+ jr nz,dly_lp ; 6/8 -> 18 cycles
pop hl
pop de
call get_timer
- ld bc,10
- call div32_r
ld b,h
ld c,l
- ld de,00119h ;18432000/(2**16)
- ld hl,04000h ;18432000%(2**16)
+ ld de,036EEh ;18432000/(2**16) * 50
+ ld hl,08000h ;18432000%(2**16) * 50
ld a,b
or a
dseg
bufinit:
- ld c,a
ld a,(ix+o.id)
cp 4
jr nc,bfi_doit2
bfi_doit2:
ld (ix+o.in_idx),0 ;reset pointers
ld (ix+o.out_idx),0
- ld (ix+o.mask),c ;reset "size"
push ix ;get phys. address of fifo
pop hl
\r
msgi_1:\r
ld ix,mtx.fifo\r
- ld a,mtx.fifo.mask\r
call bufinit\r
ld ix,mrx.fifo\r
- ld a,mrx.fifo.mask\r
jp bufinit\r
\r
\r
; CP/M-80 Version 3 -- Modular BIOS\r
\r
\r
- dseg\r
-\r
; Disk drive dispatching tables for linked BIOS\r
\r
public sd0,sd1,sd2,sd3\r
bell equ 7\r
\r
\r
+ dseg\r
+\r
; Extended Disk Parameter Headers (XPDHs)\r
\r
dw sd$write\r
extrn f_cpu
extrn ioiniml,div32_16
extrn msg.sm,msg.recv
+ extrn _b0call
include config.inc
include z180reg.inc
ld c,3
- ; fall thru
+ b0call gs_rtc
+ ret
;----------------------------------------------------------------------
; c = 2: get time
; c = 3: set time
+ dseg
gs_rtc:
push hl
push de
+ di
ld hl,(@date)
- push hl ;2
ld a,(@hour)
- ld h,a
+ ld d,a
ld a,(@min)
- ld l,a
- push hl ;4
+ ld e,a
ld a,(@sec)
+ ei
ld b,a ;b = sec, c = subcommand
+ push hl ;2
+ push de ;4
push bc ;6
ld hl,3 * 256 + 0 ;h = command, l = 0
push hl ;8
- ld h,l
+ ld h,l ;hl = 0
add hl,sp
push hl
inc hl ;7
ld b,8 ; max receive message len
call msg.recv
- pop hl ;len/command
- pop hl ;subc/sec
- ld a,h
- ld (@sec),a
+ pop hl ;len/command (discard)
+ pop bc ;subc/sec
+ pop de
pop hl
- ld a,l
+ ld a,b
+ di
+ ld (@sec),a
+ ld a,e
ld (@min),a
- ld a,h
+ ld a,d
ld (@hour),a
- pop hl
ld (@date),hl
+ ei
pop de
pop hl
in0 a,(tmdr0l)
in0 a,(tmdr0h)
- ld a,(tim_ms) ;
+ ld a,(counter_10ms) ;
inc a
cp 100 ;100 * 10ms ?
jr nz,iprt_1
ld (@sec),a
xor a
iprt_1:
- ld (tim_ms),a
+ ld (counter_10ms),a
pop af
ei
ret
-tim_ms:
+counter_10ms:
db 0
end
--- /dev/null
+ title 'general utility routines'
+
+ ; i/o port init routines
+
+ public ioiniml,ioini1l ;
+
+ ; math
+
+ public add_hla ; add a to hl
+ public div32_16,div32_r ; divide 32 bit by 16 bit number (rounded)
+
+ ; print utils
+
+ public ?pmsg ; print message
+ public pr.inln,pr.crlf ; print message inline, print newline
+ public phex2,phex4 ; print 2 digit hex (A) or 4 digit hex (HL)
+ public pr.dec,pr.decl ; print 16 or 32 bit decimal number
+ public ?pderr ; print BIOS disk error message header
+
+
+
+ extrn ?cono
+ extrn @adrv,@trk,@sect ; used by disk error message
+
+;-------------------------------------------------------------------------------
+
+cr equ 13
+lf equ 10
+bell equ 7
+
+
+ dseg
+
+;----------------------------------------------------------------------
+; output bytes to consecutive portaddresses
+;
+; hl: table with following structure:
+; db n, port1, val1, val2,... valn
+; db m, port1, val1, val2,... valm
+; ...
+; db 0 ; Terminate table
+
+ioiniml:
+ push bc
+ xor a
+ioml_lp:
+ ld b,(hl)
+ inc hl
+ cp b
+ jr z,ioml_e
+
+ ld c,(hl)
+ inc hl
+ otimr
+ jr ioml_lp
+ioml_e:
+ pop bc
+ ret
+
+;----------------------------------------------------------------------
+; output bytes to ports
+;
+; hl: tables of port,value pairs:
+; db n, port1,val1, port2,val2,... portn,valn
+; ...
+; db 0 ; Terminate table
+
+ioini1l:
+ push bc
+ jr io1_nxt
+io1_lp:
+ ld c,(hl) ;port address
+ inc hl
+ otim
+ jr nz,io1_lp
+io1_nxt:
+ ld b,(hl) ;count
+ inc hl
+ inc b
+ djnz io1_lp
+
+ pop bc
+ ret
+
+;--------------------------------------------------------------------
+; add a to hl
+;
+; return:
+; hl = hl + a
+; Flags undefined
+
+add_hla:
+ add a,l
+ ld l,a
+ ret nc
+ inc h
+ ret
+
+;--------------------------------------------------------------------
+; rounded div 32 by 16 bit
+;
+; HLDE: Dividend (x)
+; BC: Divisor (y)
+; return:
+; HLDE: Rounded Quotient (q)
+; BC: Remainder (r)
+
+div32_r:
+ push bc
+ srl b ;y/2
+ rr c
+ add hl,bc ;low x + y/2
+ pop bc
+ jr nc,div_r1
+ inc hl
+div_r1:
+ ;fall thru
+
+;--------------------------------------------------------------------
+; Divide 32 bit by 16
+;
+; DEHL: Dividend (x)
+; BC: Divisor (y)
+;
+; return:
+; DEHL: Quotient
+; BC: Reminder
+
+div32_16:
+ exx ;low
+ push de ;save alternate registers (de,bc)
+ push bc
+ exx ;high
+ push hl ;lx
+ push bc ;ly
+ ld bc,0 ;bc = hy = 0
+ ld h,b ;hl = hr = 0
+ ld l,c
+ ;de = x, hl = r
+ exx ;low
+ pop bc ;bc' = ly
+ ex (sp),hl ;hl' = lx, save alternate hl
+ ld de,0 ;de' = lr = 0
+ ex de,hl ;de = x, hl = r
+ exx ;high
+ ld a,32 ;count
+;
+; start:
+; de: x (de: hx, de': lx)
+; bc: y (bc: hy, bc': ly)
+; hl: 0
+;
+div_lp: ;do
+ exx ; low
+ ex de,hl ; x
+ add hl,hl ; x <<= 1
+ exx ; high
+ ex de,hl ; x
+ adc hl,hl ; x <<= 1
+ exx ; low
+ ex de,hl ; r
+ adc hl,hl ; r <<= 1
+ exx ; high
+ ex de,hl ; r
+ adc hl,hl ; r <<= 1
+ exx ; low
+ inc de ; x/q += 1
+ or a ;
+ sbc hl,bc ;
+ exx ; high
+ sbc hl,bc ;
+ jr nc,div_no_restore
+ exx ; low
+ dec de ;
+ add hl,bc ; r += y
+ exx ; high
+ adc hl,bc ;
+
+div_no_restore: ;
+ dec a ;
+ jr nz,div_lp ;while (--count)
+
+; result:
+; de: q (de: hq, de': lq)
+; hl: r (hl: hr, hl': lr)
+
+ exx ;low
+ ex de,hl ;hl = lq, de = lr
+
+ ex (sp),hl ;lq
+ push de ;lr
+ exx ;high
+ pop bc ;bc = lr
+ pop hl ;de = lq
+
+ exx ;low
+ pop bc ;restore alternate registers
+ pop de
+ exx ;high
+ ret
+
+;-------------------------------------------------------------------------------
+; print message @<HL> up to a null
+; saves <BC> & <DE>
+
+?pmsg:
+ push bc
+ push de
+pmsg$loop:
+ ld a,(hl)
+ or a
+ jr z,pmsg$exit
+ ld c,a
+ push hl
+ call ?cono
+ pop hl
+ inc hl
+ jr pmsg$loop
+pmsg$exit:
+ pop de
+ pop bc
+ ret
+
+;-------------------------------------------------------------------------------
+; print message inline up to a null
+; saves all registers
+
+pr.inln:
+ ex (sp),hl
+ push af
+ call ?pmsg
+ pop af
+ ex (sp),hl
+ ret
+
+;-------------------------------------------------------------------------------
+; print <CR><LF>
+; saves all registers
+
+pr.crlf:
+ call pr.inln
+ db cr,lf,0
+ ret
+
+;-------------------------------------------------------------------------------
+; print hl as a 4 digit hexadecimal number
+; saves all registers
+
+phex4:
+ ld a,h
+ call phex2
+ ld a,l
+ ; fall thru
+
+;-------------------------------------------------------------------------------
+; print a as a 2 digit hexadecimal number
+; saves all registers
+
+phex2:
+ push af
+ rra
+ rra
+ rra
+ rra
+ call print.digit
+ pop af
+
+print.digit:
+ push hl
+ push de
+ push bc
+ push af
+ and 00fh
+ cp 10
+ jr c,prd_1
+ add a,007h
+prd_1:
+ add a,'0'
+
+ ld c,a
+ call ?cono
+ pop af
+ pop bc
+ pop de
+ pop hl
+ ret
+
+
+;-------------------------------------------------------------------------------
+; print decimal 16 bit number from HL
+;
+; HL: unsigned binary number to print
+; C: minimum print field width
+; number is prined right-aligned
+; B: pad character, typically ' ' or '0'
+
+pr.dec:
+ push de
+ ld de,0
+ call pr.decl
+ pop de
+ ret
+
+;-------------------------------------------------------------------------------
+; print decimal 32 bit number from DEHL
+;
+; DEHL: unsigned binary number to print
+; C: minimum print field width
+; number is prined right-aligned
+; B: pad character, typically ' ' or '0'
+
+pr.decl:
+ push bc ;save width and fillchar
+ push bc
+ exx ;(alt)
+ ex (sp),hl ;save hl', get width and fill
+ push de ;save de'
+
+ xor a
+ ld d,a ;clear counter
+ ld e,a
+ push af ; string terminator
+ inc sp
+
+prd_divloop: ;do
+ exx ; (main)
+ ld bc,10 ;
+ call div32_16 ; get a digit
+ ld a,c ;
+ add a,'0' ; make it printable
+ push af ;
+
+ ld a,h ;
+ or l ;
+ or d ;
+ or e ;
+ exx ; (alt)
+ inc sp ;
+ inc de ;
+ jr nz,prd_divloop ;
+
+prd_filloop: ;h=filler, l=field width
+ ld a,e
+ cp l
+ jr nc,prd_out
+ push hl
+ inc sp
+ inc de
+ jr prd_filloop
+prd_out:
+ ld hl,0
+ add hl,sp ;ptr to beginning of number string (hl==0 here)
+ call ?pmsg
+ ex de,hl
+ add hl,sp
+ ld sp,hl
+ inc sp ;remove string terminator
+ pop de
+ pop hl
+ exx ;(main)
+ pop bc
+ ret
+
+
+;-------------------------------------------------------------------------------
+
+?pderr:
+ ld hl,drive$msg
+ call ?pmsg ; error header
+ ld a,(@adrv)
+ add a,'A'
+ ld c,a
+ call ?cono ; drive code
+ ld hl,track$msg
+ call ?pmsg ; track header
+ ld c,0
+ ld hl,(@trk)
+ call pr.dec ; track number
+ ld hl,sector$msg
+ call ?pmsg ; sector header
+ ld hl,(@sect)
+ call pr.dec ; sector number
+ ret
+
+ ; error message components
+drive$msg: db cr,lf,bell,'BIOS Error on ',0
+track$msg: db ': T-',0
+sector$msg: db ', S-',0