]> cloudbase.mooo.com Git - z180-stamp-cpm3.git/blobdiff - cbios/utils.180
reduce stack usage
[z180-stamp-cpm3.git] / cbios / utils.180
index d9300aad93c50e214af57644d741eeece7418b24..08c5fd092c339780a47ffb5a6c2eec86989c947f 100644 (file)
-       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
-;
-;      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)
-       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
+       title 'general utility routines'\r
+\r
+       ; i/o port init routines\r
+\r
+       public ioiniml,ioini1l          ;\r
+\r
+       ; math\r
+\r
+       public ijphl                    ; vectored CALL point\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
+\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
+       cseg\r
+\r
+;--------------------------------------------------------------------\r
+; vectored CALL point\r
+\r
+ijphl:\r
+       jp      (hl)\r
+\r
+       dseg\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