]> cloudbase.mooo.com Git - z180-stamp-cpm3.git/blobdiff - cbios/utils.180
add ioctl data
[z180-stamp-cpm3.git] / cbios / utils.180
index 4a91641e110348751f86427639b76d58d0b4a4a5..a84d2171ec14e4fed661969c729e223226057c01 100644 (file)
-       title 'general utility routines'\r
-\r
-       ; i/o port init routines\r
-\r
-       public ioiniml,ioini1l          ;\r
-\r
-       ; math\r
-\r
-       public add_hla                  ; add a to hl\r
-       public div32_16,div32_r         ; divide 32 bit by 16 bit number (rounded)\r
-\r
-       ; print utils\r
-\r
-       public ?pmsg                    ; print message\r
-       public pr.idx                   ; print message from table indexed by <A>\r
-       public pr.inln,pr.crlf          ; print message inline, print newline\r
-       public phex2,phex4              ; print 2 digit hex <A> or 4 digit hex <HL>\r
-       public pr.dec,pr.decl           ; print 16 or 32 bit decimal number\r
-       public pr.errors                ; print BIOS disk error message header\r
-\r
-       extrn ?const,?conin,?cono\r
-       extrn @adrv,@trk,@sect          ; used by disk error message\r
-       extrn @op,@ermde\r
-\r
-;-------------------------------------------------------------------------------\r
-\r
-cr     equ     13\r
-lf     equ     10\r
-bell   equ     7\r
-\r
-\r
-       dseg\r
-\r
-;----------------------------------------------------------------------\r
-; output bytes to consecutive portaddresses\r
-;\r
-;     hl: table with following structure:\r
-;        db n, port1, val1, val2,... valn\r
-;        db m, port1, val1, val2,... valm\r
-;        ...\r
-;        db 0 ; Terminate table\r
-\r
-ioiniml:\r
-       push    bc\r
-       xor     a\r
-ioml_lp:\r
-       ld      b,(hl)\r
-       inc     hl\r
-       cp      b\r
-       jr      z,ioml_e\r
-\r
-       ld      c,(hl)\r
-       inc     hl\r
-       otimr\r
-       jr      ioml_lp\r
-ioml_e:\r
-       pop     bc\r
-       ret\r
-\r
-;----------------------------------------------------------------------\r
-; output bytes to ports\r
-;\r
-;     hl: tables of port,value pairs:\r
-;         db n, port1,val1, port2,val2,... portn,valn\r
-;         ...\r
-;         db 0 ; Terminate table\r
-\r
-ioini1l:\r
-       push    bc\r
-       jr      io1_nxt\r
-io1_lp:\r
-       ld      c,(hl)          ;port address\r
-       inc     hl\r
-       otim\r
-       jr      nz,io1_lp\r
-io1_nxt:\r
-       ld      b,(hl)          ;count\r
-       inc     hl\r
-       inc     b\r
-       djnz    io1_lp\r
-\r
-       pop     bc\r
-       ret\r
-\r
-;--------------------------------------------------------------------\r
-; add a to hl\r
-;\r
-;    return:\r
-;       hl = hl + a\r
-;       Flags undefined\r
-\r
-add_hla:\r
-       add     a,l\r
-       ld      l,a\r
-       ret     nc\r
-       inc     h\r
-       ret\r
-\r
-;--------------------------------------------------------------------\r
-; rounded div 32 by 16 bit\r
-;\r
-;      DEHL:   Dividend (x)\r
-;      BC:     Divisor  (y)\r
-;    return:\r
-;      HLDE:   Rounded Quotient (q)\r
-;      BC:     Remainder              (r)\r
-\r
-div32_r:\r
-       push bc\r
-       srl     b               ;y/2\r
-       rr      c\r
-       add     hl,bc           ;low x + y/2\r
-       pop     bc\r
-       jr      nc,div_r1\r
-       inc     de\r
-div_r1:\r
-       ;fall thru\r
-\r
-;--------------------------------------------------------------------\r
-; Divide 32 bit by 16\r
-;\r
-;    DEHL:     Dividend (x)\r
-;    BC:       Divisor  (y)\r
-;\r
-;  return:\r
-;    DEHL:     Quotient\r
-;    BC:       Reminder\r
-\r
-div32_16:\r
-       exx                     ;low\r
-       push    de              ;save alternate registers (de,bc)\r
-       push    bc\r
-       exx                     ;high\r
-       push    hl              ;lx\r
-       push    bc              ;ly\r
-       ld      bc,0            ;bc  = hy = 0\r
-       ld      h,b             ;hl  = hr = 0\r
-       ld      l,c\r
-                               ;de = x, hl = r\r
-       exx                     ;low\r
-       pop     bc              ;bc' = ly\r
-       ex      (sp),hl         ;hl' = lx, save alternate hl\r
-       ld      de,0            ;de' = lr = 0\r
-       ex      de,hl           ;de = x, hl = r\r
-       exx                     ;high\r
-       ld      a,32            ;count\r
-;\r
-; start:\r
-;     de: x    (de: hx, de': lx)\r
-;     bc: y    (bc: hy, bc': ly)\r
-;     hl: 0\r
-;\r
-div_lp:                                ;do\r
-       exx                     ;    low\r
-       ex      de,hl           ;    x\r
-       add     hl,hl           ;    x <<= 1\r
-       exx                     ;    high\r
-       ex      de,hl           ;    x\r
-       adc     hl,hl           ;    x <<= 1\r
-       exx                     ;    low\r
-       ex      de,hl           ;    r\r
-       adc     hl,hl           ;    r <<= 1\r
-       exx                     ;    high\r
-       ex      de,hl           ;    r\r
-       adc     hl,hl           ;    r <<= 1\r
-       exx                     ;    low\r
-       inc     de              ;    x/q += 1\r
-       or      a               ;\r
-       sbc     hl,bc           ;\r
-       exx                     ;    high\r
-       sbc     hl,bc           ;\r
-       jr      nc,div_no_restore\r
-       exx                     ;        low\r
-       dec     de              ;\r
-       add     hl,bc           ;        r += y\r
-       exx                     ;        high\r
-       adc     hl,bc           ;\r
-\r
-div_no_restore:                        ;\r
-       dec     a               ;\r
-       jr      nz,div_lp       ;while (--count)\r
-\r
-; result:\r
-;     de: q    (de: hq, de': lq)\r
-;     hl: r    (hl: hr, hl': lr)\r
-\r
-       exx                     ;low\r
-       ex      de,hl           ;hl = lq,  de = lr\r
-\r
-       ex      (sp),hl         ;lq\r
-       push    de              ;lr\r
-       exx                     ;high\r
-       pop     bc              ;bc = lr\r
-       pop     hl              ;de = lq\r
-\r
-       exx                     ;low\r
-       pop     bc              ;restore alternate registers\r
-       pop     de\r
-       exx                     ;high\r
-       ret\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
-       inc     hl\r
-       or      a\r
-       jr      z,pmsg$exit\r
-       ld      c,a\r
-       push    hl\r
-       call    ?cono\r
-       pop     hl\r
-       jr      pmsg$loop\r
-pmsg$exit:\r
-       pop     de\r
-       pop     bc\r
-       ret\r
-\r
-;-------------------------------------------------------------------------------\r
-; print message from table @<HL>, indexed by <A>\r
-; saves <BC> & <DE>\r
-\r
-pr.idx:\r
-       push    bc\r
-       push    de\r
-       push    hl              ; put pointer to first message on stack\r
-       ld      e,a             ; save message number\r
-       xor     a\r
-       ld      b,a\r
-       ld      c,a\r
-       inc     e\r
-pdc_nxt_str:\r
-       dec     e\r
-       ex      (sp),hl\r
-       jr      z,pdc_found\r
-       ex      (sp),hl\r
-       cpir\r
-       cp      (hl)\r
-       jr      nz,pdc_nxt_str\r
-                               ; End of List, msg not found.\r
-                               ; Print first msg.\r
-pdc_found:\r
-       pop     hl\r
-       call    ?pmsg\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      cr,lf,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
-       jp      pr.dec          ; sector number\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
-;-------------------------------------------------------------------------------\r
-; get console input, echo it, and shift to upper case\r
-; save hl,de,bc\r
-\r
-uciecho:\r
-       push    hl\r
-       push    de\r
-       push    bc\r
-u$c0:\r
-       call    ?const\r
-       or      a\r
-       jr      z,u$c1          ; see if any char already struck\r
-       call    ?conin\r
-       jr      u$c0            ; yes, eat it and try again\r
-u$c1:\r
-       call    ?conin\r
-       push    af\r
-       ld      c,a\r
-       cp      ' '-1\r
-       call    nc,?cono\r
-       pop     af\r
-       pop     bc\r
-       pop     de\r
-       pop     hl\r
-       cp      'a'\r
-       ret     c\r
-       sub     'a'-'A'         ; make upper case\r
-       ret\r
-\r
-;-------------------------------------------------------------------------------\r
-;\r
-\r
-pr.errors:\r
-\r
-       ; suppress error message if BDOS\r
-       ; is returning errors to application...\r
-\r
-       ld      a,(@ermde)\r
-       inc     a\r
-       jr      nz,pre1\r
-       dec     a               ;return NZ, if @ermde == 0FFH\r
-       ret\r
-pre1:\r
-       push    hl\r
-       ld      hl,pre2\r
-       ex      (sp),hl\r
-       push    hl\r
-\r
-       ; Had permanent error, print message like:\r
-       ; BIOS Err on d: T-nn, S-mm, <operation> <type>, Retry ?\r
-\r
-       call    ?pderr          ; print message header\r
-\r
-       ld      hl,op$msg\r
-       ld      a,(@op)\r
-       jp      pr.idx          ; last function (read or write)\r
-\r
-pre2:\r
-                               ; prompt for retry\r
-       call    pr.inln\r
-       db      ' Retry (Y/N) ? ',0\r
-\r
-       call    uciecho         ; get operator response\r
-       cp      'Y'\r
-       ret                     ; return Z-flag for yes\r
-\r
-\r
-op$msg:\r
-       db      ', Unknown op, ',0\r
-       db      ', Read, ',0\r
-       db      ', Write, ',0\r
-       db      0\r
-\r
-       end\r
+==== 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 <A>
+       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 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 @<HL> up to a null
+; saves <BC> & <DE>
+
+?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 @<HL>, indexed by <A>
+; saves <BC> & <DE>
+
+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 <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)
+       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, <operation> <type>, 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