home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / cpm / utils / asmutl / xref250.lbr / XREF.AQM / XREF.ASM
Encoding:
Assembly Source File  |  1985-02-09  |  39.6 KB  |  1,385 lines

  1. ;    TITLE    XREF.ASM  VER 2.50    13-Jan-85 B.Eiben (EIBEN@MARKET)
  2. ;
  3. ;    for Assembly with LASM.COM
  4. ;
  5. ;    Cross Reference Program
  6. ;    for ASM and MAC files
  7. ;
  8. ;       jeff kravitz
  9. ;
  10. ;    modified by    john mahr
  11. ;            ray malitzke z80, m80
  12. ;
  13. ; This  program  generates  a  cross reference list for all Symbols in a .MAC
  14. ;.ASM assembler program.  Its  input  is  either  an  assembler  source  file
  15. ;(FN.typ)  or  an  assembler listing file (FN.PRN).  It will number the lines
  16. ;and generate a cross reference listing at  the  end  of  the  program.   The
  17. ;output  defaults  to  the  CPM  list  device,  but it can be directed to the
  18. ;console or to a disk file instead.  If the output  is  directed  to  a  disk
  19. ;file,  that file will be named FN.XRF.  The filename will be the filename of
  20. ;the input file.
  21. ;
  22. ; It is invoked by entering:
  23. ;        XREF FN.typ    (OUTPUT TO LIST DEVICE)
  24. ;        XREF FN.PRN CON    (OUTPUT TO CONSOLE)
  25. ;        XREF FN.ASM D    (OUTPUT TO DISK-DEFAULT
  26. ;                        DRIVE)
  27. ;        XREF FN.PRN B:D    (OUTPUT TO DISK-DRIVE
  28. ;                NUMBER SPECIFIED)
  29. ;
  30. ; To invoke help function enter:
  31. ;        XREF ?
  32. ;
  33. ;13/Jan/85.   Modified  help-message  and  introduced  XRF-only  option (most
  34. ;editors allow to get to line-numbers easily).  added marker  "<>"  for  line
  35. ;holding  symbol-definition.   Shortened  line-Nr.   display to be consistent
  36. ;with CREF output.  Moved code to  conserve  space  -  Warning  XREF  is  NOT
  37. ;restartable.   Moved comments from M80 source - not anymore needed - LASM is
  38. ;there and does the job.  XREF assumes,  that  a  symbol-definition  ONLY  is
  39. ;valid,  if the specific token is the FIRST token on the line.  This seems to
  40. ;work pretty well - with one exception  :  Since  XREF  works  from  unmarked
  41. ;source,  it  does  NOT  keep  track (can't) of IF -- ENDIF phrases.  So some
  42. ;symbols will appear to be multiply defined.  (B.Eiben)
  43. ;
  44. ;01/30/83  Added  operation  (and  pseudo)  codes  for Z80 and M80 assembler.
  45. ;  (RMG)
  46. ;
  47. ;03/15/82 This program would lock up if there was a comment line that started
  48. ;with  an  asterisk('*')  instead of a semicolon.  The program then processed
  49. ;the whole line as a valid line of assemble code.  This usually  resulted  in
  50. ;the  cross  reference  program  locking  up  if  there were a lot lines that
  51. ;started with an asterisk.  The program now treats an asterisk the same as  a
  52. ;semicolon.   This  was  done by changing the table CTAB1 so that the program
  53. ;branches to LSEMI when it finds an asterisk.  Also fixed bug  that  occurred
  54. ;when  the last record of a file was completely filled with data and thus had
  55. ;no control Z's(EOF characters) in it.  This was done by always  placing  two
  56. ;control Z's after the last record was read.  Finally fixed a bug that showed
  57. ;up only when a program had no symbols or labels in it.  Added a check for an
  58. ;empty symbol table before attempting to print the symbol table.  (JRM)
  59. ;
  60. ;03/06/82  Changed  the  code  so  that the size of output disk buffer can be
  61. ;specified at assembly time.  The size is set by  OUTSECT  which  equals  the
  62. ;number  of  disk sectors to be written when the buffer is full.  Implemented
  63. ;the same feature for disk input.  INSECT sets the number of disk records  to
  64. ;be  read  into  the input buffer.  On file type PRN the was a bug.  Whenever
  65. ;the first symbol on a line was preceded by a character,  the  line  was  not
  66. ;listed in the cross reference listing.  This was caused by skipping over the
  67. ;first  16  characters  in  the line on a CR(carriage return) instead of on a
  68. ;LF(line feed).  This bug has been fixed.   Added  help  function.   This  is
  69. ;invoked by entering XFER ?.  (JRM)
  70. ;
  71. ;03/03/82  Added  a 2k buffer for disk output writes.  This was done to speed
  72. ;up the execution of program when disk output was specified.  Fixed bug  when
  73. ;page  size  was  specified.   CPM assembler was not doing the conditional IF
  74. ;assembly correctly.  Changed the code to test if page size is in  effect  by
  75. ;testing  LPAGE  to  see  if  it  is zero.  Changed test to question to erase
  76. ;existing disk cross reference file to handle lower case  as  well  as  upper
  77. ;case.  (JRM)
  78. ;
  79. ;02/20/82  Changed  code so that the size of the symbol that is referenced in
  80. ;the cross reference listing can be  set  at  assembly  time.   The  original
  81. ;program only allowed for 5 char per symbol.  This did not allow for separate
  82. ;unique  symbols  where the uniqueness occurred after the first 5 characters.
  83. ;I tested this function for a length of 5, 8, and 10 characters  labels.   It
  84. ;should  work  for any length of symbol.  I also allowed the '$' character to
  85. ;be a valid character in a symbol.  The equ SYMSIZ was added  and  all  other
  86. ;values  and  variables  that  are  dependent  on  the size of the symbol are
  87. ;expressed using SYMSIZ.
  88. ;
  89. ;Added  a disk file output option.  The output disk file will the filename of
  90. ;the input file and always a file type of 'XRF'.  This option is  enabled  by
  91. ;specifying  a  'D'  as the second parameter when executing the program.  The
  92. ;user can optionally specify a different drive than the default drive for the
  93. ;cross reference disk output. (JRM)
  94. ;
  95. ;11/01/81  Changed the code so that the hex addresses and the hex translation
  96. ;of the instructions are not included in the cross reference listing for  PRN
  97. ;files from CPM assembler.  The listing can now be directed at execution time
  98. ;to the console or the list (LST:) device. (JRM)
  99. ;
  100. ;Modifications 4/5/79, 4/26/79, 5/3/79, 8/28/79 by SAN: Suppress initial page
  101. ;eject,  add  page  eject  at  completion Automatically convert lower case in
  102. ;source file to UPPER Abort execution if ^C typed,  but  ignore  other  typed
  103. ;chars Add ELSE, PAGE to reserved word table
  104. ;
  105. ;LPAGE     is Number of lines per output page
  106. ;
  107. ;NREFS is Number of symbol refs per table entry.  This value should be set to
  108. ;the  average number of references that a symbol will have in program.  It is
  109. ;used to build the symbol reference table entries.  Each entry will be  equal
  110. ;to  (NREFS  *  2)+2.   If  it  is  made unnecessarily large, then the symbol
  111. ;reference table will be very large with a lot of unused slots.   Example:  a
  112. ;program  with  300  symbols  will require a reference table that is at least
  113. ;12600 bytes if NREFS=20, whereas the same program will require  a  reference
  114. ;table  that  is  at  least  3600 bytes if NREFS=5.  Each symbol that exceeds
  115. ;NREFS references will require ((Total references/NREFS)rounded up) reference
  116. ;table entries.  Recommended values: 3-5.
  117. ;
  118. ;LREFS  is  Number  of  symbol  references to be printed per output line.  It
  119. ;should be a multiple of NREFS.  If it is not, then the first number that  is
  120. ;less  than  LREFS  and  is  a multiple of NREFS will be printed on the line.
  121. ;Example: if NREFS is 5 and LREFS is 13, then only 10 entries will be printed
  122. ;per line.  The total number of references that will fit on one line  without
  123. ;overflow  is  equal  to  the size of the line minus (SYMSIZ+2) divided by 5.
  124. ;Example: if the line size is 132 characters and SYMSIZ equals 8, then  Total
  125. ;num of ref/line can be INT((132-(8+2))/5) or INT(122/5) or 20.
  126. ;
  127. ;SYMSIZ  sets the Symbol size.  This is the symbol size that the program will
  128. ;use in the cross reference listing.  It should be large enough to make  each
  129. ;symbol  unique  in  cross reference listing.  If a symbol is larger than the
  130. ;value for SYMSIZ, then the  symbol  will  be  truncated  in  the  output(eg:
  131. ;LARGE$SYMBOL  would  be LARGE$SYM if SYMSIZ was set to 9.  Recommended value
  132. ;is 8.
  133. ;
  134. ;OUTSECT  sets  the  number of disk records that will be written to disk when
  135. ;the output disk buffer is full.  This  value  is  used  by  the  program  to
  136. ;calculate  the size of the output disk buffer.  Output buffer size = OUTSECT
  137. ;* 128.  Recommended value is from 8 to 32.  16 works well.
  138. ;
  139. ;INSECT  is  the number of disk records that will be read when the disk input
  140. ;buffer is empty.  It is used to calculate the  size  of  the  input  buffer.
  141. ;Input  buffer  size  =  INSECT  * 128.  Recommend value is from 8 to 32.  16
  142. ;works well.
  143. ;
  144. ;NOTE:  If OUTSECT and INSECT are made too large, there will not be be enough
  145. ;memory left to build the cross reference table for a large program.  Largest
  146. ;tested values so far(3/6/82) is 64 for OUTSECT and 64 for INSECT  on  a  64K
  147. ;system.  The file successfully cross referenced was MODEM74.PRN.  (JRM)
  148. ;
  149. ;    Equates which COULD be changed
  150. ;
  151. LPAGE    EQU    00        ; num lines per page if peject is true
  152. NREFS    EQU    03        ; number of references per ref tbl entry
  153. LREFS    EQU    21        ; references per output line
  154. SYMSIZ    EQU    08        ; number of symbol char
  155. OUTSECT    EQU    04        ; number of disk sectors written from buffer
  156. INSECT    EQU    08        ; number of disk sectors read into buffer
  157. LEADIN    EQU    '['        ; Left marker for definition ref in CREF
  158. TRAIL    EQU    ']'        ; Right marker for above reference
  159. ;
  160. ;    Equates NOT to be changed
  161. ;
  162. RSIZ    EQU    05        ; size of rtab table entry
  163. SSIZ    EQU    SYMSIZ+3    ; symbol table entry size
  164. REFSZ    EQU    2+(NREFS*2)    ; number of bytes in ref block
  165. ;
  166. CR    EQU    0DH        ; carriage return        2.5
  167. LF    EQU    0AH        ; line feed            2.5
  168. BS    EQU    08H        ; backspace
  169. EOF    EQU    1AH        ; eof code
  170. ;
  171. ;    operating system equates
  172. ;
  173. BOOT    EQU    0000H        ; reboot entry point
  174. CPM    EQU    0005H        ; cpm entry point
  175. ;
  176. MEMSZ    EQU    0006H        ; end of memory pointer
  177. TFCB    EQU    005CH        ; trans. fcb
  178. ;
  179. CONIN    EQU    01        ; console input function code
  180. PSTRING    EQU    09        ; print string function code
  181. CSTAT    EQU    11        ; console status
  182. OPEN    EQU    15        ; open function code
  183. CLOSE    EQU    16        ; close file function code
  184. DELETE    EQU    19        ; delete file function code
  185. READ    EQU    20        ; read disk function code
  186. WRITE    EQU    21        ; write disk function code
  187. MAKE    EQU    22        ; make file function code
  188. SETDMA    EQU    26        ; set dma function code
  189. ;
  190. ;       main loop
  191. ;
  192. ;    ASEG
  193.     ORG    100H        ; origin address
  194. XREF:    LXI    SP,STACK    ; set stack pointer
  195.     CALL    SETUP        ; initialize
  196. MAIN:    CALL    GETBT        ; get a byte from source file
  197.     CALL    SAVBT        ; save byte in print buffer
  198. MAIN2:    CALL    CKNUM        ; test for numeric
  199.     JNC    LNUM        ; yes, found a number, process
  200.     CALL    CKALP        ; test for alphabetic
  201.     JNC    LALPH        ; yes, process
  202.     LXI    H,CTAB1        ; point to character table
  203.     CALL    LOOK        ; look up char in char table
  204.     JC    MAIN        ; not found, ignore        2.5
  205.     PCHL            ; execute routine
  206. ;
  207. ;        done
  208. ;
  209. ;      final symbol table print
  210. ;
  211. DONE:    CALL    EJECT        ; issue page eject
  212.     MVI    A,0FFH        ;
  213.     STA    LISTFLG        ; cref-list on always
  214.     LHLD    SYMBT        ; get symbol table bottom
  215.     MVI    A,0FFH        ; check to see if there were...
  216.     CMP    M        ; any symbols in the program
  217.     JZ    DLP4        ; no, don't print symbol table
  218.     SHLD    SYM        ; set symbol pointer
  219.     LHLD    SYMTP        ; get symbol table top
  220.     MVI    M,0FFH        ; end off symbol table
  221. DLP1:    LHLD    SYM        ; get symbol table pointer
  222.     CALL    PSYM        ; print symbol
  223.     LHLD    SYM
  224.     LXI    D,SYMSIZ+1    ; offset to ref link
  225.     DAD    D
  226.     MOV    E,M
  227.     INX    H
  228.     MOV    D,M        ; get ref block addr
  229.     XCHG            ; into hl
  230.     SHLD    REF
  231.     CALL    PREFS        ; print references
  232.     LHLD    SYM        ; get symbol table pointer
  233.     LXI    D,SSIZ        ; size of sym table entry
  234.     DAD    D
  235.     SHLD    SYM
  236.     MOV    A,M        ; get byte
  237.     CPI    0FFH        ; end of table?
  238.     JNZ    DLP1        ; loop
  239.  
  240. DLP2:    CALL    EJECT        ; page eject
  241.     LDA    DISKOUT        ; get disk output switch
  242.     ORA    A        ; disk output being used?
  243.     JZ    DLP3        ; no, issue end msg & return to cpm
  244.     LXI    H,DISKBUF    ; get output disk buffer
  245.     LXI    D,OFCB        ; and out fcb
  246.     CALL    DCLOSE        ; and close output disk file
  247.  
  248. DLP3:    LXI    D,TFCB        ; close the...
  249.     MVI    C,CLOSE        ; input...
  250.     CALL    CPM        ; file.
  251.     LXI    D,DONEMSG    ; tell operator we're done
  252.     CALL    PSOUT        ;
  253.     JMP    BOOT        ; and return to cp/m
  254.  
  255. DLP4:    LXI    H,NOSYMS    ; get no symbol message
  256.     MVI    B,28        ; number of char in msg
  257. DLP5:    MOV    E,M        ; print the...
  258.     CALL    PBYT        ; message
  259.     INX    H
  260.     DCR    B
  261.     JNZ    DLP5
  262.     JMP    DLP2        ; go close files
  263. ;
  264. ;     symbol print routine
  265. ;
  266. PSYM:    MVI    B,SYMSIZ    ; symbol size
  267. PSYM2:    MOV    E,M        ; get byte
  268.     CALL    PBYT        ; print byte
  269.     INX    H
  270.     DCR    B
  271.     JNZ    PSYM2
  272.     MVI    E,' '
  273.     CALL    PBYT        ; print 2 spaces
  274.     CALL    PBYT
  275.     RET
  276. ;
  277. ;     reference print routine
  278. ;
  279. PREFS:    MVI    A,LREFS/NREFS    ; number of blocks to print on one line
  280.     STA    NLINS        ; to nlins
  281. PREF0:    LHLD    REF        ; get ref block addr
  282.     INX    H
  283.     INX    H        ; bump to first ref number
  284.     SHLD    TEMP        ; save ref num addr
  285.     MVI    A,(REFSZ-2)/2    ; number of ref slots
  286.     STA    SYMCT        ; save in symct
  287. PREF:    LHLD    TEMP        ; get ref slot addr
  288.     MOV    E,M
  289.     INX    H
  290.     MOV    D,M        ; get ref
  291.     LXI    H,0000        ; zero?
  292.     CALL    CPHL
  293.     JZ    CRLF        ; yes, done
  294.     MOV    A,D        ;                    2.5
  295.     ANI    080H        ; High bit set ?            2.5
  296.     JZ    PREF1        ; nope                    2.5
  297.     MOV    A,D        ;                    2.5
  298.     ANI    07FH        ;                    2.5
  299.     MOV    D,A        ; clear it                2.5
  300.     PUSH    D        ;                    2.5
  301.     MVI    E,' '        ;                    2.5
  302.     CALL    PBYT        ;                    2.5
  303.     MVI    A,LEADIN    ;                    2.5
  304.     STA    DECMRK        ; modify lead-in marker            2.5
  305.     MVI    A,TRAIL        ;                    2.5
  306.     STA    DECEND        ; and trailing marker            2.5
  307.     POP    D        ;                    2.5
  308. PREF1:    XCHG            ; get num in hl
  309.     CALL    DECOT        ; convert
  310.     CALL    DECPNT        ; print it                2.5
  311.     MVI    A,' '        ;                    2.5
  312.     STA    DECMRK        ; restore lead-in space            2.5
  313.     MVI    A,'$'        ;                    2.5
  314.     STA    DECEND        ; and trailing marker            2.5
  315.     LHLD    TEMP        ; get ref slot addr
  316.     INX    H
  317.     INX    H        ; bump to next slot
  318.     SHLD    TEMP
  319.     LDA    SYMCT        ; get count
  320.     DCR    A        ; decrement
  321.     STA    SYMCT
  322.     JNZ    PREF
  323.     LHLD    REF        ; get ref block address
  324.     MOV    E,M
  325.     INX    H
  326.     MOV    D,M        ; get link to next block
  327.     LXI    H,0000
  328.     CALL    CPHL        ; any more blocks?
  329.     JZ    CRLF        ; no, exit
  330.     XCHG            ; yes, set next block pointer in ref
  331.     SHLD    REF
  332.     LDA    NLINS
  333.     DCR    A        ; decrement lines count
  334.     STA    NLINS
  335.     JNZ    PREF0        ; and print more on same line
  336.     CALL    CRLF        ; print cr,lf
  337.     MVI    B,SYMSIZ+2    ; indent continuation line...
  338. PREF3:    MVI    E,' '        ; with spaces
  339.     CALL    PBYT        ; print spaces
  340.     DCR    B
  341.     JNZ    PREF3        ; print 6 spaces
  342.     JMP    PREFS
  343. ;
  344. ;   character parsing routines
  345. ;
  346. LALPH:    LXI    H,SBUF        ; point to symbol buffer
  347.     MVI    C,SYMSIZ
  348.     MVI    A,' '        ; fill symbol...
  349. LALX:    MOV    M,A        ; with...
  350.     INX    H        ; blanks
  351.     DCR    C
  352.     JNZ    LALX        ; clear symbol buffer
  353.     LXI    H,SBUF
  354.     SHLD    SYMPT
  355.     MVI    A,00
  356.     STA    SYMCT        ; reset symbol pointer+count
  357.     LDA    CHAR        ; get character again
  358.     CALL    GTSYM        ; collect identifier
  359. LALC:    CALL    GETBT        ; get a byte from source file
  360.     CALL    SAVBT        ; save byte in print buffer
  361.     CALL    CKNUM        ; test for number
  362.     JNC    LAL3        ; yes, continue
  363.     CALL    CKALP        ; test for alphabetic
  364.     JNC    LAL3        ; yes, continue
  365.     CALL    CRES        ; test for reserved word
  366.     JC    LAL1        ; no, continue
  367. LAL0:    CALL    LINUP        ; Up LINSYM                2.5
  368.     LDA    CHAR        ; get character that ended ID
  369.     JMP    MAIN2        ; continue scan
  370. LAL1:    CALL    FIND        ; see if defined
  371.     JC    LAL2        ; no, continue
  372.     CALL    ADDRF        ; yes, add reference
  373.     JMP    LAL0        ; done
  374. LAL2:    CALL    ENSYM        ; enter symbol definition
  375.     CALL    ADDRF        ; add reference
  376.     JMP    LAL0        ; continue
  377. LAL3:    CALL    GTSYM        ; collect identifier
  378.     JMP    LALC        ; continue
  379. ;
  380. LNUM:    CALL    GETBT        ; get byte
  381.     CALL    SAVBT        ; save byte in printer buffer
  382.     CALL    CKNUM        ; test for numeric
  383.     JNC    LNUM        ; yes, continue
  384.     CALL    CKALP        ; test for alphabetic
  385.     JNC    LNUM        ; yes, continue
  386.     JMP    MAIN2        ; continue with main scan
  387. ;
  388. LQUOT:    CALL    GETBT        ; get a byte
  389.     CALL    SAVBT        ; save byte in printer buffer
  390.     CPI    ''''        ; see if string quote
  391.     JNZ    LQUOT        ; no, keep looping
  392.     CALL    GETBT        ; get next byte
  393.     CALL    SAVBT        ; save byte
  394.     CPI    ''''        ; test for doubles
  395.     JZ    LQUOT        ; yes, start scan again
  396.     JMP    MAIN2        ; no, continue in main scan
  397. ;
  398. LSEMI:    CALL    GETBT        ; get a byte
  399.     CALL    SAVBT        ; save byte
  400.     CPI    CR        ; wait for cr
  401.     JNZ    LSEMI        ; continue
  402.     JMP    MAIN2        ; enter main loop
  403. ;
  404. LCR:    CALL    PLINE        ; print line
  405.     LHLD    LCNT        ; get line number
  406.     INX    H        ; bump line number
  407.     SHLD    LCNT        ; store
  408.     JMP    MAIN
  409. ;
  410. LLF:    PUSH    PSW        ; save char
  411.     LDA    FTPRN        ; is it file...
  412.     ORA    A        ; type prn?
  413.     JZ    LLF2        ; yes, skip 1rst 16 char
  414.     POP    PSW        ; restore char
  415. LLF1A:    PUSH    PSW        ;                    2.5
  416.     MVI    A,0        ; reset LINSYM                2.5
  417.     STA    LINSYM        ;                    2.5
  418.     POP    PSW        ;                    2.5
  419.     JMP    MAIN
  420. ;
  421. LLF2:    POP    PSW        ; restore character
  422.     MVI    B,16        ; # of char to skip over
  423. ;
  424. LLF3:    CALL    GETBT        ; get next byte
  425.     CALL    SAVBT        ; put in print buf
  426.     CPI    CR        ; carriage return?
  427.     JZ    LCR        ; yes, get next line
  428.     DCR    B        ; skipped all char?
  429.     JNZ    LLF3        ; no, continue skipping
  430.     JMP    LLF1A        ; continue                2.5
  431. ;
  432. LIGN:    JMP    MAIN        ; re-enter main loop
  433. LSPC    EQU    LIGN
  434. LTAB    EQU    LIGN
  435. LDOL    EQU    LIGN
  436. LDEL    EQU    LIGN
  437. ;
  438. ;
  439. ;       subroutines
  440. ;
  441. ;    check for reserved word
  442. ;
  443. CRES:    LXI    H,RTAB        ; point to reserved word table
  444.     SHLD    TEMP        ; save in temp word
  445. CRES1:    LHLD    TEMP        ; get table pointer
  446.     LXI    D,SBUF        ; point to symbol
  447.     MVI    B,5        ; symbol size
  448. CRES2:    LDAX    D        ; get symbol byte
  449.     CMP    M        ; compare against table entry
  450.     RC            ; less, not in table
  451.     JNZ    CRES3        ; greater, get next table entry
  452.     INX    D        ; bump pointers
  453.     INX    H
  454.     DCR    B        ; decrement byte count
  455.     JNZ    CRES2        ; keep testing
  456.     JMP    CRES4        ; found
  457. CRES3:    LHLD    TEMP        ; get table pointer
  458.     LXI    D,RSIZ        ; size of entry
  459.     DAD    D        ; bump pointer
  460.     SHLD    TEMP        ; store new pointer
  461.     MOV    A,M        ; get table byte
  462.     CPI    0FFH        ; end of table?
  463.     JNZ    CRES1        ; no, loop
  464.     STC            ; set carry (not in table)
  465.     RET
  466. CRES4:    ORA    A        ; reset carry
  467.     RET
  468. ;
  469. ;     find symbol in table
  470. ;
  471. FIND:    LHLD    SYMBT        ; get begin of sym table
  472.     SHLD    SYM        ; set temp pointer
  473. FIND1:    LHLD    SYM        ; get temp pointer
  474.     LXI    D,SBUF        ; point to current symbol
  475.     MVI    B,SYMSIZ    ; symbol size
  476. FIND2:    LDAX    D        ; get byte from sbuf
  477.     CMP    M        ; compare to sym table byte
  478.     RC            ; greater, not in table
  479.     JNZ    FIND3        ; less, get next table entry
  480.     INX    D        ; bump pointer
  481.     INX    H        ; bump pointer
  482.     DCR    B        ; decrement byte count
  483.     JNZ    FIND2        ; loop
  484.     RET            ; true zero, found
  485. FIND3:    LHLD    SYM        ; get current pointer
  486.     LXI    D,SSIZ        ; symbol table entry size
  487.     DAD    D        ; bump pointer
  488.     XCHG            ; into de
  489.     LHLD    SYMTP        ; get top of symbol table
  490.     CALL    CPHL        ; test for end of table
  491.     JZ    FIND4        ; yes, done
  492.     JC    FERR        ; table overflow, error
  493.     XCHG            ; current pointer into hl
  494.     SHLD    SYM        ; set current pointer
  495.     JMP    FIND1        ; loop
  496. FIND4:    STC            ; set carry for not found
  497.     LHLD    SYMTP        ; get current top
  498.     SHLD    SYM        ; set current pointer
  499.     RET
  500. ;
  501. FERR:    LXI    D,EMSG1        ; symbol table err msg
  502. FERR1:    CALL    PSOUT        ;
  503.     JMP    BOOT        ; exit
  504. ;
  505. FERR2:    LXI    D,EMSG6        ; no room for symbol table
  506.     JMP    FERR1
  507. ;
  508. ;   add reference to ref table
  509. ;
  510. ADDRF:    LHLD    SYM        ; get symbol pointer
  511.     LXI    D,SYMSIZ+1    ; offset past symbol&flags
  512.     DAD    D
  513.     MOV    E,M
  514.     INX    H
  515.     MOV    D,M        ; get reference pointer
  516.     LXI    H,0000
  517.     CALL    CPHL        ; test for zero ref ptr
  518.     JZ    BLDRF        ; yes, build reference entry
  519. LINK1:    XCHG            ; ref ptr in hl
  520.     MOV    E,M        ; get ref link
  521.     INX    H
  522.     MOV    D,M        ; into de
  523.     DCX    H        ; reposition hl
  524.     PUSH    H        ; save ref ptr
  525.     LXI    H,0000
  526.     CALL    CPHL        ; if link is zero
  527.     POP    H
  528.     JNZ    LINK1        ; non zero, get next link
  529.     SHLD    REF        ; save ref pointer
  530.     INX    H
  531.     INX    H        ; skip to first ref number
  532.     MVI    B,(REFSZ-2)/2    ; number of ref numbers/entry
  533. LINK3:    MOV    E,M        ; get ref number
  534.     INX    H
  535.     MOV    D,M
  536.     DCX    H        ; reposition
  537.     PUSH    H        ; save ref num addr
  538.     LXI    H,0000
  539.     CALL    CPHL        ; see if ref num is zero
  540.     POP    H
  541.     JZ    ENREF        ; yes, enter reference
  542.     INX    H
  543.     INX    H        ; skip to next ref num
  544.     DCR    B        ; decrement count
  545.     JNZ    LINK3        ; try again at next slot
  546.     CALL    ADBLK        ; add new ref block
  547.     LHLD    REF        ; get ref pointer
  548.     INX    H
  549.     INX    H        ; skip to first ref slot
  550. ENREF:    PUSH    H        ; save ref slot addr
  551.     LHLD    LCNT        ; get line number
  552.     XCHG            ; into de
  553.     POP    H        ; get ref slot addr
  554.     LDA    LINSYM        ; first SYMBOL on line ?        2.5
  555.     ORA    A        ;                    2.5
  556.     JNZ    ENREF1        ; nope                    2.5
  557.     CALL    LINUP        ; up LINSYM                2.5
  558.     MOV    A,D        ;                    2.5
  559.     ADI    080H        ;                    2.5
  560.     MOV    D,A        ; set high bit                2.5
  561. ENREF1:    MOV    M,E
  562.     INX    H
  563.     MOV    M,D        ; store line ref
  564.     RET            ; done
  565. ;
  566. ;     build ref table block
  567. ;
  568. BLDRF:    LHLD    SYM        ; get symbol pointer
  569.     LXI    D,SYMSIZ+1    ; offset to ref pointer
  570.     DAD    D
  571.     SHLD    REF        ; set temp ref pointer to here
  572.     CALL    ADBLK        ; add block
  573.     LHLD    REF        ; get real ref pointer
  574.     INX    H
  575.     INX    H        ; position to first ref slot
  576.     JMP    ENREF        ; add reference
  577. ADBLK:    LHLD    REFBT        ; get ref bottom
  578.     LXI    D,REFSZ        ; subtract ref size
  579.     MOV    A,L
  580.     SUB    E
  581.     MOV    L,A
  582.     MOV    A,H
  583.     SBB    D
  584.     MOV    H,A
  585.     SHLD    TEMP        ; save new ref bottom
  586.     XCHG            ; into de also
  587.     LHLD    SYMTP        ; get symbol top
  588.     CALL    CPHL        ; check for bump
  589.     JZ    FERR2        ; yes, no room
  590.     JNC    FERR2        ; no room
  591.     LHLD    TEMP        ; get ref bottom
  592.     XCHG            ; into de
  593.     LHLD    REF        ; get ref pointer
  594.     MOV    M,E        ; set link
  595.     INX    H
  596.     MOV    M,D        ; to new ref block
  597.     LHLD    TEMP        ; get new ref block addr
  598.     SHLD    REF        ; store in ref
  599.     MVI    B,REFSZ        ; size of ref block
  600.     MVI    A,00
  601. ADB2:    MOV    M,A        ; zero the ref block
  602.     INX    H
  603.     DCR    B
  604.     JNZ    ADB2
  605.     LHLD    TEMP        ; get new ref bottom
  606.     SHLD    REFBT        ; set refbt
  607.     RET
  608. ;
  609. ;     enter symbol in sym table
  610. ;
  611. ENSYM:    LHLD    SYM        ; get symbol pointer
  612.     XCHG            ; into de
  613.     LHLD    SYMTP        ; get symbol table top
  614.     CALL    CPHL        ; check for end of table
  615.     JZ    NWSYM        ; yes, add symbol at end
  616.     LXI    D,SSIZ        ; symbol table entry size
  617.     DAD    D        ; calculate new end of table
  618.     XCHG            ; into de
  619.     LHLD    REFBT        ; reference table bottom
  620.     CALL    CPHL        ; test for table overflow
  621.     LXI    D,EMSG7        ; addr of err msg in of overflow
  622.     JZ    FERR1        ; full, error
  623.     JC    FERR1        ; yes, error
  624.     LHLD    SYMTP        ; get table top
  625.     LXI    D,SSIZ-1    ; bump to end of entry
  626.     DAD    D
  627.     SHLD    TO        ; store in to address
  628.     LXI    D,SSIZ
  629.     MOV    A,L
  630.     SUB    E
  631.     MOV    L,A
  632.     MOV    A,H
  633.     SBB    D
  634.     MOV    H,A        ; subtract size of one entry
  635.     SHLD    FROM        ; store as from address
  636.     LHLD    SYM        ; get current pointer
  637.     SHLD    LIMIT        ; store as limit address
  638.     CALL    MVUP        ; move table up in memory
  639. NWSYM:    LHLD    SYM        ; get current pointer
  640.     LXI    D,SBUF        ; point to symbol
  641.     MVI    B,SYMSIZ    ; size of symbol
  642.     CALL    MOVE        ; copy symbol to table
  643.     MVI    A,0
  644.     MOV    M,A
  645.     INX    H
  646.     MOV    M,A
  647.     INX    H
  648.     MOV    M,A        ; set pointers to 0000
  649.     LHLD    SYMTP        ; get symbol table top
  650.     LXI    D,SSIZ        ; get symbol entry size
  651.     DAD    D        ; bump
  652.     SHLD    SYMTP        ; store ew top
  653.     RET
  654. ;
  655. ;    move symbol table up
  656. ;
  657. MVUP:    LHLD    TO        ; get to pointer
  658.     MOV    B,H
  659.     MOV    C,L        ; into bc
  660.     LHLD    FROM        ; get from pointer
  661.     XCHG            ; into de
  662.     LHLD    LIMIT        ; get limit address
  663. MVUP2:    LDAX    D        ; get from byte
  664.     STAX    B        ; store at to address
  665.     CALL    CPHL        ; compare from to limit
  666.     RZ            ; exit if done
  667.     DCX    B        ; decrement to
  668.     DCX    D        ; decrment from
  669.     JMP    MVUP2        ; loop
  670. ;
  671. ;  general purpose move routine
  672. ;
  673. MOVE:    LDAX    D        ; get byte
  674.     MOV    M,A        ; store byte
  675.     INX    D
  676.     INX    H        ; bump pointers
  677.     DCR    B        ; decrement count
  678.     JNZ    MOVE        ; loop
  679.     RET
  680. ;
  681. ;    binary to decimal conversion
  682. ;
  683. DECOT:    LXI    D,DEC
  684.     XCHG
  685.     LXI    B,10000
  686.     CALL    DIG
  687.     LXI    B,1000
  688.     CALL    DIG
  689.     LXI    B,100
  690.     CALL    DIG
  691.     LXI    B,10
  692.     CALL    DIG
  693.     LXI    B,1
  694.     CALL    DIG
  695.     RET
  696. ;
  697. DIG:    MVI    M,'0'
  698. DI0:    MOV    A,E
  699.     SUB    C
  700.     MOV    E,A
  701.     MOV    A,D
  702.     SBB    B
  703.     MOV    D,A
  704.     JM    DI2
  705.     INR    M
  706.     JMP    DI0
  707. DI2:    MOV    A,E
  708.     ADD    C
  709.     MOV    E,A
  710.     MOV    A,D
  711.     ADC    B
  712.     MOV    D,A
  713.     INX    H
  714.     RET
  715. ;
  716. ;    Print number string in DEC
  717. ;
  718. DECPNT:    LXI    H,DEC        ; point to dec string
  719.     LDA    DECMRK        ;                2.5
  720.     MOV    M,A        ; set lead-in marker        2.5
  721. DCPNT1:    MOV    E,M        ; get string byte
  722.     MOV    A,E        ;
  723.     CPI    '$'        ; done?
  724.     RZ            ; yes
  725.     CALL    PBYT        ; print byte
  726.     INX    H        ; bump pointer
  727.     JMP    DCPNT1        ;
  728. ;
  729. ;    Up LINSYM after symbol found
  730. LINUP:    PUSH    PSW        ;                2.5
  731.     LDA    LINSYM        ;                2.5
  732.     INR    A        ;                2.5
  733.     STA    LINSYM        ; found first separator        2.5
  734.     POP    PSW        ;                2.5
  735.     RET            ;                2.5
  736. ;
  737. ;    test for alphabetic char.
  738. ;
  739. CKALP:    CPI    '$'        ; treat '$' like a char
  740.     RZ
  741.     CPI    'A'        ; ascii 'a'
  742.     RC            ; no, exit
  743.     CPI    'Z'+1
  744.     CMC
  745.     RET
  746. ;
  747. ;    test for numeric char
  748. ;
  749. CKNUM:    CPI    '0'
  750.     RC
  751.     CPI    '9'+1
  752.     CMC
  753.     RET
  754. ;
  755. ;  look up char in parse table
  756. ;
  757. LOOK:    LXI    D,0003        ; table entry size
  758.     MOV    B,A        ; argument byte in b
  759. LOOK2:    MOV    A,M        ; get table byte
  760.     CPI    0FFH        ; end of table?
  761.     JZ    LOOKN        ; yes, not found
  762.     CMP    B        ; compare
  763.     JZ    LOOKY        ; found
  764.     DAD    D        ; bump pointer
  765.     JMP    LOOK2        ; loop
  766. LOOKN:    STC            ; carry = not found
  767.     RET
  768. ;
  769. LOOKY:    INX    H        ; skip to table byte
  770.     MOV    E,M
  771.     INX    H
  772.     MOV    D,M        ; table entry in de
  773.     XCHG            ; into hl
  774.     RET
  775. ;
  776. ;    save byte in line buffer
  777. ;
  778. SAVBT:    LHLD    LPNT        ; get line pointer
  779.     MOV    M,A        ; save byte
  780.     INX    H        ; bump pointer
  781.     SHLD    LPNT        ; save pointer
  782.     CALL    LWRUPR        ; convert lower to upper case
  783.     STA    CHAR        ; save char in char
  784.     RET
  785. ;
  786. ;  print source line with number
  787. ;
  788. PLINE:
  789.     LHLD    LCNT        ; get line number
  790.     CALL    DECOT        ; convert to decimal
  791.     CALL    DECPNT        ; print it                2.5
  792.     MVI    E,':'
  793.     CALL    PBYT        ; print ':'
  794.     MVI    E,' '
  795.     CALL    PBYT        ; print ' '
  796.     CALL    PBYT        ; print space
  797.     LXI    H,PBUF        ; point to print buffer
  798.     MVI    A,00
  799.     STA    COL        ; set column count
  800. PL41:    MOV    E,M        ; get byte
  801.     MOV    A,E
  802.     CPI    CR        ; done?
  803.     JZ    PL5
  804.     CPI    LF        ; lf?
  805.     JZ    PL4A        ; yes, ignore
  806.     CPI    09H        ; tab?
  807.     JNZ    PL42        ; no, continue
  808.     PUSH    H        ; save hl
  809. PL43:    MVI    E,' '
  810.     CALL    PBYT        ; print space
  811.     LXI    H,COL
  812.     INR    M
  813.     MOV    A,M
  814.     ANI    07H        ; modulo 8
  815.     JNZ    PL43
  816.     POP    H
  817.     JMP    PL4A
  818. PL42:    LDA    COL
  819.     INR    A
  820.     STA    COL
  821.     CALL    PBYT        ; print byte
  822. PL4A:    INX    H
  823.     JMP    PL41
  824. PL5:    CALL    CRLF        ; print cr,lf
  825.     LXI    H,PBUF
  826.     SHLD    LPNT        ; reset line pointer
  827.     RET
  828. ;
  829. ;      collect symbol in sym buf
  830. ;
  831. GTSYM:    MOV    B,A        ; save char
  832.     LDA    SYMCT        ; get symbol count
  833.     CPI    SYMSIZ        ; max?
  834.     RNC            ; yes, done
  835.     INR    A
  836.     STA    SYMCT
  837.     LHLD    SYMPT
  838.     MOV    M,B
  839.     INX    H        ; bump symbol pointer
  840.     SHLD    SYMPT
  841.     RET
  842. ;
  843. ;    print a single byte
  844. ;
  845. PBYT:    PUSH    B
  846.     PUSH    D
  847.     PUSH    H
  848.     PUSH    PSW
  849.     LDA    LISTFLG        ; listing on ?            2.5
  850.     ORA    A        ;                2.5
  851.     JZ    PBYT3        ; no listing            2.5
  852.     LDA    DISKOUT        ; disk output...
  853.     ORA    A        ; in effect?
  854.     JNZ    DBYT        ; yes, go write to disk
  855.     MVI    C,05
  856.     LDA    CONSOLE        ; get console out switch
  857.     ORA    A        ; console output?
  858.     JZ    PBYT2        ; no, print output
  859.     MVI    C,2        ; console output
  860. ;
  861. PBYT2:    CALL    CPM
  862. ;
  863. PBYT3:    MVI    C,CSTAT        ; check console status
  864.     CALL    CPM
  865.     ORA    A        ; if zero, ok
  866.     JZ    PBYTX        ; exit
  867.     MVI    C,CONIN
  868.     CALL    CPM        ; read console char
  869.     CPI    3
  870.     JZ    BOOT        ; abort if ^c, otherwise ignore
  871. PBYTX:    POP    PSW
  872.     POP    H
  873.     POP    D
  874.     POP    B
  875.     RET
  876. ;
  877. ;    put output character into disk buffer.
  878. ;
  879. DBYT:    MOV    A,E        ; save char to be put in buffer
  880.     LHLD    DSKCNT        ; get num of char left in buf
  881.     XCHG            ; put num in d,e
  882.     LHLD    DCHAR        ; point to next char in buf
  883.     MOV    M,A        ; put char in disk buf
  884.     DCR    E        ; at end of buf?
  885.     JNZ    DBYT1        ; no, don't write buffer
  886.     DCR    D        ; at end of buf?
  887.     JZ    PUTREC        ; yes, go write buffer
  888. ;
  889. DBYT1:    INX    H        ; point to next char in buf
  890.     SHLD    DCHAR        ; save next pos
  891.     XCHG            ; put num of char left in h,l
  892.     SHLD    DSKCNT        ; save num of remaining char
  893.     JMP    PBYT3        ; go check console status
  894. ;
  895. ;    write out disk buffer to disk
  896. ;
  897. PUTREC:    LXI    H,DISKBUF    ; address of disk buffer
  898.     SHLD    BUFADR        ; save it for later dma's
  899.     MVI    B,OUTSECT    ; number of disk sectors to write
  900. ;
  901. PUTRC2:    PUSH    B        ; save sector count
  902.     LHLD    BUFADR        ; get disk buffer address
  903.     XCHG            ; put it in d,e for dma
  904.     LXI    H,80H        ; put 128 h,l
  905.     DAD    D        ; add 128 to disk buf adr for next dma
  906.     SHLD    BUFADR        ; save it for next dma
  907.     MVI    C,SETDMA    ; point dma to...
  908.     CALL    CPM        ; correct buffer
  909.     LXI    D,OFCB        ; get output disk fcb
  910.     MVI    C,WRITE        ; write sector...
  911.     CALL    CPM        ; to disk
  912.     ORA    A        ; was write successfull?
  913.     POP    B        ; restore num of sectors left
  914.     LXI    D,EMSG4        ; get err msg in case write failed
  915.     JNZ    FERR1        ; disk write failed, display err msg, quit
  916.     DCR    B        ; written 16 sectors yet?
  917.     JNZ    PUTRC2        ; no, continue writing disk sectors
  918.     LXI    H,OUTSECT*128    ; put disk buffer size into h,l
  919.     SHLD    DSKCNT        ; set num of char left in buf to buffer size
  920.     LXI    H,DISKBUF    ; point to front...
  921.     SHLD    DCHAR        ; of disk buffer
  922.     JMP    PBYT3        ; go check console status for ^c
  923. ;
  924. ;      issue page eject
  925. ;
  926. EJECT:    MVI    E,0CH        ; printer eject command
  927.     CALL    PBYT
  928.     MVI    E,00H
  929.     MVI    B,10
  930. EJECT2:    CALL    PBYT        ; print 10 nulls
  931.     DCR    B
  932.     JNZ    EJECT2
  933.     MVI    A,00
  934.     STA    LINES        ; set line count
  935.     RET
  936. ;
  937. ;      issue cr, lf & test page
  938. ;
  939. CRLF:    MVI    E,CR
  940.     CALL    PBYT
  941.     MVI    E,LF
  942.     CALL    PBYT
  943.     LDA    LINES
  944.     INR    A
  945.     STA    LINES        ; increment line count
  946.     MVI    A,LPAGE        ; get number of lines
  947.     ORA    A        ; is it zero?
  948.     LDA    LINES
  949.     RZ            ; yes, return
  950.     CPI    LPAGE        ; test line count
  951.     CZ    EJECT        ; if eq to lpage then new page
  952.     RET
  953. ;
  954. ;  routine to open a disk file
  955. ;
  956. FOPEN:    MVI    C,OPEN        ; open code
  957.     CALL    CPM        ; issue open
  958.     CPI    0FFH        ; error?
  959.     RNZ            ; no error
  960.     LXI    D,EMSG0
  961.     JMP    FERR1
  962. ;
  963. ; routine to close output disk cross reference file
  964. ;
  965. DCLOSE:    PUSH    D        ; save fcb address
  966.     PUSH    H        ; save buffer address
  967.     LHLD    DSKCNT        ; put number of char left...
  968.     XCHG            ; in buffer into d,e
  969.     LHLD    DCHAR        ; point to next char in output buf
  970.     MVI    A,1AH        ; put a control z in accum
  971. DCLSE2:    MOV    M,A        ; fill...
  972.     INX    H        ; rest of...
  973.     DCR    E        ; buffer...
  974.     JNZ    DCLSE2        ; with...
  975.     DCR    D        ; control z's.
  976.     JNZ    DCLSE2
  977.     POP    H        ; point to...
  978. ;
  979. DCLSE4:    XCHG            ; output buffer
  980.     LXI    H,128        ; put 128 into h,l
  981.     DAD    D        ; add 128 to disk buf addr for next dma
  982.     SHLD    BUFADR        ; save it for next dma after this one
  983.     MVI    C,SETDMA    ; disk buffer for...
  984.     CALL    CPM        ; last disk write
  985.     POP    D        ; do last...
  986.     PUSH    D        ; (d,e contains ofcb)...
  987.     MVI    C,WRITE        ; disk...
  988.     CALL    CPM        ; write
  989. ;
  990. ;check to see if last record has been written.    do this by comparing
  991. ;address of next available char to address of buffer for next disk write.
  992. ;if address of next available char is equal or greater, close file.
  993.     LHLD    DCHAR        ; put high order address
  994.     XCHG            ; of last char+1...
  995.     MOV    A,D        ; into accum
  996.     LHLD    BUFADR        ; get addr of next disk buffer
  997.     CMP    H        ; compare to last char+1 in buffer
  998.     JC    DCLSE5        ; if next addr is greater, close file
  999.     JNZ    DCLSE4        ; if not equal, continue
  1000.     MOV    A,E        ; put low order address of last char+1
  1001.     CMP    L        ; into accum and test
  1002.     JNC    DCLSE4        ; if not less, do another write
  1003. ;
  1004. DCLSE5:    POP    D        ; close the...(d,e contains ofcb)
  1005.     MVI    C,CLOSE        ; output disk
  1006.     CALL    CPM        ; cross ref file
  1007.     CPI    0FFH        ; close successfull?
  1008.     RNZ            ; yes, return
  1009.     LXI    D,EMSG5        ; no, display error msg...
  1010.     JMP    FERR1        ; and quit
  1011. ;
  1012. ;   routine to read a byte
  1013. ;
  1014. GETBT:    LXI    H,TBUF+(INSECT*128) ; end of input buf addr
  1015.     XCHG            ; buffer end addr. in de
  1016.     LHLD    INPTR        ; current pointer in hl
  1017.     CALL    CPHL        ; test for end of buffer
  1018.     CZ    GETREC        ; yes, read disk records
  1019.     MOV    A,M        ; get byte
  1020.     INX    H        ; bump pointer
  1021.     SHLD    INPTR        ; save pointer
  1022.     ORA    A        ; clear carry
  1023.     RET            ; return carry reset
  1024. ;
  1025. ;    getrec
  1026. ;
  1027. GETREC:    LDA    CONSOLE        ; Console on ?            2.5
  1028.     ORA    A        ;                2.5
  1029.     JNZ    GTREC1        ; Then he sees progress        2.5
  1030.     LHLD    LCNT        ; Line-count            2.5
  1031.     CALL    DECOT        ; into ASCII            2.5
  1032.     LXI    D,DECERA    ; Erase area            2.5
  1033.     CALL    PSOUT        ;                2.5
  1034.     LXI    D,DEC        ; ASCII linecount        2.5
  1035.     CALL    PSOUT        ; to show progress        2.5
  1036. GTREC1:    MVI    B,INSECT    ; number of sectors to read
  1037.     LXI    H,TBUF        ; get address of disk input buffer
  1038.     SHLD    IDADDR        ; initialize current buffer address
  1039.  
  1040. GETRC2:    LHLD    IDADDR        ; get addr of input buffer
  1041.     XCHG            ; put it in d,e
  1042.     LXI    H,128        ; add 128 to input buf
  1043.     DAD    D        ; addr for read after next
  1044.     SHLD    IDADDR        ; save it read after next
  1045.     PUSH    B        ; save sector count
  1046.     PUSH    D        ; save current buf ptr in case eof occurrs
  1047.     MVI    C,SETDMA    ; point to input buffer...
  1048.     CALL    CPM
  1049.     MVI    C,READ        ; read code
  1050.     LXI    D,TFCB        ; fcb address
  1051.     CALL    CPM        ; issue read
  1052.     POP    D        ; restore current buf pointer
  1053.     POP    B        ; restore sector count
  1054.     CPI    00        ; error?
  1055.     JNZ    GETRC4        ; yes
  1056.     DCR    B        ; read all of the sectors?
  1057.     JNZ    GETRC2        ; no, continue reading
  1058.  
  1059. GETRC3:    LXI    H,TBUF        ; reset buffer pointer
  1060.     SHLD    INPTR
  1061.     RET            ; return to caller
  1062.  
  1063. GETRC4:    XCHG            ; point to first char past buf
  1064.     MVI    M,26H        ; put two...
  1065.     INX    H        ; control z's
  1066.     MVI    M,26H        ; after last rec in file
  1067.     JMP    GETRC3        ; go reset buffer pointer
  1068. ;
  1069. ;   converts lower to upper case
  1070. ;
  1071. LWRUPR:    CPI    'A'+20H        ; is it upper case?
  1072.     CMC            ; complement carry
  1073.     RNC            ; yes, return with carry reset
  1074.     CPI    'Z'+21H        ; over lower case 'z'?
  1075.     RNC            ; no, return no carry
  1076.     SUI    20H        ; convert to upper case
  1077.     RET
  1078. ;
  1079. ;    PSOUT prints string in D
  1080. ;
  1081. PSOUT:    MVI    C,PSTRING    ; 
  1082.     CALL    CPM        ;Print String
  1083.     RET
  1084. ;
  1085. ;  routine to compare hl vs de
  1086. ;
  1087. CPHL:    MOV    A,H
  1088.     CMP    D
  1089.     RNZ
  1090.     MOV    A,L
  1091.     CMP    E
  1092.     RET
  1093. ;
  1094. ;          d a t a
  1095. ;
  1096. ;
  1097. ;    character parsing table
  1098. ;
  1099. CTAB1:    DB    CR
  1100.     DW    LCR
  1101.     DB    LF
  1102.     DW    LLF
  1103.     DB    ''''
  1104.     DW    LQUOT
  1105.     DB    ';'
  1106.     DW    LSEMI
  1107.     DB    ' '
  1108.     DW    LSPC
  1109.     DB    09H
  1110.     DW    LTAB
  1111.     DB    '$'
  1112.     DW    LDOL
  1113.     DB    '('
  1114.     DW    LDEL
  1115.     DB    ')'
  1116.     DW    LDEL
  1117.     DB    '+'
  1118.     DW    LDEL
  1119.     DB    '-'
  1120.     DW    LDEL
  1121.     DB    '*'
  1122.     DW    LSEMI
  1123.     DB    '/'
  1124.     DW    LDEL
  1125.     DB    ','
  1126.     DW    LDEL
  1127.     DB    ':'
  1128.     DW    LDEL
  1129.     DB    EOF
  1130.     DW    DONE
  1131.     DB    0FFH
  1132.     DW    0000H
  1133. ;
  1134. ;     reserved word table
  1135. ;
  1136. RTAB:    DB    '8080 '
  1137.     DB    'A    ','ACI  ','ADC  ','ADD  ','ADI  '
  1138.     DB    'AF   ','ANA  ','AND  ','ANI  ','ASEG '
  1139.     DB    'B    ','BC   ','BIT  '
  1140.     DB    'C    ','CALL ','CC   ','CCF  ','CM   '
  1141.     DB    'CMA  ','CMC  ','CMP  ','CNC  ','CNZ  '
  1142.     DB    'COMME','COMMO','COND ','CP   ','CPD  '
  1143.     DB    'CPDR ','CPE  ','CPI  ','CPL  ','CPO  '
  1144.     DB    'CSEG ','CZ   '
  1145.     DB    'D    ','DAA  ','DAD  ','DB   ','DC   '
  1146.     DB    'DCR  ','DCX  ','DE   ','DEC  ','DEFB '
  1147.     DB    'DEFL ','DEFM ','DEFW ','DI   ','DJNZ '
  1148.     DB    'DS   ','DSEG ','DW   '
  1149.     DB    'E    ','EI   ','ELSE ','END  ','ENDC '
  1150.     DB    'ENDIF','ENDM ','ENTRY','EQ   ','EQU  '
  1151.     DB    'EX   ','EXX  ','EXITM','EXT  ','EXTRN'
  1152.     DB    'GE   ','GLOBA','GT   '
  1153.     DB    'H    ','HL   ','HIGH ','HALT '
  1154.     DB    'IF   ','IFB  ','IFDEF','IFE  ','IFF  '
  1155.     DB    'IFNB ','IFNDE','IFT  ','IF1  ','IF2  '
  1156.     DB    'IM   ','IN   ','INC  ','INCLU','IND  '
  1157.     DB    'INDR ','INIR ','INR  ','INX  ','IRP  '
  1158.     DB    'IRPC ','IX   ','IY   '
  1159.     DB    'JC   ','JM   ','JMP  ','JNC  ','JNZ  '
  1160.     DB    'JP   ','JPE  ','JPO  ','JR   ','JZ   '
  1161.     DB    'L    ','LALL ','LD   ','LDA  ','LDAX '
  1162.     DB    'LDD  ','LDDR ','LDI  ','LDIR ','LE   '
  1163.     DB    'LHLD ','LIST ','LOCAL','LOW  ','LT   '
  1164.     DB    'LXI  '
  1165.     DB    'M    ','MACRO','MOD  ','MOV  ','MVI  '
  1166.     DB    'NAME ','NC   ','NE   ','NEG  ','NOP  '
  1167.     DB    'NOT  ','NUL  ','NZ   '
  1168.     DB    'OR   ','ORA  ','ORG  ','ORI  ','OTDR '
  1169.     DB    'OTIR ','OUT  ','OUTI ','OUTD '
  1170.     DB    'PAGE ','PCHL ','P    ','PE   ','PO   '
  1171.     DB    'POP  '
  1172.     DB    'PRINT','PSW  ','PUBLI','PUSH '
  1173.     DB    'RADIX','RAL  ','RAR  ','RC   ','REPT '
  1174.     DB    'RES  ','RET  ','RETI ','RL   ','RLA  '
  1175.     DB    'RLC  ','RLCA ','RLD  ','RM   ','RNC  '
  1176.     DB    'RNZ  ','RP   ','RPE  ','RPO  ','RR   '
  1177.     DB    'RRA  ','RRC  ','RRCA ','RRD  ','RST  '
  1178.     DB    'RZ   '
  1179.     DB    'SALL ','SBB  ','SBC  ','SBI  ','SCF  '
  1180.     DB    'SET  ','SHL  ','SHLD ','SHR  ','SLA  '
  1181.     DB    'SP   ','SPHL ','SRA  ','SRL  ','STA  '
  1182.     DB    'STAX ','STC  ','SUB  ','SUBTT','SUI  '
  1183.     DB    'TITLE'
  1184.     DB    'XALL ','XCHG ','XLIST','XOR  ','XRA  '
  1185.     DB    'XRI  ','XTHL '
  1186.     DB    'Z    ','Z80  '
  1187.     DB    0FFH        ; end of reserved word table
  1188. ;
  1189. EMSG1:    DB    'Symbol Table Error',CR,LF,'$'
  1190. EMSG2:    DB    'Failed to delete existing cross reference file',CR,LF,'$'
  1191. EMSG3:    DB    'Failed to create cross reference file',CR,LF,'$'
  1192. EMSG4:    DB    'Disk write failed - Out of space?',CR,LF,'$'
  1193. EMSG5:    DB    'Close failed on disk cross reference file',CR,LF,'$'
  1194. EMSG6:    DB    '++ERROR++ Not enough memory for Symbol Table',CR,LF,'$'
  1195. EMSG7:    DB    '++ERROR++ Symbol table Overflow?',CR,LF,'$'
  1196. DONEMSG: DB    CR,LF,'Cross Reference List is done',CR,LF,'$'
  1197. NOSYMS:    DB    'No Symbols in this Program'
  1198. CONCRLF:DB    CR,LF,'$'
  1199. OFCB:    DB    0        ; disk output fcb, default drive
  1200.     DS    8        ; file name
  1201.     DB    'XRF'        ; file type
  1202.     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
  1203. DCHAR:    DW    DISKBUF        ; pointer for disk buffer
  1204. BUFADR:    DS    2        ; pointer to disk output buffer for dma
  1205. IDADDR:    DS    2        ; pointer to disk input buffer for dma
  1206. DSKCNT:    DW    OUTSECT*128    ; number of char left in disk buffer
  1207. INPTR:    DW    TBUF+(INSECT*128) ; pointer to char in input buffer
  1208. DISKBUF:DS    OUTSECT*128    ; output disk buffer
  1209. TBUF:    DS    INSECT*128    ; disk input buffer
  1210. EOFCHR:    DB    26H,26H        ; control z's in case last block is
  1211.                 ; filled with data
  1212. ;
  1213. SYMBT:    DS    2        ; symbol table bottom address
  1214. SYMTP:    DS    2        ; symbol table top address
  1215. REFBT:    DS    2        ; reference table bottom address
  1216. REFTP:    DS    2        ; reference table top address
  1217. SYM:    DS    2        ; current symbol table address
  1218. REF:    DS    2        ; current reference table address
  1219. FROM:    DS    2        ; move pointer
  1220. TO:    DS    2        ; to pointer
  1221. LIMIT:    DS    2        ; limit pointer
  1222. COL:    DS    1
  1223. CHAR:    DS    1
  1224. LCNT:    DS    2        ; line counter
  1225. LINSYM:    DS    1        ; 0 if first symbol on line
  1226. LPNT:    DS    2
  1227. DEC:    DS    5
  1228. DECEND:    DB    '$$'
  1229. DECMRK:    DB    ' '
  1230. DECERA:    DB    BS,BS,BS,BS,BS,'$'    ;Erase string for Line-Nr display
  1231. PBUF:    DS    132
  1232. SYMCT:    DS    1
  1233. SYMPT:    DS    2
  1234. SBUF:    DS    SYMSIZ        ; symbol buffer
  1235. NLINS:    DB    0        ; buffers to print on line
  1236. LINES:    DB    0        ; print line count
  1237. ;
  1238. CONSOLE:DB    0        ; console output switch
  1239. DISKOUT:DB    0        ; disk output switch
  1240. LISTFLG:DB    0        ; 0=no source listing            2.5
  1241. FTPRN:    DB    1        ; prn file type
  1242. TEMP:    DS    2        ; temp save word
  1243.     DS    64        ; stack contains 32 words
  1244. STACK    EQU    $
  1245. ;
  1246. ;        symbol table area
  1247. ;
  1248. ;    the symbol table must be the
  1249. ;    last byte before ONCE ONLY CODE - XREF is NOT RESTARTABLE    2.5
  1250. ;
  1251.     ORG    $        ;
  1252. SYMT:    DB    0FFH
  1253. ;
  1254. LOGO:    DB    CR,LF,'CP/M Assembler Cross Reference List Ver 2.50',CR,LF,'$'
  1255. MSG1:    DB    'Disk Cross Reference File Exists - ERAse it(Y/N) ? ','$'
  1256. MSG2:    DB    'Want Line-numbered Listing (Y/N) ? ','$'        ;2.5
  1257. EMSG0:    DB    '++ERROR++ Input File does not exist',CR,LF        ;2.5
  1258. HELP:    DB    CR,LF,'This program can be used to'
  1259.     DB    ' create a cross reference listing',CR,LF
  1260.     DB    'of CPM assembler programs.'
  1261.     DB    '  The input can be either the assembler',CR,LF
  1262.     DB    'language source code(FN.ASM) or the assembly listing(FN.PRN).',CR,LF
  1263.     DB    'The output can be printed on the CPM list device, displayed on',CR,LF
  1264.     DB    'the console, or written to disk(file type will be XRF).  It is',CR,LF
  1265.     DB    'invoked by keying:',CR,LF,LF
  1266.     DB    09H,'XREF FN.ASM      (Output on List device)',CR,LF
  1267.     DB    09H,'XREF FN.PRN CON  (Output on the Console)',CR,LF
  1268.     DB    09H,'XREF FN.ASM D    (Output on disk-default drive)',CR,LF
  1269.     DB    09H,'XREF FN.PRN B:D  (Output on disk-drive specified)',CR,LF,'$'
  1270. ;
  1271. ;    setup or initialization
  1272. ;
  1273.  
  1274. SETUP:    LXI    D,LOGO        ; get program logo msg
  1275.     CALL    PSOUT        ;                2.5
  1276.     LDA    TFCB+1        ; get first char of file name
  1277.     CPI    '?'        ; help function?
  1278.     JNZ    SETUP1        ; no, go check input file type
  1279.     LXI    D,HELP        ; display help message
  1280.     JMP    FERR1
  1281.  
  1282. SETUP1:    MVI    A,0        ;                2.5
  1283.     STA    LISTFLG        ; no listing            2.5
  1284.     LDA    TFCB+9        ; get first char of file type
  1285.     CPI    'P'        ; is it type prn?
  1286.     JNZ    SETUP2        ; no, don't set switch
  1287.     LDA    TFCB+10        ; get 2nd char of file type
  1288.     CPI    'R'
  1289.     JNZ    SETUP2
  1290.     LDA    TFCB+11        ; get 3rd char of file type
  1291.     CPI    'N'
  1292.     JNZ    SETUP2
  1293.     XRA    A
  1294.     STA    FTPRN        ; turn on prn file type
  1295. ;
  1296. SETUP2:    LDA    TFCB+17        ; get 1rst char of 2nd fcb
  1297.     CPI    'C'        ; output to console?
  1298.     JNZ    SETUP3        ; no, don't turn on switch
  1299.     LDA    TFCB+18        ; get 2nd char of 2nd fcb
  1300.     CPI    'O'        ; output to console?
  1301.     JNZ    SETUP3        ; no, don't turn on switch
  1302.     MVI    A,0FFH        ; turn on...
  1303.     STA    CONSOLE        ; console output
  1304.     JMP    SETUP6        ; go open input file
  1305. SETUP3:    LDA    TFCB+17        ; get 1rst char of 2nd fcb
  1306.     CPI    'D'        ; output to be written to disk?
  1307.     JNZ    SETUP6        ; no, go open input file.
  1308.     MVI    A,0FFH        ;                    2.5
  1309.     STA    DISKOUT        ; turn on disk output switch
  1310.     LDA    TFCB+16        ; get output file drive number
  1311.     STA    OFCB        ; move to output fcb
  1312.     LXI    D,TFCB        ; point to fcb
  1313.     CALL    FOPEN        ; open disk input file
  1314.     LXI    D,TFCB+1    ; point to input file name
  1315.     MVI    B,8        ; length of file name
  1316.     LXI    H,OFCB+1    ; point to output fcb file name
  1317.     CALL    MOVE        ; move input file name to output fcb
  1318.     LXI    D,OFCB        ; does output file...
  1319.     MVI    C,OPEN        ; already...
  1320.     CALL    CPM        ; exist?
  1321.     CPI    0FFH        ; open succeed?
  1322.     JZ    SETUP4        ; no, file does not exist
  1323. ;
  1324.     LXI    D,OFCB        ; close...
  1325.     MVI    C,CLOSE        ; the open...
  1326.     CALL    CPM        ; file.
  1327.     LXI    D,MSG1        ; ask operator...
  1328.     CALL    PSOUT        ; if old file should be deleted        2.5
  1329.     MVI    C,CONIN        ; deleted
  1330.     CALL    CPM
  1331.     ANI    05FH        ; make upper case
  1332.     CPI    'Y'        ; operator say yes?
  1333.     JNZ    BOOT        ; no, terminate
  1334. ;
  1335.     LXI    D,CONCRLF    ; write CRLF to console
  1336.     CALL    PSOUT        ;                    2.5
  1337.     LXI    D,OFCB        ; point to fcb to delete file
  1338.     MVI    C,DELETE    ; delete the...
  1339.     CALL    CPM        ; file
  1340.     CPI    0FFH        ; delete succeed?
  1341.     LXI    D,EMSG2        ; get err msg in case of failure
  1342.     JZ    FERR1        ; failure, print msg & quit
  1343. ;
  1344. SETUP4:    LXI    D,OFCB        ; point to output fcb
  1345.     MVI    C,MAKE        ; create new...
  1346.     CALL    CPM        ; cross reference file.
  1347.     CPI    0FFH        ; create succeed?
  1348.     LXI    D,EMSG3        ; get err msg in case of failure
  1349.     JZ    FERR1        ; create failed, print msg & quit
  1350.     LXI    H,DISKBUF    ; get addr of disk buffer
  1351.     SHLD    DCHAR        ; init disk char pointer
  1352. ;
  1353. SETUP6:    LXI    D,TFCB        ; point to fcb
  1354.     CALL    FOPEN        ; open fcb
  1355.     LXI    D,MSG2        ; "Want Listing.."            2.5
  1356.     CALL    PSOUT        ;                    2.5
  1357.     MVI    C,CONIN        ;                    2.5
  1358.     CALL    CPM        ; get answer                2.5
  1359.     ANI    05FH        ; make upper case            2.5
  1360.     CPI    'N'        ;                    2.5
  1361.     JZ    STUP61        ; no listing                2.5
  1362.     MVI    A,0FFH        ;                    2.5
  1363.     STA    LISTFLG        ; wants listing                2.5
  1364. STUP61:    LXI    D,CONCRLF    ; write CRLF to console            2.5
  1365.     CALL    PSOUT        ;                    2.5
  1366.     LXI    H,PBUF
  1367.     SHLD    LPNT        ; set print pointer
  1368.     LXI    H,00001        ; set line counter...
  1369.     SHLD    LCNT        ; to one.
  1370.     LXI    H,SYMT        ; get address of symbol table
  1371.     SHLD    SYM
  1372.     SHLD    SYMBT
  1373.     SHLD    SYMTP        ; set symbol table pointers
  1374.     LHLD    MEMSZ        ; get available memory address
  1375.     DCX    H
  1376.     SHLD    REF
  1377.     SHLD    REFBT
  1378.     SHLD    REFTP        ; set reference table pointers
  1379.     RET
  1380. ;
  1381.     END    XREF
  1382. .
  1383.     LXI    H,SYMT        ; get address of symbol table
  1384.     SHLD    SYM
  1385.     SHLD    SYMBT