home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / beehive / zcat / xref27.lbr / XREF27.AZM / XREF27.ASM
Assembly Source File  |  1991-01-31  |  45KB  |  1,695 lines

  1. ; XREF27.ASM  Cross-reference program for .ASM or .PRN files 11/09/85
  2. ;
  3. ;
  4. ; This program generates a cross-reference list for all labels in an
  5. ; .ASM, .MAC or .PRN file.  Thus it works with either an assembly level
  6. ; source code file or an assembled print file.    No other cross-reference
  7. ; program is known to have this sort of versatility and ease of use.  It
  8. ; will number the lines and generate a cross-reference listing at the
  9. ; end of the program.  If a numbered listing is not requested, it makes
  10. ; a cross-reference listing without the source code - this is often used
  11. ; to find what label names have been already used - or which labels were
  12. ; actually unnecessary as they were not used at all.  The output can be
  13. ; shown to the CRT, sent directly to the printer, or to a disk file.  If
  14. ; a disk file is used, it is given the same name as the original file,
  15. ; with an .EXR extent.
  16. ;
  17. ;-----------------------------------------------------------------------
  18. ;            current revision
  19. ;
  20. ; 11/09/85  Fixed an intermittent bug that was causing the program to
  21. ;   v27     miss seeing the EOF character and keep right on going until
  22. ;        it bombed by filling the disk.  This occured on some longer
  23. ;        .PRN files when adding line numbers.  Took awhile to find,
  24. ;        as only occured occasionally.  Likely been around since the
  25. ;        program was written.    - Irv Hoff
  26. ;
  27. ;-----------------------------------------------------------------------
  28. ;
  29. ; It is invoked by entering:
  30. ;
  31. ;    XREF FILEBNME.ASM    (output to printer)
  32. ;    XREF FILENAME.PRN CRT    (output to CRT)
  33. ;    XREF FILENAME.ASM D    (output to disk - default drive)
  34. ;    XREF FILENAME.PRN B:D    (output to disk - drive B: in this case)
  35. ;
  36. ; To get the help guide type:
  37. ;
  38. ;    XREF ? <ret>  or   XREF <ret>
  39. ;
  40. ;-----------------------------------------------------------------------
  41. ; Number of lines per output page set by equ LPAGE.  Set this equate to
  42. ; zero if you don't want any form feeds added in the cross-reference
  43. ; listing - it will still put one at the beginning and end.
  44. ;
  45. ; NREFS sets the number of label references per table entry.  This
  46. ; value should be set to the average number of references that a label
  47. ; will have in the program.  It is used to build the label reference
  48. ; table entries.  Each entry will be equal to (NREFS*2)+2.  If it is
  49. ; made unnecessarily large, then the label reference table will be very
  50. ; large with a lot of unused slots.  Example: a program with 300 labels
  51. ; will require a reference table that is at least 12600 bytes if
  52. ; NREFS=20, whereas the same program will require a reference table that
  53. ; is at least 3600 bytes if NREFS=5.  Each label that exceeds NREFS re-
  54. ; ferences will require ((Total references/NREFS) rounded up) reference
  55. ; table entries.  Recommended values: 3-5.
  56. ;
  57. ; LREFS sets the Number of labels references to be printed per output
  58. ; line.  It should be a multiple of NREFS.  If it is not, then the first
  59. ; number that is less than LREFS and is a multiple of NREFS will be
  60. ; printed on the line.    Example: if NREFS is 5 and LREFS is 13, then
  61. ; only 10 entries will be printed per line.  The total number of refer-
  62. ; ences that will fit on one line without overflow is equal to the size
  63. ; of the line minus (LABSIZ+2) divided by 6.  Example: if the line size
  64. ; is 72 characters and LABSIZ equals 10, then total number of references
  65. ; per line can be INT((72-(10+2))/6) or INT(60/6) or 10.
  66. ;
  67. ; LABSIZ sets the Label size.  This is the label size that the program
  68. ; will use in the cross reference listing.  It should be large enough to
  69. ; make each label unique in cross-reference listing.  If a label is
  70. ; larger than the value for LABSIZ, then the label will be truncated in
  71. ; the output i.e., LARGE$LABEL would be LARGE$LABE if LABSIZ was set to
  72. ; 10.  Recommended value is 8.
  73. ;
  74. ; BUFSIZ is the number of disk records that will be read when the disk
  75. ; input buffer is empty.  It is used to calculate the size of the input
  76. ; buffer and output buffers.  Input buffer size = BUFSIZ * 128.  Recom-
  77. ; mended value is from 8 to 32.  16 works well.  This represents a 2k
  78. ; buffer.  Remember there are separate buffers of this size for input
  79. ; and output, doubling the total memory used.
  80. ;
  81. ;
  82. ; NOTE: If INSECT is made too large, there will not be enough memory
  83. ; left to build the cross-reference table for a large program.    Largest
  84. ; tested values so far is 916 on a 64k system.    The file successfully
  85. ; cross-referenced was MDM740.PRN.    - JRM
  86. ;
  87. ;-----------------------------------------------------------------------
  88. ;
  89. ; DONE
  90. ; ----
  91. ;    DONE gets control when a control Z(1AH) is found
  92. ;    in the input data stream.  This routine:
  93. ;
  94. ;    1) issues a page eject
  95. ;    2) prints the cross reference table
  96. ;    3) issues a page eject
  97. ;    4) if disk output, writes out the remaining
  98. ;        sectors in the disk output buffer and
  99. ;        then closes the disk output file
  100. ;    5) closes the disk input file
  101. ;    6) displays end of program message
  102. ;
  103. ;
  104. ; SETUP OR INITIALIZATION
  105. ; -----------------------
  106. ;    1) displays program logo and version
  107. ;    2) checks for input file type PRN
  108. ;         -if file type PRN, sets PRN switch
  109. ;    3) if operator specified FN.FT CON, then sets console
  110. ;       output switch on.  Goes to step 5
  111. ;    4) else check for disk output option
  112. ;         -if not disk output, default to printer output
  113. ;         -go to step 5
  114. ;         -else check to see if cross reference file exists
  115. ;          -if it exists, ask operater if it is to be erased
  116. ;            -if no erase, terminate program
  117. ;            -else erase cross reference file
  118. ;         -then create new cross reference disk file
  119. ;         -initialize output character pointer to disk buffer
  120. ;    5) open input disk file
  121. ;    6) initialize printer buffer, address pointers for label table
  122. ;       and reference table, set line counter to 1
  123. ;    7) return to caller
  124. ;
  125. ; DBYT
  126. ; ----
  127. ;    Put output character into disk buffer
  128. ;
  129. ;    Input = E (output character)
  130. ;
  131. ;    1) move character to buffer
  132. ;    2) if at end of buffer, go
  133. ;       write out disk buffer
  134. ;    3) else add 1 to disk buffer
  135. ;       pointer
  136. ;    4) subtract 1 from number of
  137. ;       positions left in buffer
  138. ;    5) go check if operator pressed ^C
  139. ;
  140. ;
  141. ; PUTREC
  142. ; ------
  143. ;    Write out disk buffer to disk
  144. ;
  145. ;    1) initialize start of disk buffer address and number
  146. ;       of sectors to write out
  147. ;    2) get current disk sector buffer address
  148. ;    3) add 128 to it and save for DMA of sector after
  149. ;       current sector
  150. ;    4) do DMA for current sector buffer address
  151. ;    5) write current disk sector
  152. ;    6) if not last sector repeat steps 2 thru 5
  153. ;    7) set number of characters positions left in buffer
  154. ;       to size of buffer
  155. ;    8) set disk output buffer pointer to front of buffer
  156. ;    9) go check to see if operator pressed control C
  157. ;
  158. ;
  159. ; GETBT
  160. ; -----
  161. ;    Routine to read a byte
  162. ;
  163. ;    Outputs: A=byte
  164. ;
  165. ;    1) is current byte pointer at
  166. ;       end of buffer?
  167. ;          -yes, Read disk records
  168. ;           into buffer
  169. ;    2) move character from buffer
  170. ;       to ACCUM
  171. ;    3) add 1 to character pointer
  172. ;       and save pointer
  173. ;    4) return to caller
  174. ;
  175. ;
  176. ; GETREC
  177. ; ------
  178. ; Read the number of input records specified by BUFSIZ.  The buffer
  179. ; starts at TBUF.  Before each DMA, the buffer address is incremented by
  180. ; 128 and saved in IDADDR.  This address will be used for the DMA after
  181. ; the current sector is read.  The logic is:
  182. ;
  183. ;    1) get current buffer address
  184. ;    2) add 128 to it and save it
  185. ;    3) issue DMA for current buffer address
  186. ;    4) read the disk record,
  187. ;          -if end of file goto step 7
  188. ;    5) decrement number of sectors to read
  189. ;    6) if not number of sectors not zero
  190. ;          -repeat above
  191. ;    7) reset character pointer to first buffer
  192. ;    8) return to caller
  193. ;
  194. ;-----------------------------------------------------------------------
  195. ;              prior updates
  196. ; 09/09/85  Rewrote the display routine so it has all reference numbers
  197. ;   v26     lined up uniformly, with a leading asterisk on the number
  198. ;        representing the line where the label is defined.  Other
  199. ;        changes.            - Irv Hoff
  200. ;
  201. ; 01/13/85  Modified help message and introduced XRF-only option, most
  202. ;   v25     editors can easily find a line with a number.  Added markers
  203. ;        " >>" for label-definition.  Shortened line number display
  204. ;        to be consistent with CREF output.    Moved code to conserve
  205. ;        space.  Moved comments from M80 source which are no longer
  206. ;        needed as LASM is there and does the job.
  207. ;                    - B. Eiben
  208. ;
  209. ; 01/30/83  Added operation (and pseudo) codes for the Z80 and M80 as-
  210. ;   v24     semblers.  While M80 CREF80 are superior they are limited by
  211. ;        the size of the CRF files since instead of TAB space fill is
  212. ;        used (an 80K MAC file expands to a 240K CRF file).    This
  213. ;        program will handle at least 1200  labels in 48K RAM.  Even
  214. ;        without flagging the defining statement, this program is
  215. ;        quite useful.        - RMG
  216. ;
  217. ; 03/15/82  This program would lock up if there was a comment line that
  218. ;   v23     started with an asterisk '*' instead of a semicolon.  The
  219. ;        program then processed the whole line as a valid line of as-
  220. ;        sembly-level code.    This usually resulted in the cross re-
  221. ;        ference program locking up if there were a lot of lines that
  222. ;        started with an asterisk.  The program now treats an aster-
  223. ;        isk the same as a semicolon.  This was done by changing the
  224. ;        table CTAB1 so that the program branches to LSEMI when it
  225. ;        finds an asterisk.    Also fixed bug that occurred when the
  226. ;        last record of a file was completely filled with data and
  227. ;        thus had no control Z's (EOF characters) in it.  This was
  228. ;        done by always placing two control Z's after the last record
  229. ;        was read.  Finally fixed a bug that showed up only when a
  230. ;        program had no symbols or labels in it.  Added a check for
  231. ;        an empty label table before attempting to print the label
  232. ;        symbol table.        - JRM
  233. ;
  234. ; 03/06/82  Changed the code so the size of output disk buffer can be
  235. ;   v22     specified at assembly time.  The size is set by OUTSECT
  236. ;        which equals the number of disk sectors to be written when
  237. ;        the buffer is full.  Implemented the same feature for disk
  238. ;        input.  INSECT sets the number of disk records to be read
  239. ;        into the input buffer.  On file type PRN the was a bug.
  240. ;        Whenever the first label on a line was preceded by a char-
  241. ;        acter, the line was not listed in the cross-reference list-
  242. ;        ing.  This was caused by skipping over the first 16 char-
  243. ;        acters in the line on a CR (carriage return) instead of on a
  244. ;        LF (line feed).  This bug has been fixed.  Added help func-
  245. ;        tion.  This is invoked by entering XFER ?
  246. ;                    - JRM
  247. ;
  248. ; 03/03/82  Added a 2k buffer for disk output writes.  This was done to
  249. ;   v21     speed up the execution of program when disk output was spec-
  250. ;        ified.  Fixed bug when page size was specified.  CP/M assem-
  251. ;        bler was not doing the conditional IF assembly correctly.
  252. ;        Changed the code to test if page size is in effect by test-
  253. ;        ing LPAGE to see if it is zero.  Changed test to question to
  254. ;        erase existing disk cross-reference file to handle lower-
  255. ;        case as well as upper-case.
  256. ;                    - JRM
  257. ;
  258. ; 02/20/82  Changed code so that the size of the label that is refer-
  259. ;   v20     enced in the cross-reference listing can be set at assembly
  260. ;        time.  The original program only allowed for 5 characters
  261. ;        per label.    This did not allow for separate unique labels
  262. ;        where the uniqueness occurred after the first 5 characters.
  263. ;        I tested this function for a length of 5, 8, and 10 chara-
  264. ;        cters  labels.  It should work for any length of label.  I
  265. ;        also allowed the '$' character to be a valid character in a
  266. ;        label.  The equ LABSIZ was added and all other values and
  267. ;        variables that are dependent on the size of the label are
  268. ;        expressed using LABSIZ.
  269. ;
  270. ;        Example: LSIZ EQU LABSIZ+3
  271. ;
  272. ;        Added a disk file output option.  The output disk file will
  273. ;        use the filename of the input file and always have a file
  274. ;        type of 'XRF'.  This option is enabled by specifying a 'D'
  275. ;        as the second parameter when executing the program.  The
  276. ;        user can optionally specify a different drive from the de-
  277. ;        fault drive for the cross-reference disk output.
  278. ;
  279. ;        Example: XREF FILENAME.ASM D
  280. ;             XREF FILENAME.PRN B:D
  281. ;                        - JRM
  282. ;
  283. ;-----------------------------------------------------------------------
  284. ;
  285. ;
  286. ; Equates that can be changed
  287. ;
  288. BUFSIZ    EQU    16        ; In and out buffer size, 8 records = 1k
  289. LABSIZ    EQU    10        ; Number of characters per label
  290. LPAGE    EQU    0        ; Num lines per page if peject is true
  291. LREFS    EQU    10        ; References per output line
  292. NREFS    EQU    5        ; Number of references per ref tbl entry
  293. ;
  294. ;
  295. ; Equates that can't be changed
  296. ;
  297. LSIZ    EQU    LABSIZ+3    ; Label table entry size
  298. REFSZ    EQU    2+(NREFS*2)    ; Number of bytes in ref block
  299. RSIZ    EQU    05        ; Size of rtab table entry
  300. ;
  301. BS    EQU    08H        ; Backspace
  302. CR    EQU    0DH        ; Carriage return
  303. EOF    EQU    1AH        ; EOF code
  304. LF    EQU    0AH        ; Line feed
  305. ;
  306. ;
  307. ; Operating system equates
  308. ;
  309. BOOT    EQU    0000H        ; Reboot entry point
  310. BDOS    EQU    0005H        ; CP/M entry point
  311. ;
  312. MEMSZ    EQU    0006H        ; End of memory pointer
  313. TFCB    EQU    005CH        ; Trans. FCB
  314. ;
  315. CONIN    EQU    01        ; Console input function code
  316. PSTRING    EQU    09        ; Print string function code
  317. OPEN    EQU    15        ; Open function code
  318. CLOSE    EQU    16        ; Close file function code
  319. DELETE    EQU    19        ; Delete file function code
  320. READ    EQU    20        ; Read disk function code
  321. WRITE    EQU    21        ; Write disk function code
  322. MAKE    EQU    22        ; Make file function code
  323. SETDMA    EQU    26        ; Set DMA function code
  324. ;
  325. ;
  326. ; Main loop
  327. ;
  328. ;
  329.     ORG    100H
  330. ;
  331. ;
  332. START:    LXI    SP,STACK    ; Set stack pointer
  333.     CALL    SETUP        ; Initialize
  334. ;
  335. MAIN:    CALL    GETBT        ; Get a byte from source file
  336. ;
  337. MAIN1:    CALL    CKNUM        ; Test for numeric
  338.     JNC    LNUM        ; Yes, found a number, process
  339.     CALL    CKALP        ; Test for alphabetic
  340.     JNC    LALPH        ; Yes, process
  341.     LXI    H,CTAB1        ; Point to character table
  342.     CALL    LOOK        ; Look up character in character table
  343.     JC    MAIN        ; Not found, ignore
  344.     PCHL            ; Execute routine
  345. ;.....
  346. ;
  347. ;
  348. ; Finished
  349. ;
  350. ; Final label table print
  351. ;
  352. DONE:    MVI    E,0CH        ; Printer form feed character
  353.     CALL    PBYT
  354.     MVI    A,0FFH        ;
  355.     STA    LISTFLG        ; CREF-list on always
  356.     LHLD    LABBT        ; Get label table bottom
  357.     MVI    A,0FFH        ; Check to see if there were...
  358.     CMP    M        ; Any labels in the program
  359.     JZ    DLP4        ; No, don't print label table
  360.     SHLD    LAB        ; Set label pointer
  361.     LHLD    LABTP        ; Get label table top
  362.     MVI    M,0FFH        ; End off label table
  363. ;
  364. DLP1:    LHLD    LAB        ; Get label table pointer
  365.     CALL    PLAB        ; Print label
  366.     LHLD    LAB
  367.     LXI    D,LABSIZ+1    ; Offset to reference link
  368.     DAD    D
  369.     MOV    E,M
  370.     INX    H
  371.     MOV    D,M        ; Get reference block address
  372.     XCHG            ; Into HL
  373.     SHLD    REF
  374.     CALL    PREF        ; Print references
  375.     LHLD    LAB        ; Get label table pointer
  376.     LXI    D,LSIZ        ; Size of symbol table entry
  377.     DAD    D
  378.     SHLD    LAB
  379.     MOV    A,M        ; Get byte
  380.     CPI    0FFH        ; End of table?
  381.     JNZ    DLP1        ; Loop
  382. ;
  383. DLP2:    MVI    E,0CH        ; Printer form feed character
  384.     CALL    PBYT
  385.     LDA    DISKOUT        ; Get disk output switch
  386.     ORA    A        ; Disk output being used?
  387.     JZ    DLP3        ; No, issue end msg & return to CP/M
  388.     LXI    H,DISKBUF    ; Get output disk buffer
  389.     LXI    D,OFCB        ; And out fcb
  390.     CALL    DCLOSE        ; And close output disk file
  391. ;
  392. DLP3:    LXI    D,TFCB        ; Close input file
  393.     MVI    C,CLOSE
  394.     CALL    BDOS
  395.     LXI    D,DONEMSG    ; Tell operator we're done
  396.     CALL    PSOUT
  397.     JMP    BOOT        ; And return to CP/M
  398. ;.....
  399. ;
  400. ;
  401. DLP4:    LXI    H,NOLABS    ; Get no label message
  402.     MVI    B,28        ; Number of characters in message
  403. ;
  404. DLP5:    MOV    E,M        ; Print the message
  405.     CALL    PBYT
  406.     INX    H
  407.     DCR    B
  408.     JNZ    DLP5
  409.     JMP    DLP2        ; Go close files
  410. ;
  411. ;
  412. ; Label print routine
  413. ;
  414. PLAB:    MVI    B,LABSIZ    ; Label size
  415. ;
  416. PLAB1:    MOV    E,M        ; Get byte
  417.     CALL    PBYT        ; Print byte
  418.     INX    H
  419.     DCR    B
  420.     JNZ    PLAB1
  421.     MVI    E,' '
  422.     CALL    PBYT        ; Print 2 spaces
  423.     CALL    PBYT
  424.     RET
  425. ;.....
  426. ;
  427. ;
  428. ; Reference print routine
  429. ;
  430. PREF:    MVI    A,LREFS/NREFS    ; Number of blocks to print on one line
  431.     STA    NLINS        ; To nlins
  432. ;
  433. PREF1:    LHLD    REF        ; Get reference block address
  434.     INX    H
  435.     INX    H        ; Bump to first reference number
  436.     SHLD    TEMP        ; Save reference number address
  437.     MVI    A,(REFSZ-2)/2    ; Number of ref slots
  438.     STA    LABCT        ; Save in symct
  439. ;
  440. PREF2:    LHLD    TEMP        ; Get reference slot address
  441.     MOV    E,M
  442.     INX    H
  443.     MOV    D,M        ; Get reference
  444.     LXI    H,0000        ; Zero?
  445.     CALL    CPHL
  446.     JZ    CRLF        ; Yes, done
  447.     PUSH    D
  448.     MVI    E,' '
  449.     CALL    PBYT
  450.     POP    D
  451.     MOV    A,D
  452.     ANI    080H        ; High bit set ?
  453.     JZ    PREF3        ; Nope
  454. ;
  455.     MOV    A,D        ; If a label entry, show
  456.     ANI    07FH
  457.     MOV    D,A        ; Clear it
  458.     PUSH    D
  459.     MVI    E,'*'
  460.     CALL    PBYT
  461.     POP    D
  462.     JMP    PREF4        ; Skip next space
  463. ;
  464. PREF3:    PUSH    D
  465.     MVI    E,' '
  466.     CALL    PBYT
  467.     POP    D
  468. ;
  469. PREF4:    XCHG            ; Get number in HL
  470.     CALL    DECOT        ; Convert
  471.     CALL    DECPNT        ; Print it
  472.     LHLD    TEMP        ; Get reference slot address
  473.     INX    H
  474.     INX    H        ; Bump to next slot
  475.     SHLD    TEMP
  476.     LDA    LABCT        ; Get count
  477.     DCR    A        ; Decrement
  478.     STA    LABCT
  479.     JNZ    PREF2
  480.     LHLD    REF        ; Get ref block address
  481.     MOV    E,M
  482.     INX    H
  483.     MOV    D,M        ; Get link to next block
  484.     LXI    H,0000
  485.     CALL    CPHL        ; Any more blocks?
  486.     JZ    CRLF        ; No, exit
  487. ;
  488.     XCHG            ; Yes, set next block pointer in ref
  489.     SHLD    REF
  490.     LDA    NLINS
  491.     DCR    A        ; Decrement lines count
  492.     STA    NLINS
  493.     JNZ    PREF1        ; And print more on same line
  494.     CALL    CRLF        ; Print CR and LF
  495.     MVI    B,LABSIZ+2    ; Indent continuation line...
  496. ;
  497. PREF5:    MVI    E,' '        ; With spaces
  498.     CALL    PBYT        ; Print spaces
  499.     DCR    B
  500.     JNZ    PREF5        ; Print 6 spaces
  501.     JMP    PREF
  502. ;.....
  503. ;
  504. ;
  505. ; Character parsing routines
  506. ;
  507. LALPH:    LXI    H,SBUF        ; Point to label buffer
  508.     MVI    C,LABSIZ
  509.     MVI    A,' '        ; Fill label...
  510. ;
  511. LALX:    MOV    M,A        ; With...
  512.     INX    H        ; Blanks
  513.     DCR    C
  514.     JNZ    LALX        ; Clear label buffer
  515.     LXI    H,SBUF
  516.     SHLD    LABPT
  517.     MVI    A,00
  518.     STA    LABCT        ; Reset label pointer+count
  519.     LDA    CHAR        ; Get character again
  520.     CALL    GTLAB        ; Collect identifier
  521. ;
  522. LALC:    CALL    GETBT        ; Get a byte from source file
  523.     CALL    CKNUM        ; Test for number
  524.     JNC    LAL3        ; Yes, continue
  525.     CALL    CKALP        ; Test for alphabetic
  526.     JNC    LAL3        ; Yes, continue
  527.     CALL    CRES        ; Test for reserved word
  528.     JC    LAL1        ; No, continue
  529. ;
  530. LAL0:    CALL    LINUP        ; Up LINLAB
  531.     LDA    CHAR        ; Get character that ended ID
  532.     JMP    MAIN1        ; Continue scan
  533. ;.....
  534. ;
  535. ;
  536. ;
  537. LAL1:    CALL    FIND        ; See if defined
  538.     JC    LAL2        ; No, continue
  539.     CALL    ADDRF        ; Yes, add reference
  540.     JMP    LAL0        ; Done
  541. ;.....
  542. ;
  543. ;
  544. LAL2:    CALL    ENLAB        ; Enter label definition
  545.     CALL    ADDRF        ; Add reference
  546.     JMP    LAL0        ; Continue
  547. ;.....
  548. ;
  549. ;
  550. LAL3:    CALL    GTLAB        ; Collect identifier
  551.     JMP    LALC        ; Continue
  552. ;.....
  553. ;
  554. ;
  555. LNUM:    CALL    GETBT        ; Get byte
  556.     CALL    CKNUM        ; Test for numeric
  557.     JNC    LNUM        ; Yes, continue
  558.     CALL    CKALP        ; Test for alphabetic
  559.     JNC    LNUM        ; Yes, continue
  560.     JMP    MAIN1        ; Continue with main scan
  561. ;.....
  562. ;
  563. ;
  564. LQUOT:    CALL    GETBT        ; Get a byte
  565.     CPI    ''''        ; See if string quote
  566.     JNZ    LQUOT        ; No, keep looping
  567.     CALL    GETBT        ; Get next byte
  568.     CPI    ''''        ; Test for doubles
  569.     JZ    LQUOT        ; Yes, start scan again
  570.     JMP    MAIN1        ; No, continue in main scan
  571. ;.....
  572. ;
  573. ;
  574. LSEMI:    CALL    GETBT        ; Get a byte
  575.     CPI    CR        ; Wait for cr
  576.     JNZ    LSEMI        ; Continue
  577.     JMP    MAIN1        ; Enter main loop
  578. ;.....
  579. ;
  580. ;
  581. LCR:    CALL    PLINE        ; Print line
  582.     LHLD    LCNT        ; Get line number
  583.     INX    H        ; Bump line number
  584.     SHLD    LCNT        ; Store
  585.     JMP    MAIN
  586. ;.....
  587. ;
  588. ;
  589. LLF:    PUSH    PSW        ; Save char
  590.     LDA    FTPRN        ; Is it file...
  591.     ORA    A        ; Type prn?
  592.     JZ    LLF2        ; Yes, skip 1rst 16 char
  593.     POP    PSW        ; Restore char
  594. ;
  595. LLF1A:    PUSH    PSW        ;
  596.     MVI    A,0        ; Reset LINLAB
  597.     STA    LINLAB
  598.     POP    PSW
  599.     JMP    MAIN
  600. ;.....
  601. ;
  602. ;
  603. LLF2:    POP    PSW        ; Restore character
  604.     MVI    B,16        ; # of char to skip over
  605. ;
  606. LLF3:    CALL    GETBT        ; Get next byte
  607.     CPI    CR        ; Carriage return?
  608.     JZ    LCR        ; Yes, get next line
  609.     CPI    EOF        ; End of file now?
  610.     JZ    DONE        ; If yes, finish up
  611.     DCR    B        ; Skipped all char?
  612.     JNZ    LLF3        ; No, continue skipping
  613.     JMP    LLF1A        ; Continue
  614. ;.....
  615. ;
  616. ;
  617. LIGN:    JMP    MAIN        ; Re-enter main loop
  618. LSPC    EQU    LIGN
  619. LTAB    EQU    LIGN
  620. LDOL    EQU    LIGN
  621. LDEL    EQU    LIGN
  622. ;
  623. ;
  624. ;----------------------------------------------------------------------
  625. ;               subroutines
  626. ;
  627. ; Check for reserved word
  628. ;
  629. CRES:    LXI    H,RTAB        ; Point to reserved word table
  630.     SHLD    TEMP        ; Save in temp word
  631. ;
  632. CRES1:    LHLD    TEMP        ; Get table pointer
  633.     LXI    D,SBUF        ; Point to label
  634.     MVI    B,5        ; Label size
  635. ;
  636. CRES2:    LDAX    D        ; Get label byte
  637.     CMP    M        ; Compare against table entry
  638.     RC            ; Less, not in table
  639.     JNZ    CRES3        ; Greater, get next table entry
  640.     INX    D        ; Bump pointers
  641.     INX    H
  642.     DCR    B        ; Decrement byte count
  643.     JNZ    CRES2        ; Keep testing
  644.     JMP    CRES4        ; Found
  645. ;
  646. CRES3:    LHLD    TEMP        ; Get table pointer
  647.     LXI    D,RSIZ        ; Size of entry
  648.     DAD    D        ; Bump pointer
  649.     SHLD    TEMP        ; Store new pointer
  650.     MOV    A,M        ; Get table byte
  651.     CPI    0FFH        ; End of table?
  652.     JNZ    CRES1        ; No, loop
  653.     STC            ; Set carry (not in table)
  654.     RET
  655. ;.....
  656. ;
  657. ;
  658. CRES4:    ORA    A        ; Reset carry
  659.     RET
  660. ;.....
  661. ;
  662. ;
  663. ; Find label in table
  664. ;
  665. FIND:    LHLD    LABBT        ; Get begin of sym table
  666.     SHLD    LAB        ; Set temp pointer
  667. ;
  668. FIND1:    LHLD    LAB        ; Get temp pointer
  669.     LXI    D,SBUF        ; Point to current label
  670.     MVI    B,LABSIZ    ; Label size
  671. ;
  672. FIND2:    LDAX    D        ; Get byte from sbuf
  673.     CMP    M        ; Compare to sym table byte
  674.     RC            ; Greater, not in table
  675.     JNZ    FIND3        ; Less, get next table entry
  676.     INX    D        ; Bump pointer
  677.     INX    H        ; Bump pointer
  678.     DCR    B        ; Decrement byte count
  679.     JNZ    FIND2        ; Loop
  680.     RET            ; True zero, found
  681. ;...
  682. ;
  683. ;
  684. FIND3:    LHLD    LAB        ; Get current pointer
  685.     LXI    D,LSIZ        ; Label table entry size
  686.     DAD    D        ; Bump pointer
  687.     XCHG            ; Into de
  688.     LHLD    LABTP        ; Get top of label table
  689.     CALL    CPHL        ; Test for end of table
  690.     JZ    FIND4        ; Yes, done
  691.     JC    FERR        ; Table overflow, error
  692.     XCHG            ; Current pointer into HL
  693.     SHLD    LAB        ; Set current pointer
  694.     JMP    FIND1        ; Loop
  695. ;
  696. FIND4:    STC            ; Set carry for not found
  697.     LHLD    LABTP        ; Get current top
  698.     SHLD    LAB        ; Set current pointer
  699.     RET
  700. ;.....
  701. ;
  702. ;
  703. FERR:    LXI    D,EMSG1        ; Label table error message
  704. ;
  705. FERR1:    CALL    PSOUT        ;
  706.     JMP    BOOT        ; Exit
  707. ;
  708. FERR2:    LXI    D,EMSG6        ; No room for label table
  709.     JMP    FERR1
  710. ;
  711. ;
  712. ; Add reference to ref table
  713. ;
  714. ADDRF:    LHLD    LAB        ; Get label pointer
  715.     LXI    D,LABSIZ+1    ; Offset past label&flags
  716.     DAD    D
  717.     MOV    E,M
  718.     INX    H
  719.     MOV    D,M        ; Get reference pointer
  720.     LXI    H,0000
  721.     CALL    CPHL        ; Test for zero ref ptr
  722.     JZ    BLDRF        ; Yes, build reference entry
  723. ;
  724. LINK1:    XCHG            ; Ref ptr in hl
  725.     MOV    E,M        ; Get ref link
  726.     INX    H
  727.     MOV    D,M        ; Into de
  728.     DCX    H        ; Reposition hl
  729.     PUSH    H        ; Save ref ptr
  730.     LXI    H,0000
  731.     CALL    CPHL        ; If link is zero
  732.     POP    H
  733.     JNZ    LINK1        ; Non zero, get next link
  734.     SHLD    REF        ; Save ref pointer
  735.     INX    H
  736.     INX    H        ; Skip to first ref number
  737.     MVI    B,(REFSZ-2)/2    ; Number of ref numbers/entry
  738. ;
  739. LINK3:    MOV    E,M        ; Get ref number
  740.     INX    H
  741.     MOV    D,M
  742.     DCX    H        ; Reposition
  743.     PUSH    H        ; Save ref num addr
  744.     LXI    H,0000
  745.     CALL    CPHL        ; See if ref num is zero
  746.     POP    H
  747.     JZ    ENREF        ; Yes, enter reference
  748.     INX    H
  749.     INX    H        ; Skip to next ref num
  750.     DCR    B        ; Decrement count
  751.     JNZ    LINK3        ; Try again at next slot
  752.     CALL    ADBLK        ; Add new ref block
  753.     LHLD    REF        ; Get ref pointer
  754.     INX    H
  755.     INX    H        ; Skip to first ref slot
  756. ;
  757. ENREF:    PUSH    H        ; Save ref slot addr
  758.     LHLD    LCNT        ; Get line number
  759.     XCHG            ; Into de
  760.     POP    H        ; Get ref slot addr
  761.     LDA    LINLAB        ; First label on line ?
  762.     ORA    A
  763.     JNZ    ENREF1        ; Nope
  764.     CALL    LINUP        ; Up LINLAB
  765.     MOV    A,D
  766.     ADI    080H
  767.     MOV    D,A        ; Set high bit
  768. ;
  769. ENREF1:    MOV    M,E
  770.     INX    H
  771.     MOV    M,D        ; Store line ref
  772.     RET            ; Done
  773. ;.....
  774. ;
  775. ;
  776. ; Build reference table block
  777. ;
  778. BLDRF:    LHLD    LAB        ; Get label pointer
  779.     LXI    D,LABSIZ+1    ; Offset to ref pointer
  780.     DAD    D
  781.     SHLD    REF        ; Set temp ref pointer to here
  782.     CALL    ADBLK        ; Add block
  783.     LHLD    REF        ; Get real ref pointer
  784.     INX    H
  785.     INX    H        ; Position to first ref slot
  786.     JMP    ENREF        ; Add reference
  787. ;
  788. ADBLK:    LHLD    REFBT        ; Get ref bottom
  789.     LXI    D,REFSZ        ; Subtract ref size
  790.     MOV    A,L
  791.     SUB    E
  792.     MOV    L,A
  793.     MOV    A,H
  794.     SBB    D
  795.     MOV    H,A
  796.     SHLD    TEMP        ; Save new ref bottom
  797.     XCHG            ; Into de also
  798.     LHLD    LABTP        ; Get label top
  799.     CALL    CPHL        ; Check for bump
  800.     JZ    FERR2        ; Yes, no room
  801.     JNC    FERR2        ; No room
  802.     LHLD    TEMP        ; Get ref bottom
  803.     XCHG            ; Into DE
  804.     LHLD    REF        ; Get ref pointer
  805.     MOV    M,E        ; Set link
  806.     INX    H
  807.     MOV    M,D        ; To new reference check
  808.     LHLD    TEMP        ; Get new reference block address
  809.     SHLD    REF        ; Store in reference
  810.     MVI    B,REFSZ        ; Size of ref block
  811.     MVI    A,0
  812. ;
  813. ADB2:    MOV    M,A        ; Zero the ref block
  814.     INX    H
  815.     DCR    B
  816.     JNZ    ADB2
  817.     LHLD    TEMP        ; Get new ref bottom
  818.     SHLD    REFBT        ; Set refbt
  819.     RET
  820. ;.....
  821. ;
  822. ;
  823. ; Enter label in label table
  824. ;
  825. ENLAB:    LHLD    LAB        ; Get label pointer
  826.     XCHG            ; Into DE
  827.     LHLD    LABTP        ; Get label table top
  828.     CALL    CPHL        ; Check for end of table
  829.     JZ    NWLAB        ; Yes, add label at end
  830.     LXI    D,LSIZ        ; Label table entry size
  831.     DAD    D        ; Calculate new end of table
  832.     XCHG            ; Into de
  833.     LHLD    REFBT        ; Reference table bottom
  834.     CALL    CPHL        ; Test for table overflow
  835.     LXI    D,EMSG7        ; Address of error msg in of overflow
  836.     JZ    FERR1        ; Full, error
  837.     JC    FERR1        ; Yes, error
  838.     LHLD    LABTP        ; Get table top
  839.     LXI    D,LSIZ-1    ; Bump to end of entry
  840.     DAD    D
  841.     SHLD    TO        ; Store in to address
  842.     LXI    D,LSIZ
  843.     MOV    A,L
  844.     SUB    E
  845.     MOV    L,A
  846.     MOV    A,H
  847.     SBB    D
  848.     MOV    H,A        ; Subtract size of one entry
  849.     SHLD    FROM        ; Store as from address
  850.     LHLD    LAB        ; Get current pointer
  851.     SHLD    LIMIT        ; Store as limit address
  852.     CALL    MVUP        ; Move table up in memory
  853. ;
  854. NWLAB:    LHLD    LAB        ; Get current pointer
  855.     LXI    D,SBUF        ; Point to label
  856.     MVI    B,LABSIZ    ; Size of label
  857.     CALL    MOVE        ; Copy label to table
  858.     MVI    A,0
  859.     MOV    M,A
  860.     INX    H
  861.     MOV    M,A
  862.     INX    H
  863.     MOV    M,A        ; Set pointers to 0000
  864.     LHLD    LABTP        ; Get label table top
  865.     LXI    D,LSIZ        ; Get label entry size
  866.     DAD    D        ; Bump
  867.     SHLD    LABTP        ; Store new top
  868.     RET
  869. ;.....
  870. ;
  871. ;
  872. ; Move label table up
  873. ;
  874. MVUP:    LHLD    TO        ; Get to pointer
  875.     MOV    B,H
  876.     MOV    C,L        ; Into BC
  877.     LHLD    FROM        ; Get from pointer
  878.     XCHG            ; Into DE
  879.     LHLD    LIMIT        ; Get limit address
  880. ;
  881. MVUP2:    LDAX    D        ; Get from byte
  882.     STAX    B        ; Store at to address
  883.     CALL    CPHL        ; Compare from to limit
  884.     RZ            ; Exit if done
  885.     DCX    B        ; Decrement to
  886.     DCX    D        ; Decrment from
  887.     JMP    MVUP2        ; Loop
  888. ;.....
  889. ;
  890. ;
  891. ; General purpose move routine
  892. ;
  893. MOVE:    LDAX    D        ; Get byte
  894.     MOV    M,A        ; Store byte
  895.     INX    D
  896.     INX    H        ; Bump pointers
  897.     DCR    B        ; Decrement count
  898.     JNZ    MOVE        ; Loop
  899.     RET
  900. ;.....
  901. ;
  902. ;
  903. ; Binary to decimal conversion
  904. ;
  905. DECOT:    LXI    D,DEC
  906.     XCHG
  907.     LXI    B,10000
  908.     CALL    DIG
  909.     LXI    B,1000
  910.     CALL    DIG
  911.     LXI    B,100
  912.     CALL    DIG
  913.     LXI    B,10
  914.     CALL    DIG
  915.     LXI    B,1
  916.     CALL    DIG
  917.     RET
  918. ;.....
  919. ;
  920. ;
  921. DIG:    MVI    M,'0'
  922. ;
  923. DI0:    MOV    A,E
  924.     SUB    C
  925.     MOV    E,A
  926.     MOV    A,D
  927.     SBB    B
  928.     MOV    D,A
  929.     JM    DI2
  930.     INR    M
  931.     JMP    DI0
  932. ;
  933. DI2:    MOV    A,E
  934.     ADD    C
  935.     MOV    E,A
  936.     MOV    A,D
  937.     ADC    B
  938.     MOV    D,A
  939.     INX    H
  940.     RET
  941. ;.....
  942. ;
  943. ;
  944. ; Print number string in DEC
  945. ;
  946. DECPNT:    LXI    H,DEC+1        ; Point to dec string
  947. ;
  948. DCPNT1:    MOV    E,M        ; Get string byte
  949.     MOV    A,E
  950.     CPI    '$'        ; Done?
  951.     RZ            ; Yes
  952. ;
  953.     CALL    PBYT        ; Print byte
  954.     INX    H        ; Bump pointer
  955.     JMP    DCPNT1
  956. ;.....
  957. ;
  958. ;
  959. ; Up LINLAB after label found
  960. ;
  961. LINUP:    PUSH    PSW
  962.     LDA    LINLAB
  963.     INR    A
  964.     STA    LINLAB        ; Found first separator
  965.     POP    PSW
  966.     RET
  967. ;.....
  968. ;
  969. ;
  970. ; Test for alphabetic character
  971. ;
  972. CKALP:    CPI    '$'        ; Treat '$' like a char
  973.     RZ
  974.     CPI    'A'        ; Ascii 'a'
  975.     RC            ; No, exit
  976.     CPI    'Z'+1
  977.     CMC
  978.     RET
  979. ;.....
  980. ;
  981. ; Test for numeric character
  982. ;
  983. CKNUM:    CPI    '0'
  984.     RC
  985.     CPI    '9'+1
  986.     CMC
  987.     RET
  988. ;.....
  989. ;
  990. ;
  991. ; Look up character in parse table
  992. ;
  993. LOOK:    LXI    D,0003        ; Table entry size
  994.     MOV    B,A        ; Argument byte in b
  995. ;
  996. LOOK2:    MOV    A,M        ; Get table byte
  997.     CPI    0FFH        ; End of table?
  998.     JZ    LOOKN        ; Yes, not found
  999.     CMP    B        ; Compare
  1000.     JZ    LOOKY        ; Found
  1001.     DAD    D        ; Bump pointer
  1002.     JMP    LOOK2        ; Loop
  1003. ;
  1004. LOOKN:    STC            ; Carry = not found
  1005.     RET
  1006. ;.....
  1007. ;
  1008. ;
  1009. LOOKY:    INX    H        ; Skip to table byte
  1010.     MOV    E,M
  1011.     INX    H
  1012.     MOV    D,M        ; Table entry in de
  1013.     XCHG            ; Into hl
  1014.     RET
  1015. ;.....
  1016. ;
  1017. ;
  1018. ; Print source line with number
  1019. ;
  1020. PLINE:    LHLD    LCNT        ; Get line number
  1021.     CALL    DECOT        ; Convert to decimal
  1022.     CALL    DECPNT        ; Print it
  1023. ;
  1024. PL1:    MVI    E,' '
  1025.     CALL    PBYT
  1026.     LDA    FTPRN
  1027.     ORA    A
  1028.     JZ    PL11
  1029.     MVI    E,' '
  1030.     CALL    PBYT
  1031. ;
  1032. PL11:    LXI    H,PBUF        ; Point to print buffer
  1033.     XRA    A
  1034.     STA    COL        ; Set column count
  1035. ;
  1036. PL41:    MOV    E,M        ; Get byte
  1037.     MOV    A,E
  1038.     CPI    CR        ; Done?
  1039.     JZ    PL5
  1040.     CPI    LF        ; Lf?
  1041.     JZ    PL4A        ; Yes, ignore
  1042.     CPI    09H        ; Tab?
  1043.     JNZ    PL42        ; No, continue
  1044.     PUSH    H        ; Save hl
  1045. ;
  1046. PL43:    MVI    E,' '
  1047.     CALL    PBYT        ; Print space
  1048.     LXI    H,COL
  1049.     INR    M
  1050.     MOV    A,M
  1051.     ANI    07H        ; Modulo 8
  1052.     JNZ    PL43
  1053.     POP    H
  1054.     JMP    PL4A
  1055. ;
  1056. PL42:    LDA    COL
  1057.     INR    A
  1058.     STA    COL
  1059.     CALL    PBYT        ; Print byte
  1060. ;
  1061. PL4A:    INX    H
  1062.     JMP    PL41
  1063. ;
  1064. PL5:    CALL    CRLF        ; Print cr,lf
  1065.     LXI    H,PBUF
  1066.     SHLD    LPNT        ; Reset line pointer
  1067.     RET
  1068. ;.....
  1069. ;
  1070. ;
  1071. ; Collect label in label buffer
  1072. ;
  1073. GTLAB:    MOV    B,A        ; Save char
  1074.     LDA    LABCT        ; Get label count
  1075.     CPI    LABSIZ        ; Max?
  1076.     RNC            ; Yes, done
  1077.     INR    A
  1078.     STA    LABCT
  1079.     LHLD    LABPT
  1080.     MOV    M,B
  1081.     INX    H        ; Bump label pointer
  1082.     SHLD    LABPT
  1083.     RET
  1084. ;.....
  1085. ;
  1086. ;
  1087. ; Printer interfaces
  1088. ;
  1089. ; Print a single byte
  1090. ;
  1091. PBYT:    PUSH    B
  1092.     PUSH    D
  1093.     PUSH    H
  1094.     PUSH    PSW
  1095. ;
  1096.     LDA    LISTFLG        ; Listing on ?
  1097.     ORA    A
  1098.     JZ    PBYT3        ; No listing
  1099.     LDA    DISKOUT        ; Disk output...
  1100.     ORA    A        ; In effect?
  1101.     JNZ    DBYT        ; Yes, go write to disk
  1102.     MVI    C,05
  1103.     LDA    CONSOLE        ; Get console out switch
  1104.     ORA    A        ; Console output?
  1105.     JZ    PBYT2        ; No, print output
  1106.     MVI    C,2        ; Console output
  1107. ;
  1108. PBYT2:    CALL    BDOS
  1109. ;
  1110. PBYT3:    MVI    C,11        ; Check console status
  1111.     CALL    BDOS
  1112.     ORA    A        ; If zero, ok
  1113.     JZ    PBYTX        ; Exit
  1114.     MVI    C,1
  1115.     CALL    BDOS        ; Read console char
  1116.     CPI    3
  1117.     JZ    BOOT        ; Abort if ^C, otherwise ignore
  1118. ;
  1119. PBYTX:    POP    PSW
  1120.     POP    H
  1121.     POP    D
  1122.     POP    B
  1123.     RET
  1124. ;.....
  1125. ;
  1126. ;
  1127. ; Put output character into disk buffer - input=e (output character)
  1128. ;
  1129. DBYT:    MOV    A,E        ; Save char to be put in buffer
  1130.     LHLD    DSKCNT        ; Get num of char left in buf
  1131.     XCHG            ; Put num in d,e
  1132.     LHLD    DCHAR        ; Point to next char in buf
  1133.     MOV    M,A        ; Put char in disk buf
  1134.     DCR    E        ; At end of buf?
  1135.     JNZ    DBYT1        ; No, don't write buffer
  1136.     DCR    D        ; At end of buf?
  1137.     JZ    PUTREC        ; Yes, go write buffer
  1138. ;
  1139. DBYT1:    INX    H        ; Point to next char in buf
  1140.     SHLD    DCHAR        ; Save next pos
  1141.     XCHG            ; Put num of char left in h,l
  1142.     SHLD    DSKCNT        ; Save num of remaining char
  1143.     JMP    PBYT3        ; Go check console status
  1144. ;.....
  1145. ;
  1146. ;
  1147. ; Write out disk buffer to disk
  1148. ;
  1149. PUTREC:    LXI    H,DISKBUF    ; Address of disk buffer
  1150.     SHLD    BUFADR        ; Save it for later dma's
  1151.     MVI    B,BUFSIZ    ; Number of disk sectors to write
  1152. ;
  1153. PUTRC2:    PUSH    B        ; Save sector count
  1154.     LHLD    BUFADR        ; Get disk buffer address
  1155.     XCHG            ; Put it in d,e for dma
  1156.     LXI    H,80H        ; Put 128 h,l
  1157.     DAD    D        ; Add 128 to disk buf adr for next dma
  1158.     SHLD    BUFADR        ; Save it for next dma
  1159.     MVI    C,SETDMA    ; Point dma to...
  1160.     CALL    BDOS        ; Correct buffer
  1161.     LXI    D,OFCB        ; Get output disk fcb
  1162.     MVI    C,WRITE        ; Write sector...
  1163.     CALL    BDOS        ; To disk
  1164.     ORA    A        ; Was write successfull?
  1165.     POP    B        ; Restore num of sectors left
  1166.     LXI    D,EMSG4        ; Get err msg in case write failed
  1167.     JNZ    FERR1        ; Disk write failed, display err msg, quit
  1168.     DCR    B        ; Written 16 sectors yet?
  1169.     JNZ    PUTRC2        ; No, continue writing disk sectors
  1170.     LXI    H,BUFSIZ*128    ; Put disk buffer size into HL
  1171.     SHLD    DSKCNT        ; Set num of char left in buf to buffer size
  1172.     LXI    H,DISKBUF    ; Point to front...
  1173.     SHLD    DCHAR        ; Of disk buffer
  1174.     JMP    PBYT3        ; Go check console status for ^C
  1175. ;.....
  1176. ;
  1177. ;
  1178. ; Issue CR, LF and test page
  1179. ;
  1180. CRLF:    MVI    E,CR
  1181.     CALL    PBYT
  1182.     MVI    E,LF
  1183.     CALL    PBYT
  1184.     LDA    LINES
  1185.     INR    A
  1186.     STA    LINES        ; Increment line count
  1187.     MVI    A,LPAGE        ; Get number of lines
  1188.     ORA    A        ; Is it zero?
  1189.     LDA    LINES
  1190.     RZ            ; Yes, return
  1191.     CPI    LPAGE        ; Test line count
  1192.     RNZ
  1193.     MVI    E,0CH        ; Printer form feed character
  1194.     CALL    PBYT
  1195. ;.....
  1196. ;
  1197. ;
  1198. ; Character parsing table
  1199. ;
  1200. CTAB1:    DB    CR
  1201.     DW    LCR
  1202.     DB    LF
  1203.     DW    LLF
  1204.     DB    ''''
  1205.     DW    LQUOT
  1206.     DB    ';'
  1207.     DW    LSEMI
  1208.     DB    ' '
  1209.     DW    LSPC
  1210.     DB    09H
  1211.     DW    LTAB
  1212.     DB    '$'
  1213.     DW    LDOL
  1214.     DB    '('
  1215.     DW    LDEL
  1216.     DB    ')'
  1217.     DW    LDEL
  1218.     DB    '+'
  1219.     DW    LDEL
  1220.     DB    '-'
  1221.     DW    LDEL
  1222.     DB    '*'
  1223.     DW    LSEMI
  1224.     DB    '/'
  1225.     DW    LDEL
  1226.     DB    ','
  1227.     DW    LDEL
  1228.     DB    ':'
  1229.     DW    LDEL
  1230.     DB    EOF
  1231.     DW    DONE
  1232.     DB    0FFH
  1233.     DW    0000H
  1234. ;.....
  1235. ;
  1236. ;
  1237. ; Reserved word table
  1238. ;
  1239. RTAB:    DB    '$    ','8080 '
  1240.     DB    'A    ','ACI  ','ADC  ','ADD  ','ADI  '
  1241.     DB    'AF   ','ANA  ','AND  ','ANI  ','ASEG '
  1242.     DB    'B    ','BC   ','BIT  '
  1243.     DB    'C    ','CALL ','CC   ','CCF  ','CM   '
  1244.     DB    'CMA  ','CMC  ','CMP  ','CNC  ','CNZ  '
  1245.     DB    'COMME','COMMO','COND ','CP   ','CPD  '
  1246.     DB    'CPDR ','CPE  ','CPI  ','CPL  ','CPO  '
  1247.     DB    'CSEG ','CZ   '
  1248.     DB    'D    ','DAA  ','DAD  ','DB   ','DC   '
  1249.     DB    'DCR  ','DCX  ','DE   ','DEC  ','DEFB '
  1250.     DB    'DEFL ','DEFM ','DEFW ','DI   ','DJNZ '
  1251.     DB    'DS   ','DSEG ','DW   '
  1252.     DB    'E    ','EI   ','ELSE ','END  ','ENDC '
  1253.     DB    'ENDIF','ENDM ','ENTRY','EQ   ','EQU  '
  1254.     DB    'EX   ','EXX  ','EXITM','EXT  ','EXTRN'
  1255.     DB    'GE   ','GLOBA','GT   '
  1256.     DB    'H    ','HL   ','HIGH ','HALT '
  1257.     DB    'IF   ','IFB  ','IFDEF','IFE  ','IFF  '
  1258.     DB    'IFNB ','IFNDE','IFT  ','IF1  ','IF2  '
  1259.     DB    'IM   ','IN   ','INC  ','INCLU','IND  '
  1260.     DB    'INDR ','INIR ','INR  ','INX  ','IRP  '
  1261.     DB    'IRPC ','IX   ','IY   '
  1262.     DB    'JC   ','JM   ','JMP  ','JNC  ','JNZ  '
  1263.     DB    'JP   ','JPE  ','JPO  ','JR   ','JZ   '
  1264.     DB    'L    ','LALL ','LD   ','LDA  ','LDAX '
  1265.     DB    'LDD  ','LDDR ','LDI  ','LDIR ','LE   '
  1266.     DB    'LHLD ','LIST ','LOCAL','LOW  ','LT   '
  1267.     DB    'LXI  '
  1268.     DB    'M    ','MACRO','MOD  ','MOV  ','MVI  '
  1269.     DB    'NAME ','NC   ','NE   ','NEG  ','NOP  '
  1270.     DB    'NOT  ','NUL  ','NZ   '
  1271.     DB    'OR   ','ORA  ','ORG  ','ORI  ','OTDR '
  1272.     DB    'OTIR ','OUT  ','OUTI ','OUTD '
  1273.     DB    'P    ','PAGE ','PCHL ','PE   ','PO   '
  1274.     DB    'POP  ','PRINT','PSW  ','PUBLI','PUSH '
  1275.     DB    'RADIX','RAL  ','RAR  ','RC   ','REPT '
  1276.     DB    'RES  ','RET  ','RETI ','RL   ','RLA  '
  1277.     DB    'RLC  ','RLCA ','RLD  ','RM   ','RNC  '
  1278.     DB    'RNZ  ','RP   ','RPE  ','RPO  ','RR   '
  1279.     DB    'RRA  ','RRC  ','RRCA ','RRD  ','RST  '
  1280.     DB    'RZ   '
  1281.     DB    'SALL ','SBB  ','SBC  ','SBI  ','SCF  '
  1282.     DB    'SET  ','SHL  ','SHLD ','SHR  ','SLA  '
  1283.     DB    'SP   ','SPHL ','SRA  ','SRL  ','STA  '
  1284.     DB    'STAX ','STC  ','SUB  ','SUBTT','SUI  '
  1285.     DB    'TITLE'
  1286.     DB    'XALL ','XCHG ','XLIST','XOR  ','XRA  '
  1287.     DB    'XRI  ','XTHL '
  1288.     DB    'Z    ','Z80  '
  1289.     DB    0FFH        ; End of reserved word table
  1290. ;.....
  1291. ;
  1292. ;
  1293. ; Routine to open a disk file
  1294. ; input: DE=A(FCB)
  1295. ;
  1296. FOPEN:    MVI    C,OPEN        ; Open code
  1297.     CALL    BDOS        ; Issue open
  1298.     CPI    0FFH        ; Error?
  1299.     RNZ            ; No error
  1300.     LXI    D,EMSG0
  1301.     JMP    FERR1
  1302. ;.....
  1303. ;
  1304. ;
  1305. ; Routine to close output disk cross-reference file
  1306. ; input: DE=ADDR(FCB)
  1307. ;     HL=ADDR(BUFFER)
  1308. ;
  1309. DCLOSE:    PUSH    D        ; Save fcb address
  1310.     PUSH    H        ; Save buffer address
  1311.     LHLD    DSKCNT        ; Put number of char left...
  1312.     XCHG            ; In buffer into d,e
  1313.     LHLD    DCHAR        ; Point to next char in output buf
  1314.     MVI    A,1AH        ; Put a control z in accum
  1315. ;
  1316. DCLSE2:    MOV    M,A        ; Fill...
  1317.     INX    H        ; Rest of...
  1318.     DCR    E        ; Buffer...
  1319.     JNZ    DCLSE2        ; With...
  1320.     DCR    D        ; Control z's.
  1321.     JNZ    DCLSE2
  1322.     POP    H        ; Point to...
  1323. ;
  1324. DCLSE4:    XCHG            ; Output buffer
  1325.     LXI    H,128        ; Put 128 into h,l
  1326.     DAD    D        ; Add 128 to disk buf addr for next dma
  1327.     SHLD    BUFADR        ; Save it for next dma after this one
  1328.     MVI    C,SETDMA    ; Disk buffer for...
  1329.     CALL    BDOS        ; Last disk write
  1330.     POP    D        ; Do last...
  1331.     PUSH    D        ; (d,e contains ofcb)...
  1332.     MVI    C,WRITE        ; Disk...
  1333.     CALL    BDOS        ; Write
  1334. ;
  1335. ;
  1336. ; Check to see if last record has been written.  Do this by comparing
  1337. ; the address of the next available character to the address of the buf-
  1338. ; fer for the next disk write.    If the address of the next available
  1339. ; character is equal to or greater, close the file.
  1340. ;
  1341.     LHLD    DCHAR        ; Put high order address
  1342.     XCHG            ; Of last char+1...
  1343.     MOV    A,D        ; Into accum
  1344.     LHLD    BUFADR        ; Get addr of next disk buffer
  1345.     CMP    H        ; Compare to last char+1 in buffer
  1346.     JC    DCLSE5        ; If next addr is greater, close file
  1347.     JNZ    DCLSE4        ; If not equal, continue
  1348.     MOV    A,E        ; Put low order address of last char+1
  1349.     CMP    L        ; Into accum and test
  1350.     JNC    DCLSE4        ; If not less, do another write
  1351. ;
  1352. DCLSE5:    POP    D        ; Close the...(d,e contains ofcb)
  1353.     MVI    C,CLOSE        ; Output disk
  1354.     CALL    BDOS        ; Cross ref file
  1355.     CPI    0FFH        ; Close successfull?
  1356.     RNZ            ; Yes, return
  1357.     LXI    D,EMSG5        ; No, display error msg...
  1358.     JMP    FERR1        ; And quit
  1359. ;.....
  1360. ;
  1361. ;
  1362. ; Rroutine to read a byte
  1363. ; outputs: A=BYTE
  1364. ;
  1365. GETBT:    LXI    H,TBUF+(BUFSIZ*128) ; End of input buf addr
  1366.     XCHG            ; Buffer end addr. in de
  1367.     LHLD    INPTR        ; Current pointer in hl
  1368.     CALL    CPHL        ; Test for end of buffer
  1369.     CZ    GETREC        ; Yes, read disk records
  1370.     MOV    A,M        ; Get byte
  1371.     INX    H        ; Bump pointer
  1372.     SHLD    INPTR        ; Save pointer
  1373.     ORA    A        ; Clear carry
  1374.     JMP    SAVBT
  1375. ;.....
  1376. ;
  1377. ;
  1378. ; Save byte in line buffer
  1379. ;
  1380. SAVBT:    LHLD    LPNT        ; Get line pointer
  1381.     MOV    M,A        ; Save byte
  1382.     INX    H        ; Bump pointer
  1383.     SHLD    LPNT        ; Save pointer
  1384.     CALL    LWRUPR        ; Convert lower to upper case
  1385.     STA    CHAR        ; Save char in char
  1386.     RET
  1387. ;.....
  1388. ;
  1389. ;
  1390. GETREC:    LDA    CONSOLE        ; Console on ?
  1391.     ORA    A
  1392.     JNZ    GTREC1        ; Then he sees progress
  1393.     LHLD    LCNT        ; Line-count
  1394.     CALL    DECOT        ; Into ASCII
  1395.     LXI    D,DECERA    ; Erase area
  1396.     CALL    PSOUT
  1397.     LXI    D,DEC        ; ASCII linecount
  1398.     CALL    PSOUT        ; To show progress
  1399. ;
  1400. GTREC1:    MVI    B,BUFSIZ    ; Number of sectors to read
  1401.     LXI    H,TBUF        ; Get address of disk input buffer
  1402.     SHLD    IDADDR        ; Initialize current buffer address
  1403. ;
  1404. GETRC2:    LHLD    IDADDR        ; Get addr of input buffer
  1405.     XCHG            ; Put it in DE
  1406.     LXI    H,128        ; Add 128 to input buf
  1407.     DAD    D        ; Addr for read after next
  1408.     SHLD    IDADDR        ; Save it read after next
  1409.     PUSH    B        ; Save sector count
  1410.     PUSH    D        ; Save current ptr in case EOF occurrs
  1411.     MVI    C,SETDMA    ; Point to input buffer...
  1412.     CALL    BDOS
  1413.     MVI    C,READ        ; Read code
  1414.     LXI    D,TFCB        ; FCB address
  1415.     CALL    BDOS        ; Issue read
  1416.     POP    D        ; Restore current buf pointer
  1417.     POP    B        ; Restore sector count
  1418.     CPI    00        ; Error?
  1419.     JNZ    GETRC4        ; Yes
  1420.     DCR    B        ; Read all of the sectors?
  1421.     JNZ    GETRC2        ; No, continue reading
  1422.  
  1423. GETRC3:    LXI    H,TBUF        ; Reset buffer pointer
  1424.     SHLD    INPTR
  1425.     RET            ; Return to caller
  1426. ;...
  1427. ;
  1428. ;
  1429. GETRC4:    XCHG            ; Point to first char past buf
  1430.     MVI    M,26H        ; Put two...
  1431.     INX    H        ; Control z's
  1432.     MVI    M,26H        ; After last rec in file
  1433.     JMP    GETRC3        ; Go reset buffer pointer
  1434. ;.....
  1435. ;
  1436. ;
  1437. ; Converts lower to upper case
  1438. ; input: a=byte(upper/lower
  1439. ; outputs: a=byte upper
  1440. ;
  1441. LWRUPR:    CPI    'A'+20H        ; Is it upper case?
  1442.     CMC            ; Complement carry
  1443.     RNC            ; Yes, return with carry reset
  1444.     CPI    'Z'+21H        ; Over lower case 'z'?
  1445.     RNC            ; No, return no carry
  1446.     SUI    20H        ; Convert to upper case
  1447.     RET
  1448. ;.....
  1449. ;
  1450. ;
  1451. ;PSOUT prints string in D
  1452. ;
  1453. PSOUT:    MVI    C,PSTRING
  1454.     CALL    BDOS        ; Print String
  1455.     RET
  1456. ;.....
  1457. ;
  1458. ;
  1459. ; Routine to compare HL vs DE
  1460. ; output: HL=DE, zero=on
  1461. ;      HL<>DE, zero=off
  1462. ;
  1463. CPHL:    MOV    A,H
  1464.     CMP    D
  1465.     RNZ
  1466.     MOV    A,L
  1467.     CMP    E
  1468.     RET
  1469. ;.....
  1470. ;
  1471. ;
  1472. ; DATA
  1473. ;
  1474. EMSG1:    DB    CR,LF,'Label table error',CR,LF,'$'
  1475. EMSG2:    DB    CR,LF,'Failed to delete existing cross reference file'
  1476.     DB    CR,LF,'$'
  1477. EMSG3:    DB    CR,LF,'Failed to create cross reference file',CR,LF,'$'
  1478. EMSG4:    DB    CR,LF,'Disk write failed - Out of space?',CR,LF,'$'
  1479. EMSG5:    DB    CR,LF,'Close failed on disk cross reference file'
  1480.     DB    CR,LF,'$'
  1481. EMSG6:    DB    CR,LF,'++ERROR++ Not enough memory for label table'
  1482.     DB    CR,LF,'$'
  1483. EMSG7:    DB    CR,LF,'++ERROR++ Label table overflow?',CR,LF,'$'
  1484. DONEMSG:DB    CR,LF,'Cross-reference list is done',CR,LF,'$'
  1485. NOLABS:    DB    CR,LF,'No Labels in this Program'
  1486. CONCRLF:DB    CR,LF,'$'
  1487. OFCB:    DB    0        ; Disk output FCB, default drive
  1488.     DS    8        ; File name
  1489.     DB    'XRF'        ; File type
  1490.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  1491. DCHAR:    DW    DISKBUF        ; Pointer for disk buffer
  1492. BUFADR:    DS    2        ; Pointer to disk output buffer for dma
  1493. IDADDR:    DS    2        ; Pointer to disk input buffer for dma
  1494. DSKCNT:    DW    BUFSIZ*128    ; Number of char left in disk buffer
  1495. INPTR:    DW    TBUF+(BUFSIZ*128) ; Pointer to char in input buffer
  1496. DISKBUF:DS    BUFSIZ*128    ; Output disk buffer
  1497. TBUF:    DS    BUFSIZ*128    ; Disk input buffer
  1498. ;
  1499. ;
  1500. CHAR:    DS    1
  1501. COL:    DS    1
  1502. FROM:    DS    2        ; Move pointer
  1503. LAB:    DS    2        ; Current label table address
  1504. LABBT:    DS    2        ; Label table bottom address
  1505. LABTP:    DS    2        ; Label table top address
  1506. LCNT:    DS    2        ; Line counter
  1507. LIMIT:    DS    2        ; Limit pointer
  1508. LINLAB:    DS    1        ; 0 if first label on line
  1509. LPNT:    DS    2
  1510. REF:    DS    2        ; Current reference table address
  1511. REFBT:    DS    2        ; Reference table bottom address
  1512. REFTP:    DS    2        ; Reference table top address
  1513. TO:    DS    2        ; To pointer
  1514. DEC:    DS    5
  1515.     DB    '$'
  1516. ;
  1517. DECERA:    DB    BS,BS,BS,BS,BS,'$' ; Erase string for Line-Nr display
  1518. PBUF:    DS    132
  1519. LABCT:    DS    1
  1520. LABPT:    DS    2
  1521. SBUF:    DS    LABSIZ        ; Label buffer
  1522. NLINS:    DB    0        ; Buffers to print on line
  1523. LINES:    DB    0        ; Print line count
  1524. ;
  1525. CONSOLE:DB    0        ; Console output switch
  1526. DISKOUT:DB    0        ; Disk output switch
  1527. LISTFLG:DB    0        ; 0=no source listing
  1528. FTPRN:    DB    1        ; Prn file type
  1529. TEMP:    DS    2        ; Temp save word
  1530.     DS    64        ; Stack can have up to 32 addresses
  1531. STACK    EQU    $
  1532. ;.....
  1533. ;
  1534. ;
  1535. ; Label table area
  1536. ;
  1537. ; The label table must be the last byte before ONCE ONLY CODE - XREF
  1538. ; is NOT RESTARTABLE
  1539. ;
  1540. ;
  1541.     ORG    $
  1542. ;
  1543. ;
  1544. LABT:    DB    0FFH
  1545. ;
  1546. LOGO:    DB    CR,LF,'CP/M assembler cross-reference list v27'
  1547.     DB    CR,LF,'$'
  1548. ;
  1549. MSG1:    DB    '   disk cross-reference file exists, keep it (y/n) ? '
  1550.     DB    '$'
  1551. ;
  1552. MSG2:    DB    '   like to have a line-numbered .XRF listing (y/n) ? '
  1553.     DB    '$'
  1554. ;
  1555. EMSG0:    DB    CR,LF,'++ Can''t find that file ++',CR,LF,'$'
  1556. ;
  1557. ;
  1558. ;
  1559. HELP:    DB    CR,LF,'This program can be used to create a cross-'
  1560.     DB    'reference listing',CR,LF,'of CP/M assembler programs.'
  1561.     DB    '  The input can be either the assembler',CR,LF
  1562.     DB    'language source code (FILENAME.ASM) or the assembly '
  1563.     DB    'listing (FILENAME.PRN).',CR,LF
  1564.     DB    'The output can be printed on the CP/M list device, '
  1565.     DB    'displayed on',CR,LF
  1566.     DB    'the CRT, or written to disk (file type will be '
  1567.     DB    '.XRF).  It is',CR,LF,'invoked by keying:',CR,LF,LF
  1568.     DB    09H,'XREF FILENAME.ASM      (Output on list device)'
  1569.     DB    CR,LF,09H,'XREF FILENAME.PRN CRT  (Output on the '
  1570.     DB    'CRT)',CR,LF,09H,'XREF FILENAME.ASM D    (Output on '
  1571.     DB    'disk-default drive)',CR,LF,09H,'XREF FILENAME.PRN B:D'
  1572.     DB    '  (Output on disk-drive specified)'
  1573.     DB    CR,LF,CR,LF,CR,LF,CR,LF,CR,LF,'$'
  1574. ;.....
  1575. ;
  1576. ;
  1577. ; Setup or initialization
  1578. ;
  1579. SETUP:    LXI    D,LOGO        ; Get program logo messagew
  1580.     CALL    PSOUT        ; Display it
  1581.     LDA    TFCB+1        ; Get first character of file name
  1582.     CPI    ' '
  1583.     JZ    SETUP0
  1584.     CPI    '?'        ; Help function?
  1585.     JNZ    SETUP1        ; No, go check input file type
  1586. ;
  1587. SETUP0:    LXI    D,HELP        ; Display help message
  1588.     JMP    FERR1
  1589. ;...
  1590. ;
  1591. ;
  1592. SETUP1:    MVI    A,0
  1593.     STA    LISTFLG        ; No listing
  1594.     LDA    TFCB+9        ; Get first character of file type
  1595.     CPI    'P'        ; Is it type .PRN?
  1596.     JNZ    SETUP2        ; No, don't set switch
  1597.     LDA    TFCB+10        ; Get 2nd character of file type
  1598.     CPI    'R'
  1599.     JNZ    SETUP2
  1600.     LDA    TFCB+11        ; Get 3rd character of file type
  1601.     CPI    'N'
  1602.     JNZ    SETUP2
  1603.     XRA    A
  1604.     STA    FTPRN        ; Turn on .PRN file type
  1605. ;
  1606. SETUP2:    LDA    TFCB+17        ; Get 1st character of 2nd FCB
  1607.     CPI    'C'        ; Output to console?
  1608.     JNZ    SETUP3        ; No, don't turn on switch
  1609.     LDA    TFCB+18        ; Get 2nd character of 2nd FCB
  1610.     CPI    'R'        ; Output to CRT?
  1611.     JNZ    SETUP3        ; If not, exit
  1612.     MVI    A,0FFH        ; else turn on CRT
  1613.     STA    CONSOLE
  1614.     JMP    SETUP5        ; Go open input file
  1615. ;
  1616. SETUP3:    LDA    TFCB+17        ; Get 1st character of 2nd FCB
  1617.     CPI    'D'        ; Output to be written to disk?
  1618.     JNZ    SETUP5        ; If not, exit
  1619.     MVI    A,0FFH
  1620.     STA    DISKOUT        ; Turn on disk output switch
  1621.     LDA    TFCB+16        ; Get output file drive number
  1622.     STA    OFCB        ; Move to output FCB
  1623.     LXI    D,TFCB        ; Point to FCB
  1624.     CALL    FOPEN        ; Open disk input file
  1625.     LXI    D,TFCB+1    ; Point to input file name
  1626.     MVI    B,8        ; Length of file name
  1627.     LXI    H,OFCB+1    ; Point to output FCB file name
  1628.     CALL    MOVE        ; Move input file name to output FCB
  1629.     LXI    D,OFCB        ; Does output file already exist?
  1630.     MVI    C,OPEN
  1631.     CALL    BDOS
  1632.     CPI    0FFH        ; Open succeed?
  1633.     JZ    SETUP4        ; No, file does not exist
  1634.     LXI    D,OFCB        ; Close...
  1635.     MVI    C,CLOSE        ; The open...
  1636.     CALL    BDOS        ; File.
  1637. ;
  1638.     LXI    D,MSG1        ; Want to keep the old file?
  1639.     CALL    PSOUT
  1640.     MVI    C,CONIN        ; Get the answer
  1641.     CALL    BDOS
  1642.     ANI    05FH        ; Make upper case
  1643.     CPI    'Y'        ; Operator say yes, keep it?
  1644.     JZ    BOOT        ; If, yes, exit, done
  1645.     LXI    D,CONCRLF    ; Write CRLF to console
  1646.     CALL    PSOUT
  1647.     LXI    D,OFCB        ; Point to FCB to delete file
  1648.     MVI    C,DELETE    ; Delete the file
  1649.     CALL    BDOS
  1650.     CPI    0FFH        ; Delete succeed?
  1651.     LXI    D,EMSG2        ; If not, show error message
  1652.     JZ    FERR1
  1653. ;
  1654. SETUP4:    LXI    D,OFCB        ; Point to output FCB
  1655.     MVI    C,MAKE        ; Create new...
  1656.     CALL    BDOS        ; Cross reference file.
  1657.     CPI    0FFH        ; Create succeed?
  1658.     LXI    D,EMSG3        ; Get err msg in case of failure
  1659.     JZ    FERR1        ; Create failed, print msg & quit
  1660.     LXI    H,DISKBUF    ; Get addr of disk buffer
  1661.     SHLD    DCHAR        ; Init disk char pointer
  1662. ;
  1663. SETUP5:    LXI    D,TFCB        ; Point to fcb
  1664.     CALL    FOPEN        ; Open fcb
  1665.     LXI    D,MSG2        ; "Want Listing.."
  1666.     CALL    PSOUT
  1667.     MVI    C,CONIN
  1668.     CALL    BDOS        ; Get answer
  1669.     ANI    05FH        ; Make upper case
  1670.     CPI    'Y'
  1671.     JNZ    SETUP6        ; No listing
  1672.     MVI    A,0FFH
  1673.     STA    LISTFLG        ; Wants listing
  1674. ;
  1675. SETUP6:    LXI    D,CONCRLF    ; Write CRLF to console
  1676.     CALL    PSOUT
  1677.     LXI    H,PBUF
  1678.     SHLD    LPNT        ; Set print pointer
  1679.     LXI    H,00001        ; Set line counter...
  1680.     SHLD    LCNT        ; To one.
  1681.     LXI    H,LABT        ; Get address of label table
  1682.     SHLD    LAB
  1683.     SHLD    LABBT
  1684.     SHLD    LABTP        ; Set label table pointers
  1685.     LHLD    MEMSZ        ; Get available memory address
  1686.     DCX    H
  1687.     SHLD    REF
  1688.     SHLD    REFBT
  1689.     SHLD    REFTP        ; Set reference table pointers
  1690.     RET
  1691. ;.....
  1692. ;
  1693. ;
  1694.     END    START
  1695.