home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Emulators / Ersatz-2.0 / do.mac next >
Encoding:
Text File  |  1998-12-17  |  16.6 KB  |  685 lines

  1.     .title    do
  2.     .enabl    lc
  3. ;++
  4. ;
  5. ; DOS file device handler for RT-11 V4.0 and later.
  6. ;
  7. ; By John Wilson.
  8. ;
  9. ; Copyright (C) 1998 by Digby's Bitpile, Inc. DBA D Bit.  All rights reserved.
  10. ;
  11. ; This handler allows RT-11 programs to access DOS files using the DOS file
  12. ; device found in Ersatz-11.  It is currently fairly primitive and does not
  13. ; handle stripping trailing NULs off of files (so text files written this way
  14. ; will usually have some number of NUL characters in them).  It allows only
  15. ; one file at a time to be read or written, similar to magtape files.  The
  16. ; file must be located in the current DOS directory, and has to have a 6.3
  17. ; filename with no non-RAD50 characters just like any other RT-11 filename.
  18. ;
  19. ; 02-Mar-1992    JMBW    Created (as unfinished Kermit device).
  20. ; 21-Oct-1998    JMBW    Converted to DOS file interface.
  21. ; 23-Oct-1998    JMBW    Added XM support.  Initial release.
  22. ; 31-Oct-1998    JMBW    Whoops -- fixed SEEK bug with files .GE. 128 blocks.
  23. ; 18-Dec-1998    JMBW    Whip up fake directory for DIR.SAV.
  24. ;
  25. ;--
  26.     .mcall    .drdef
  27. ;
  28. nstmax=    8.    ;max # nested opens
  29.         ;(V5.X PIP!!!)
  30. ;
  31. ; CSR bits:
  32. dovec=    400    ;7-bit vector/4 starts with this bit
  33. dopri=    20    ;3-bit interrupt priority (4-7) starts with this bit
  34. dobsy=    4    ;NZ => device busy
  35. dogo=    2    ;set to start command
  36. doie=    1    ;int enable
  37. ;
  38. ; Function codes (for CMDCMD field in command packet):
  39. doopn=    0    ;open file
  40. docrt=    1    ;create (but don't open) file
  41. dodel=    2    ;delete file
  42. dordd=    3    ;read data
  43. dowrd=    4    ;write data
  44. dosek=    5    ;seek
  45. dofst=    6    ;find first wildcard match
  46. donxt=    7    ;find next wildcard match
  47. docls=    8.    ;close file
  48. ;
  49. ; MOVE address to register
  50. ;
  51.     .macro    mova    arg,r
  52.     mov    pc,r
  53.     add    #<arg>-.,r
  54.     .endm
  55. ;
  56.     .drdef    do,400-'D,specl$!spfun$,0,176470,240
  57. ;
  58. do$ba=    do$csr+2    ;bus addr reg
  59. do$bae=    do$csr+4    ;bus addr ext reg
  60. ;
  61. .if ne 0 ;;;;; SET options not yet supported
  62.     .drset    CSR,1,o.csr,OCT        ;change CSR
  63.     .drset    VECTOR,3,o.vec,OCT    ;change vector
  64. ;
  65. o.csr:    bis    #160000,r0    ;at least trap or something if way off
  66.     mov    r0,176        ;set CSR
  67.     mov    r0,docsr    ;set all
  68.     add    #2,r0
  69.     mov    r0,doba
  70.     add    #2,r0
  71.     mov    r0,dobae
  72. clcrts:    clc            ;happy
  73.     rts    pc
  74. ;
  75. o.vec:    bic    #3,r0        ;guarantee OK
  76. ;;    mov    r0,do$vtb    ;set vector
  77.     rts    pc
  78. ;
  79. .iif gt <.-1000>, .error .-1000    ;SET code too big
  80. .endc ;;;;;
  81. ;+
  82. ;
  83. ; I/O initiation.
  84. ;
  85. ;-
  86.     .drbeg    do
  87.     mov    docqe,r4    ;get curr Q-el
  88. ;    movb    q$unit(r4),r0    ;get unit #
  89. ;    bic    #^C7,r0        ;isolate
  90. ;    asl    r0        ;*2 for use as table index
  91. ;    mov    r0,unit        ;save
  92. ;;; (we don't do anything with that yet, indexing tables with PIC is a pain!)
  93.     movb    q$func(r4),r0    ;get special function code
  94.     bne    spec        ;NZ => handle it
  95.     asl    q$wcnt(r4)    ;WC*2=BC
  96.     beq    20$        ;seek, done
  97.     bcs    50$        ;.WRITE
  98.     ; .READ
  99.     call    seek        ;set up "seek" command
  100.     bcs    60$        ;(no open file, skip)
  101.     call    docmd        ;send it
  102.     bcs    40$        ;failed
  103.     call    addr        ;load up buffer addr
  104.     mov    #dordd,cmdcmd    ;set command
  105.     call    docmd        ;do command
  106.     bcs    40$
  107.     mov    cmdlen,r5    ;get actual length
  108.     beq    30$        ;EOF, special
  109.     add    r5,q$buff(r4)    ;update addr
  110.     sub    r5,q$wcnt(r4)    ;and byte count
  111.     beq    20$        ;nothing to do
  112. 10$:    ; zero fill
  113.     clr    r5        ;load zero
  114.     call    putb        ;store it
  115.     bne    10$        ;loop until buf is full
  116. 20$:    jmp    dodone        ;finished
  117. 30$:    bis    #eof$,@-(r4)    ;end of file
  118.     jmp    dodone        ;finished
  119. 40$:    jmp    doerr
  120. 50$:    br    write
  121. 60$:    ; not a file, must be trying to read from raw disk
  122.     mov    q$blkn(r4),r0    ;get starting block #
  123.     cmp    r0,#6        ;before directory?
  124.     blo    10$        ;yes, just return zeros (probably home blk)
  125.     beq    70$        ;starting new directory
  126.     cmp    r0,#6+<31.*2>    ;after directory?
  127.     bhis    10$        ;yes, who knows what they're up to
  128.     cmp    r0,dirblk    ;is this next in sequence?
  129.     beq    80$        ;yes
  130.     clr    dirblk        ;forget about dir lookup
  131.     br    10$        ;go return NULs
  132. 70$:    mov    r0,dirblk    ;starting a fresh directory
  133.     clr    diroff        ;init offset in segment
  134. 80$:    jmp    dir        ;go handle directory access
  135. ;
  136. write:    ; .WRITE
  137.     neg    q$wcnt(r4)    ;positive byte count
  138.     call    seek        ;set up "seek" command
  139.     bcs    10$        ;(no open file, skip)
  140.     call    docmd        ;send it
  141.     bcs    20$        ;failed
  142.     call    addr        ;load up buffer addr
  143.     mov    #dowrd,cmdcmd    ;set command
  144.     call    docmd        ;do command
  145.     bcs    20$
  146. 10$:    jmp    dodone        ;finished
  147. 20$:    jmp    doerr
  148. ;+
  149. ;
  150. ; Special function or directory access.
  151. ;
  152. ;-
  153. spec:    mova    spfuns-2,r1    ;get ptr to special function list
  154. 10$:    tst    (r1)+        ;skip a word
  155.     mov    (r1)+,r2    ;get function
  156.     beq    badspf        ;end of list
  157.     cmp    r0,r2        ;is this it?
  158.     bne    10$        ;no, keep searching
  159.     add    (r1),pc        ;jump
  160. spfuns:    .word    1,close-spfuns
  161.     .word    2,delete-spfuns
  162.     .word    3,lookup-spfuns
  163.     .word    4,enter-spfuns
  164.     .word    0
  165. ;
  166. badspf:    jmp    doerr        ;bad .SPFUN
  167. ;+
  168. ;
  169. ; Close innermost open file.
  170. ;
  171. ;-
  172. close:    call    gethnd        ;get file handle
  173.     bcs    10$        ;not open
  174.     mov    #docls,cmdcmd    ;func=close
  175.     call    docmd        ;close the handle
  176. 10$:    sub    #2,opensp    ;back up stack pointer
  177.     bcc    20$
  178.      clr    opensp        ;stop at 0
  179. 20$:    jmp    dodone
  180. ;+
  181. ;
  182. ; Delete a file.
  183. ;
  184. ;-
  185. delete:    call    getnam        ;convert filename
  186.     mov    #dodel,cmdcmd    ;func=delete
  187.     call    docmd        ;execute it, come back on interrupt
  188.     bcs    doerr        ;error
  189.     br    dodone
  190. ;+
  191. ;
  192. ; Look up an existing file.
  193. ;
  194. ;-
  195. lookup:    call    nulfil        ;convert filename, see if it's null
  196.     bcs    10$        ;yes
  197.     mov    #1,cmdprm    ;access=RO, sharing=compatibility mode
  198.     clr    cmdcmd        ;func=open
  199.     call    docmd        ;execute it, come back on interrupt
  200.     bcs    doerr        ;error
  201.     call    savhnd        ;save handle
  202. 10$:    mov    docqe,r4    ;restore qel ptr (NULFIL may trash)
  203.     clr    q$wcnt(r4)    ;FSM.MAC does this (say file length=0)
  204.                 ;(V5.6 Quick Ref confirms .LOOKUP behavior)
  205.     br    dodone        ;success
  206. ;+
  207. ;
  208. ; Enter a new file.
  209. ;
  210. ;-
  211. enter:    call    nulfil        ;convert filename, see if it's null
  212.     bcs    10$        ;yes
  213.     mov    #docrt,cmdcmd    ;func=create
  214.     call    docmd        ;execute it, come back on interrupt
  215.     bcs    doerr        ;error
  216.     clr    cmdprm        ;access=RW, sharing=compatibility mode
  217.     clr    cmdcmd        ;func=open
  218.     call    docmd        ;execute it, come back on interrupt
  219.     bcs    doerr        ;error
  220.     call    savhnd        ;save handle
  221. 10$:    br    dodone
  222. ;
  223. doerr:    bis    #hderr$,@-(r4)    ;hard error bit in CSW
  224. dodone:    ;clr    @krcsr        ;kill ints
  225.     ;clr    @ktcsr
  226.     .drfin    do
  227. ;+
  228. ;
  229. ; Handle directory reads.
  230. ;
  231. ; We read filenames from the host OS one at a time, and build up RT-11 dir
  232. ; segments on the fly.  Unfortunately we get no size/date information.
  233. ;
  234. ; r4    I/O qel
  235. ; DIRBLK  starting blk # of this segment (assumed to be even, screwy results
  236. ;    if not but nothing will get damaged)
  237. ;
  238. ;-
  239. dir:    bit    #1,dirblk    ;begn of segment?
  240.     bne    10$        ;no, starting midway through
  241.     ; prepend segment header
  242.     mov    #31.,r5        ;total # of segments
  243.     call    putw
  244.     mov    dirblk,r5    ;get curr dir blk
  245.     sub    #6-2-2,r5    ;find next segment (2-32.) *2
  246.     asr    r5        ;*1
  247.     bic    #^C37,r5    ;change to 0 if 32. (end of chain)
  248.     call    putw
  249.     mov    #31.,r5        ;highest seg in use (say all of them)
  250.     call    putw
  251.     clr    r5        ;# extra bytes
  252.     call    putw
  253.     mov    #6+<32.*2>,r5    ;all our null files start after dir
  254.     call    putw
  255.     ; if this is the first dir seg, get the dir search started
  256.     cmp    dirblk,#6    ;first block of dir?
  257.     bne    20$        ;no
  258.     clr    dirdon        ;not done yet
  259.     mova    file,r5        ;point at buf
  260.     mov    #"*.,(r5)+    ;init to "*.*"<0>
  261.     mov    #'*,(r5)
  262.     mov    #dofst,cmdcmd    ;command=find first match
  263.     br    30$        ;skip
  264. 10$:    ; starting midway through block, we owe the creation date from the
  265.     ; file entry that spanned the block boundary
  266.     clr    r5        ;creation date=0
  267.     call    putw
  268. 20$:    ; retrieve next filename
  269.     mov    #donxt,cmdcmd    ;command=find next match
  270. 30$:    tst    dirdon        ;already hit EOF?
  271.     bne    90$        ;yes
  272.     mova    file,r5        ;point at buf
  273.     mov    r5,cmdba    ;set addr
  274.     clr    cmdbae
  275.     mov    #lfile,cmdlen    ;length of buf
  276.     call    docmd        ;get next dir entry
  277.     bcs    80$        ;failed
  278.     clrb    efile        ;guarantee terminating NUL
  279.     cmp    diroff,#<<1000-<5*2>>/16>*16+<5*2> ;about to wrap to 2nd blk?
  280.     bne    40$        ;(that number works out to 764)
  281.      inc    dirblk        ;yes, plan ahead
  282. 40$:    mov    #2000,r5    ;status=permanent file
  283.     call    putw
  284.     ; convert filename to RAD50, and trim off path in the process
  285.     mova    file,r5        ;point at filename
  286.     mov    r0,-(sp)    ;save
  287.     mov    r1,-(sp)
  288.     mov    r2,-(sp)
  289. 50$:    call    getrad        ;get filename
  290.     cmp    r2,#'.        ;it *is* the filename right?
  291.     beq    60$        ;yes
  292.     tst    r2        ;filename with no extension?
  293.     bne    50$        ;no, device or path element, ignore
  294. 60$:    mov    r5,-(sp)    ;save ptr
  295.     mov    r0,r5        ;save first word
  296.     call    putw
  297.     mov    r1,r5        ;save second word
  298.     call    putw
  299.     mov    (sp)+,r5    ;restore ptr
  300.     mov    r2,r0        ;extension?  (R0=0 if not)
  301.     beq    70$        ;no, go save the zero
  302.     call    getrad        ;parse extension
  303. 70$:    mov    r0,r5        ;save
  304.     call    putw
  305.     mov    (sp)+,r2    ;restore
  306.     mov    (sp)+,r1
  307.     mov    (sp)+,r0
  308.     clr    r5        ;length=0 (since we don't know)
  309.     call    putw
  310.     clr    r5        ;channel/job=0
  311.     call    putw
  312.     ; if they're reading the segment (which is 2 blocks) one block at a
  313.     ; time, we can get kicked out on the next write (i.e. they only asked
  314.     ; for the first block and this dir entry is overflowing into the 2nd)
  315.     ; we compensate by starting odd blocks off with a zero word
  316.     clr    r5        ;creation date=0
  317.     call    putw
  318.     cmp    diroff,#2000-<16+2> ;space for one more entry and EOS marker?
  319.     bhis    90$        ;no, write end-of-segment marker now
  320.     br    20$        ;back for next file
  321. 80$:    mov    (pc),dirdon    ;done reading dir
  322. 90$:    ; finish off segment
  323.     mov    #4000,r5    ;mark end of segment
  324.     call    putw
  325. 100$:    bit    #777,diroff    ;finished filling out blk?
  326.     beq    120$        ;yes
  327. 110$:    clr    r5        ;write a 0
  328.     call    putw
  329.     br    100$
  330. 120$:    ; prepare for next segment
  331.     inc    dirblk        ;bump to next blk
  332.     cmp    diroff,#2000    ;had we finished padding whole segment?
  333.     bne    110$        ;no, go pad second block of seg
  334.     clr    diroff        ;reinit offset
  335.     tst    q$wcnt(r4)    ;req finished?
  336.     beq    130$        ;yes
  337.     jmp    dir
  338. 130$:    jmp    dodone        ;finish up
  339. ;+
  340. ;
  341. ; Store a byte in the user's buffer.
  342. ;
  343. ; r5    byte to store
  344. ; r4    I/O qel
  345. ;
  346. ; R0-R4 preserved, Z=1 on return if buf is full.
  347. ;
  348. ;-
  349. putb:
  350. .if ne mmg$t
  351.     movb    r5,-(sp)    ;store byte
  352.     call    @$ptbyt        ;(and update Q$BUFF)
  353. .iff
  354.     movb    r5,@q$buff(r4)    ;store byte
  355.     inc    q$buff(r4)
  356. .endc
  357.     dec    q$wcnt(r4)    ;done all?  (Z=1 if so)
  358.     rts    pc
  359. ;+
  360. ;
  361. ; As above, but stores a word, updates DIROFF, and punts if out of space.
  362. ;
  363. ;-
  364. putw:    cmp    q$wcnt(r4),#2    ;got space?
  365.     blo    10$
  366.     add    #2,diroff    ;update offset
  367.     call    putb        ;write low byte
  368.     swab    r5        ;get high byte
  369.     br    putb        ;write that too, return
  370. 10$:    tst    (sp)+        ;flush return address
  371.     jmp    dodone        ;say I/O is finished
  372. ;+
  373. ;
  374. ; Get filename passed by monitor.
  375. ;
  376. ;-
  377. getnam:
  378. .if ne mmg$t
  379.     mova    file50,r5    ;point at buffer
  380.     mov    #3*2,r0        ;counter (# bytes to copy)
  381. 10$:    call    @$gtbyt        ;get a byte
  382.     movb    (sp)+,(r5)+    ;catch it
  383.     dec    r0        ;loop through all
  384.     bne    10$
  385.     sub    #6,r5        ;point at filename
  386. .iff
  387.     mov    q$buff(r4),r5    ;get ptr to .RAD50 name
  388. .endc
  389.     mova    file,r4        ;point at filename buf
  390.     mov    r4,cmdba    ;set addr
  391.     clr    cmdbae
  392.     call    rad$        ;filename
  393.     call    rad$
  394.     movb    #'.,(r4)+    ;.
  395.     call    rad$        ;ext
  396.     clrb    (r4)
  397.     sub    cmdba,r4    ;find length
  398.     mov    r4,cmdlen    ;save length
  399.     rts    pc
  400. ;+
  401. ;
  402. ; Set up a "seek" command packet for file addr in qel at R4.
  403. ;
  404. ;-
  405. seek:    call    gethnd        ;get handle
  406.     bcs    10$        ;not open
  407.     mov    q$blkn(r4),r0    ;get starting block #
  408.     mov    r0,r1        ;copy
  409.     swab    r0        ;left 8
  410.     clrb    r0        ;(clear LSB)
  411.     asl    r0        ;left 9
  412.     mov    r0,cmdba    ;set low addr
  413.     swab    r1        ;right 8, old b7 in b15
  414.     asl    r1        ;right 7, old b7 in C
  415.     adc    r1        ;old b7 in b0
  416.     bic    #^C777,r1    ;isolate high 9
  417.     mov    r1,cmdbae
  418.     clr    cmdprm        ;seek from BOF (C=0)
  419.     mov    #dosek,cmdcmd    ;[func=seek]
  420. 10$:    rts    pc
  421. ;+
  422. ;
  423. ; Load up address (etc.) information for DOS file device access.
  424. ;
  425. ; r4    qel (preserved)
  426. ;
  427. ;-
  428. addr:
  429. .if ne mmg$t
  430.     mov    r4,r5        ;copy qel ptr
  431.     add    #q$buff,r5    ;index to buf addr
  432.     call    @$mpptr        ;call $MPPHY
  433.     mov    (sp)+,cmdba    ;low addr
  434.     mov    (sp)+,r5    ;catch high addr
  435.     asr    r5        ;right-justify
  436.     asr    r5
  437.     asr    r5
  438.     asr    r5
  439.     mov    r5,cmdbae    ;save
  440. .iff
  441.     mov    q$buff(r4),cmdba ;save addr
  442.     clr    cmdbae        ;high bits = 0
  443. .endc
  444.     mov    q$wcnt(r4),cmdlen ;length
  445.     rts    pc
  446. ;+
  447. ;
  448. ; Get file handle for innermost open file.
  449. ;
  450. ; Returned in CMDHND, or C=1 if raw device or no file.
  451. ;
  452. ; R0 trashed, others preserved.
  453. ;
  454. ;-
  455. gethnd:    tst    opensp        ;could there be files open?
  456.     beq    10$        ;no
  457.     mova    flgstk,r0    ;point at file flag stack
  458.     add    opensp,r0    ;index to our entry
  459.     tst    -(r0)        ;open file?
  460.     beq    10$        ;no
  461.     mov    hndstk-flgstk(r0),cmdhnd ;yes, fetch the handle
  462.     tst    (pc)+        ;C=0, skip SEC
  463. 10$:     sec            ;no file
  464.     rts    pc
  465. ;+
  466. ;
  467. ; Save file handle for newly opened file.
  468. ;
  469. ; Stack space already checked by NULFIL.
  470. ;
  471. ; R0 trashed, others preserved.
  472. ;
  473. ;-
  474. savhnd:    add    #2,opensp    ;advance to next
  475.     mova    flgstk,r0    ;point at file flag stack
  476.     add    opensp,r0    ;index to our entry
  477.     mov    #1,-(r0)    ;say open file
  478.     mov    cmdhnd,hndstk-flgstk(r0) ;save handle
  479.     rts    pc
  480. ;+
  481. ;
  482. ; Parse filename, see if they're opening the null filename.
  483. ;
  484. ; Return C=1 if so (or if out of stack space), stack entry created.
  485. ; C=0 if not, so open the file and add its stack entry.
  486. ;
  487. ;-
  488. nulfil:    cmp    opensp,#nstmax*2 ;stack full?
  489.     beq    10$        ;yes, give up now
  490.     call    getnam        ;convert filename
  491.     cmp    cmdlen,#1    ;anything besides the "." we added?
  492.     bne    20$        ;yes, C=0
  493.     add    #2,opensp    ;advance to next
  494.     mova    flgstk,r0    ;point at file flag stack
  495.     add    opensp,r0    ;index to our entry
  496.     clr    -(r0)        ;say no open file
  497. 10$:    sec
  498. 20$:    rts    pc
  499. ;
  500. docsr:    .word    do$csr        ;addrs of device regs
  501. doba:    .word    do$ba
  502. dobae:    .word    do$bae
  503.     .even
  504. ;+
  505. ;
  506. ; Do the current command, appear to return when done.
  507. ;
  508. ; On return, only R4/R5 may be used (because we're on an interrupt).
  509. ; C=1 if DOS file device returned error, R4 points at I/O qel.
  510. ;
  511. ;-
  512. docmd:    mov    (sp)+,docont    ;save continuation addr
  513.     mova    cmdpkt,r0    ;point at packet buf
  514.     mov    r0,@doba    ;set packet addr
  515.     clr    @dobae
  516.     mov    #do$vec,r0    ;get vector
  517.     asr    r0        ;/4
  518.     asr    r0
  519.     swab    r0        ;in LH
  520.     bis    #<4*dopri>!dogo!doie,r0 ;set PRI=4, GO, IE
  521.     mov    r0,@docsr    ;start command
  522.     rts    pc
  523. ;+
  524. ;
  525. ; Interrupt service routine.
  526. ;
  527. ;-
  528.     .drast    do,4,doabrt
  529.     clr    @docsr        ;kill further ints
  530.     tst    docont        ;spurious int?
  531.     beq    10$        ;yes
  532.     mov    docqe,r4    ;get qel back
  533.     cmp    #1,cmdsts    ;C=1 if CMDSTS is non-zero
  534.     jmp    @docont        ;continue
  535. 10$:    rts    pc        ;dismiss
  536. ;
  537. doabrt:    clr    @docsr        ;kill ints
  538. ;;; no way to abort cmd in progress?
  539.     rts    pc
  540. ;+
  541. ;
  542. ; Convert from ASCII to .RAD50.
  543. ;
  544. ; r0    returns first 3 chars
  545. ; r1    returns second 3 chars
  546. ; r2    returns terminator (non-RAD50 char that we stopped on)
  547. ; r5    pointer into .ASCIZ string (updated on return)
  548. ;
  549. ; R3/R4 preserved.
  550. ;
  551. ;-
  552. getrad:    mov    r3,-(sp)    ;save
  553.     call    20$        ;get first 3
  554.     mov    r1,r0        ;save
  555.     call    20$        ;get last 3
  556. 10$:    call    40$        ;try to get another char
  557.     tst    r2        ;was it a .RAD50 char?
  558.     bne    10$        ;yes, skip it
  559.     movb    (r5)+,r2    ;get terminator
  560.     mov    (sp)+,r3
  561.     rts    pc
  562. ;
  563. 20$:    ; get 3 .RAD50 hars from (R5)+ into R1
  564.     call    40$        ;get 1st char
  565.     mov    r2,r1        ;copy
  566.     call    30$        ;add 2nd char, then drop through for 3rd
  567. 30$:    asl    r1        ;*10
  568.     asl    r1
  569.     asl    r1
  570.     mov    r1,r2        ;save value *10
  571.     asl    r1        ;*40
  572.     asl    r1
  573.     add    r2,r1        ;*50
  574.     call    40$        ;get new char
  575.     add    r2,r1        ;add it in
  576.     rts    pc
  577. ;
  578. 40$:    ; get .RAD50 char from (R5)+ into R2, trashes R3
  579.     movb    (r5)+,r3    ;get char
  580.     mov    #<^R  $>,r2    ;try $
  581.     cmp    r3,#'$
  582.     beq    60$
  583. ;;    mov    #<^R  .>,r2    ;try .
  584. ;;    cmp    r3,#'.
  585. ;;    beq    60$
  586.     mov    r3,r2        ;try digit
  587.     add    #<^R  0>-'0,r2    ;convert value if digit
  588.     cmp    r3,#'0
  589.     blo    50$
  590.     cmp    r3,#'9
  591.     blos    60$        ;yes it's a digit
  592.     add    #<<^R  A>-'A>-<<^R  0>-'0>,r2 ;translate to letter
  593.     cmp    r3,#'A        ;is it a letter?
  594.     blo    50$
  595.     cmp    r3,#'Z
  596.     blos    60$
  597.     sub    #40,r2        ;suppose it's lower case somehow
  598.     cmp    r3,#'a
  599.     blo    50$
  600.     cmp    r3,#'z
  601.     blos    60$
  602. 50$:    dec    r5        ;none of the above, it's a delimiter
  603.     clr    r2        ;return a blank to pad out field
  604. 60$:    rts    pc
  605. ;+
  606. ;
  607. ; Routine to convert a word from .RAD50 to ASCII.
  608. ;
  609. ; r5    input ptr (+2 on return)
  610. ; r4    output ptr (+0:3 on return)
  611. ;
  612. ;-
  613. rad$:    mov    r5,-(sp)    ;save
  614.     mov    (r5),r5        ;fetch word
  615.     mova    bittab,r3    ;pt at table
  616.     br    40$        ;jump into loop
  617. 10$:    ; next digit
  618.     clr    r0        ;clear it
  619.     mov    #6,r2        ;bit count (each .RAD50 dig is 5.625 bits)
  620. 20$:    asl    r0        ;*2
  621.     cmp    r1,r5        ;OK?
  622.     bhi    30$        ;no (C=0)
  623.     sub    r1,r5        ;remove the bit (C=0)
  624.     inc    r0        ;count it
  625. 30$:    ror    r1        ;/2 (C=0 either way above)
  626.     dec    r2        ;loop
  627.     bne    20$
  628.     add    pc,r0        ;index into R50
  629.     add    #r50-.,r0
  630.     movb    (r0),(r4)+    ;convert, save
  631.     bne    40$
  632.      dec    r4        ;un-put NUL
  633. 40$:    mov    (r3)+,r1    ;get next value
  634.     bne    10$        ;loop if non-zero
  635.     add    pc,r5        ;index into R50
  636.     add    #r50-.,r5
  637.     movb    (r5),(r4)+    ;convert last, save
  638.     bne    50$
  639.      dec    r4        ;un-put NUL
  640. 50$:    mov    (sp)+,r5    ;restore
  641.     tst    (r5)+        ;skip the word we just did
  642.     rts    pc
  643. ;
  644. bittab:    .word    40*50*50,40*50,0
  645. r50:    .ascii    <0>/ABCDEFGHIJKLMNOPQRSTUVWXYZ$.?0123456789/
  646. strstr:    .asciz    /*.*/        ;wildcard for dir lookup
  647. ;
  648. docont:    .word    0        ;continuation address (called on int)
  649.                 ;or 0 if no int expected
  650. ;
  651. opensp:    .word    0        ;offset into "open file" stacks
  652. hndstk:    .blkw    nstmax        ;DOS handle for each file
  653. flgstk:    .blkw    nstmax        ;NZ if handle is valid (0 => opened raw dev)
  654. ;
  655. dirblk:    .word    0        ;next block # in sequence during dir lookup
  656.                 ;(or 0 if not in dir lookup)
  657. diroff:    .blkw            ;offset into current 1 KB dir segment, 0-1777
  658. dirdon:    .blkw            ;NZ => finished reading dir
  659. ;
  660. ;unit:    .blkw            ;current DOn: unit # *2 (used as table index)
  661. ;
  662. .if ne mmg$t
  663. file50:    .blkw    3        ;FILNAMEXT buffer
  664. .endc
  665.     .even            ;DIR expects an even addr
  666. file:    .blkb    10.        ;FILNAM.EXT buffer
  667.     .blkb    128.-10.    ;more space for pathname in DOFST/DONXT
  668. lfile=    .-file            ;length of buf
  669. efile:    .blkb            ;guaranteed NUL at end
  670. ;
  671.     .even
  672. cmdpkt:    ; command packet goes here
  673. cmdcmd:    .blkw            ;command code, 0-8.
  674. cmdsts:    .blkw            ;status (-1=timeout, 0=OK, >0=DOS err)
  675. cmdhnd:    .blkw            ;DOS file handle
  676. cmdprm:    .blkw            ;parameter (if defined by cmd)
  677. cmdlen:    .blkw            ;length of data buffer in bytes
  678. cmdba:    .blkw            ;22-bit absolute addr of data buffer
  679. cmdbae:    .blkw
  680. ;
  681.     .even
  682. ;
  683.     .drend    do
  684.     .end
  685.