X-Git-Url: http://cloudbase.mooo.com/gitweb/z180-stamp-cpm3.git/blobdiff_plain/6dd88c258326e3bc0538c15b3b7fe3e04874ab99..947c5868f3a9d8c9e5a35862f24a046d4db9f6b9:/cbios/utils.180
diff --git a/cbios/utils.180 b/cbios/utils.180
index a84d217..08c5fd0 100644
--- a/cbios/utils.180
+++ b/cbios/utils.180
@@ -1,502 +1,506 @@
-==== BASE ====
- title 'general utility routines'
-
- ; i/o port init routines
-
- public ioiniml,ioini1l ;
-
- ; math
-
- public ijphl ; vectored CALL point
- 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.idx ; print message from table indexed by
- public pr.inln,pr.crlf ; print message inline, print newline
- public phex2,phex4 ; print 2 digit hex or 4 digit hex
- public pr.dec,pr.decl ; print 16 or 32 bit decimal number
- public pr.errors ; print BIOS disk error message header
-
-
-
- extrn ?const,?conin,?cono
- extrn @adrv,@trk,@sect ; used by disk error message
- extrn @op,@ermde
-
-;-------------------------------------------------------------------------------
-
-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
-;--------------------------------------------------------------------
-; vectored CALL point
-
-ijphl:
- jp (hl)
-
-;--------------------------------------------------------------------
-; 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
-;
-; DEHL: 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 de
-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 @ up to a null
-; saves &
-
-?pmsg:
- push bc
- push de
-pmsg$loop:
- ld a,(hl)
- inc hl
- or a
- jr z,pmsg$exit
- ld c,a
- push hl
- call ?cono
- pop hl
- jr pmsg$loop
-pmsg$exit:
- pop de
- pop bc
- ret
-
-;-------------------------------------------------------------------------------
-; print message from table @, indexed by
-; saves &
-
-pr.idx:
- push bc
- push de
- push hl ; put pointer to first message on stack
- ld e,a ; save message number
- xor a
- ld b,a
- ld c,a
- inc e
-pdc_nxt_str:
- dec e
- ex (sp),hl
- jr z,pdc_found
- ex (sp),hl
- cpir
- cp (hl)
- jr nz,pdc_nxt_str
- ; End of List, msg not found.
- ; Print first msg.
-pdc_found:
- pop hl
- call ?pmsg
- 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
-; 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)
- jp pr.dec ; sector number
-
- ; error message components
-drive$msg: db cr,lf,bell,'BIOS Error on ',0
-track$msg: db ': T-',0
-sector$msg: db ', S-',0
-
-
-;-------------------------------------------------------------------------------
-; get console input, echo it, and shift to upper case
-; save hl,de,bc
-
-uciecho:
- push hl
- push de
- push bc
-u$c0:
- call ?const
- or a
- jr z,u$c1 ; see if any char already struck
- call ?conin
- jr u$c0 ; yes, eat it and try again
-u$c1:
- call ?conin
- push af
- ld c,a
- cp ' '-1
- call nc,?cono
- pop af
- pop bc
- pop de
- pop hl
- cp 'a'
- ret c
- sub 'a'-'A' ; make upper case
- ret
-
-;-------------------------------------------------------------------------------
-;
-
-pr.errors:
-
- ; suppress error message if BDOS
- ; is returning errors to application...
-
- ld a,(@ermde)
- inc a
- jr nz,pre1
- dec a ;return NZ, if @ermde == 0FFH
- ret
-pre1:
- push hl
- ld hl,pre2
- ex (sp),hl
- push hl
-
- ; Had permanent error, print message like:
- ; BIOS Err on d: T-nn, S-mm, , Retry ?
-
- call ?pderr ; print message header
-
- ld hl,op$msg
- ld a,(@op)
- jp pr.idx ; last function (read or write)
-
-pre2:
- ; prompt for retry
- call pr.inln
- db ' Retry (Y/N) ? ',0
-
- call uciecho ; get operator response
- cp 'Y'
- ret ; return Z-flag for yes
-
-
-op$msg:
- db ', Unknown op, ',0
- db ', Read, ',0
- db ', Write, ',0
- db 0
-
- end
+ title 'general utility routines'
+
+ ; i/o port init routines
+
+ public ioiniml,ioini1l ;
+
+ ; math
+
+ public ijphl ; vectored CALL point
+ 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.idx ; print message from table indexed by
+ public pr.inln,pr.crlf ; print message inline, print newline
+ public phex2,phex4 ; print 2 digit hex or 4 digit hex
+ public pr.dec,pr.decl ; print 16 or 32 bit decimal number
+ public pr.errors ; print BIOS disk error message header
+
+
+
+ extrn ?const,?conin,?cono
+ extrn @adrv,@trk,@sect ; used by disk error message
+ extrn @op,@ermde
+
+;-------------------------------------------------------------------------------
+
+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
+
+ cseg
+
+;--------------------------------------------------------------------
+; vectored CALL point
+
+ijphl:
+ jp (hl)
+
+ dseg
+
+;--------------------------------------------------------------------
+; 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
+;
+; DEHL: 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 de
+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 @ up to a null
+; saves &
+
+?pmsg:
+ push bc
+ push de
+pmsg$loop:
+ ld a,(hl)
+ inc hl
+ or a
+ jr z,pmsg$exit
+ ld c,a
+ push hl
+ call ?cono
+ pop hl
+ jr pmsg$loop
+pmsg$exit:
+ pop de
+ pop bc
+ ret
+
+;-------------------------------------------------------------------------------
+; print message from table @, indexed by
+; saves &
+
+pr.idx:
+ push bc
+ push de
+ push hl ; put pointer to first message on stack
+ ld e,a ; save message number
+ xor a
+ ld b,a
+ ld c,a
+ inc e
+pdc_nxt_str:
+ dec e
+ ex (sp),hl
+ jr z,pdc_found
+ ex (sp),hl
+ cpir
+ cp (hl)
+ jr nz,pdc_nxt_str
+ ; End of List, msg not found.
+ ; Print first msg.
+pdc_found:
+ pop hl
+ call ?pmsg
+ 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
+; 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)
+ jp pr.dec ; sector number
+
+ ; error message components
+drive$msg: db cr,lf,bell,'BIOS Error on ',0
+track$msg: db ': T-',0
+sector$msg: db ', S-',0
+
+
+;-------------------------------------------------------------------------------
+; get console input, echo it, and shift to upper case
+; save hl,de,bc
+
+uciecho:
+ push hl
+ push de
+ push bc
+u$c0:
+ call ?const
+ or a
+ jr z,u$c1 ; see if any char already struck
+ call ?conin
+ jr u$c0 ; yes, eat it and try again
+u$c1:
+ call ?conin
+ push af
+ ld c,a
+ cp ' '-1
+ call nc,?cono
+ pop af
+ pop bc
+ pop de
+ pop hl
+ cp 'a'
+ ret c
+ sub 'a'-'A' ; make upper case
+ ret
+
+;-------------------------------------------------------------------------------
+;
+
+pr.errors:
+
+ ; suppress error message if BDOS
+ ; is returning errors to application...
+
+ ld a,(@ermde)
+ inc a
+ jr nz,pre1
+ dec a ;return NZ, if @ermde == 0FFH
+ ret
+pre1:
+ push hl
+ ld hl,pre2
+ ex (sp),hl
+ push hl
+
+ ; Had permanent error, print message like:
+ ; BIOS Err on d: T-nn, S-mm, , Retry ?
+
+ call ?pderr ; print message header
+
+ ld hl,op$msg
+ ld a,(@op)
+ jp pr.idx ; last function (read or write)
+
+pre2:
+ ; prompt for retry
+ call pr.inln
+ db ' Retry (Y/N) ? ',0
+
+ call uciecho ; get operator response
+ cp 'Y'
+ ret ; return Z-flag for yes
+
+
+op$msg:
+ db ', Unknown op, ',0
+ db ', Read, ',0
+ db ', Write, ',0
+ db 0
+
+ end