X-Git-Url: http://cloudbase.mooo.com/gitweb/z180-stamp-cpm3.git/blobdiff_plain/50f3b8f0cb6ccbdc5c1ea8f916f3d95b197d3d04..afbcea2d821d1166ae347338ae52a64f3ee51e57:/cbios/utils.180 diff --git a/cbios/utils.180 b/cbios/utils.180 index f682d44..08c5fd0 100644 --- a/cbios/utils.180 +++ b/cbios/utils.180 @@ -1,388 +1,506 @@ - 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 @ up to a null -; saves & - -?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 -; 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 + 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