home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
simtel
/
sigm
/
vols000
/
vol070
/
xref141.asm
< prev
Wrap
Assembly Source File
|
1984-04-29
|
43KB
|
1,634 lines
TITLE 'XREF.ASM Ver 1.41 03/15/82'
PAGE 0
;********************************************************
; *
; This program generates a cross reference list for all *
; Symbols in a CPM assembler program. Its input is *
; either an assembler source file (FN.ASM) or an assem- *
; bler listing file (FN.PRN). It will number the lines *
; and generate a cross reference listing at the end of *
; the program. The output defaults to the CPM list *
; device, but it can be directed to the console or to a *
; disk file instead. If the output is directed to a *
; disk file, that file will be named FN.XRF. The *
; filename will be the filename of the input file. *
; It is invoked by entering: *
; XREF FN.ASM (OUTPUT TO LIST DEVICE) *
; XREF FN.PRN CON (OUTPUT TO CONSOLE) *
; XREF FN.ASM D (OUTPUT TO DISK-DEFAULT *
; DRIVE) *
; XREF FN.PRN B:D (OUTPUT TO DISK-DRIVE *
; NUMBER SPECIFIED) *
; *
; To invoke help function enter: *
; XREF ? *
; *
;********************************************************
;03/15/82 This program would lock up if there was a
;comment line that started with an asterisk('*') instead
;of a semicolon. The program then processed the whole
;line as a valid line of assemble code. This usually
;resulted in the cross reference program locking up if
;there were a lot lines that started with an asterisk.
;The program now treats an asterisk the same as a
;semicolon. This was done by changing the table CTAB1
;so that the program branches to LSEMI when it finds an
;asterisk. Also fixed bug that occurred when the last
;record of a file was completely filled with data and
;thus had no control Z's(EOF characters) in it. This
;was done by always placing two control Z's after the
;last record was read. Finally fixed a bug that showed
;up only when a program had no symbols or labels in it.
;Added a check for an empty symbol table before attempting
;to print the symbol table. (JRM)
;03/06/82 Changed the code so that the size of output
;disk buffer can be specified at assembly time. The
;size is set by OUTSECT which equals the number of disk
;sectors to be written when the buffer is full.
;Implemented the same feature for disk input. INSECT sets
;the number of disk records to be read into the input
;buffer. On file type PRN the was a bug. Whenever the
;first symbol on a line was preceded by a character, the
;line was not listed in the cross reference listing. This
;was caused by skipping over the first 16 characters in the
;line on a CR(carriage return) instead of on a LF(line feed).
;This bug has been fixed. Added help function. This is
;invoked by entering XFER ?. (JRM)
;03/03/82 Added a 2k buffer for disk output writes. This
;was done to speed up the execution of program when disk
;output was specified. Fixed bug when page size was
;specified. CPM assembler was not doing the conditional
;IF assembly correctly. Changed the code to test if page
;size is in effect by testing LPAGE to see if it is zero.
;Changed test to question to erase existing disk cross
;reference file to handle lower case as well as upper
;case. (JRM)
;02/20/82 Changed code so that the size of the symbol
;that is referenced in the cross reference listing can
;be set at assembly time. The original program only
;allowed for 5 char per symbol. This did not allow for
;separate unique symbols where the uniqueness occurred
;after the first 5 characters. I tested this function
;for a length of 5, 8, and 10 characters labels. It
; should work for any length of symbol. I also
;allowed the '$' character to be a valid character in a
;symbol. The equ SYMSIZ was added and all other values
;and variables that are dependent on the size of the
;symbol are expressed using SYMSIZ.
; Example: SSIZ EQU SYMSIZ+3
;Added a disk file output option. The output disk file
;will the filename of the input file and always a file
;type of 'XRF'. This option is enabled by specifying
;a 'D' as the second parameter when executing the program.
;The user can optionally specify a different drive than
;the default drive for the cross reference disk output.
; Example: XREF FN.ASM D
; XREF FN.PRN B:D
; (JRM)
;11/01/81 Changed the code so that the hex addresses and
;the hex translation of the instructions are not included
;in the cross reference listing for PRN files from CPM
;assembler. The listing can now be directed at execution
;time to the console or the list (LST:) device. If the
;listing is to be displayed on the console enter
; XREF FN.FT C
;If the listing is to go to the list device enter
; XREF FN.FT
;In other words, the output goes to the list device by
;default. (JRM)
;Modifications 4/5/79, 4/26/79, 5/3/79, 8/28/79 by SAN:
;Suppress initial page eject, add page eject at completion
;Automatically convert lower case in source file to UPPER
;Abort execution if ^C typed, but ignore other typed chars
;Add ELSE, PAGE to reserved word table
;********************************************************
;Number of lines per output page set by LPAGE EQUate
;Number of symbol refs per table entry set by NREFS EQUate
; This value should be set to the average number of
; references that a symbol will have in program. It
; is used to build the symbol reference table entries.
; Each entry will be equal to (NREFS * 2)+2. If it is
; made unnecessarily large, then the symbol reference
; table will be very large with a lot of unused slots.
; Example: a program with 300 symbols will require a
; reference table that is at least 12600 bytes if
; NREFS=20, whereas the same program will require a
; reference table that is at least 3600 bytes if
; NREFS=5. Each symbol that exceeds NREFS references
; will require ((Total references/NREFS)rounded up)
; reference table entries. Recommended values: 3-5.
;Number of symbol references to be printed per output line
; This is set by LREFS EQUate. It should be a multiple
; of NREFS. If it is not, then the first number that is
; less than LREFS and is a multiple of NREFS will be
; printed on the line. Example: if NREFS is 5 and
; LREFS is 13, then only 10 entries will be printed per
; line. The total number of references that will fit on
; one line without overflow is equal to the size of the
; line minus (SYMSIZ+2) divided by 5. Example: if the
; line size is 132 characters and SYMSIZ equals 8,
; then Total num of ref/line can be INT((132-(8+2))/5)
; or INT(122/5) or 20.
;Symbol size is set by SYMSIZ. This is the symbol size that the
; program will use in the cross reference listing. It
; should be large enough to make each symbol unique in
; cross reference listing. If a symbol is larger than the
; value for SYMSIZ, then the symbol will be truncated in the
; output(eg: LARGE$SYMBOL would be LARGE$SYM if SYMSIZ was
; set to 9. Recommended value is 8.
;OUTSECT sets the number of disk records that will be written to
; disk when the output disk buffer is full. This value is
; used by the program to calculate the size of the output
; disk buffer. Output buffer size = OUTSECT * 128.
; Recommended value is from 8 to 32. 16 works well.
;INSECT is the number of disk records that will be read when the
; disk input buffer is empty. It is used to calculate the
; size of the input buffer. Input buffer size = INSECT * 128.
; Recommend value is from 8 to 32. 16 works well.
;NOTE: If OUTSECT and INSECT are made too large, there will not be
; be enough memory left to build the cross reference table
; for a large program. Largest tested values so far(3/6/82)
; is 64 for OUTSECT and 64 for INSECT on a 64K system. The
; file successfully cross referenced was MODEM74.PRN. (JRM)
;Graceful exit after error message if file not found
LPAGE EQU 00 ;NUM LINES PER PAGE IF PEJECT IS TRUE
NREFS EQU 03 ;NUMBER OF REFERENCES PER REF TBL ENTRY
LREFS EQU 21 ;REFERENCES PER OUTPUT LINE
SYMSIZ EQU 08 ;NUMBER OF SYMBOL CHAR
OUTSECT EQU 32 ;NUMBER OF DISK SECTORS WRITTEN FROM BUFFER
INSECT EQU 32 ;NUMBER OF DISK SECTORS READ INTO BUFFER
;********************************;
;
; INTEL ASSEMBLER
; CROSS REFERENCE PROGRAM
;
; VERSION 1.41
;
; JEFF KRAVITZ
;
; MODIFIED BY JOHN MAHR
;
;********************************;
;********************************;
;
; MAIN LOOP
;
;********************************;
ORG 100H ;ORIGIN ADDRESS
XREF: LXI SP,STACK ;SET STACK POINTER
CALL SETUP ;INITIALIZE
MAIN: CALL GETBT ;GET A BYTE FROM SOURCE FILE
CALL SAVBT ;SAVE BYTE IN PRINT BUFFER
MAIN2: CALL CKNUM ;TEST FOR NUMERIC
JNC LNUM ;YES, FOUND A NUMBER, PROCESS
CALL CKALP ;TEST FOR ALPHABETIC
JNC LALPH ;YES, PROCESS
LXI H,CTAB1 ;POINT TO CHARACTER TABLE
CALL LOOK ;LOOK UP CHAR IN CHAR TABLE
JC LIGN ;NOT FOUND, IGNORE
PCHL ;EXECUTE ROUTINE
;*******************************************************
;
; DONE
;
; FINAL SYMBOL TABLE PRINT
;
; DONE gets control when a control Z(1AH) is found
; in the input data stream. This routine:
;
; 1. issues a page eject
; 2. prints the cross reference table
; 3. issues a page eject
; 4. if disk output, writes out the remaining
; sectors in the disk output buffer and
; then closes the disk output file.
; 5. close the disk input file.
; 6. displays end of program message.
;
;*******************************************************
DONE: CALL EJECT ;ISSUE PAGE EJECT
LHLD SYMBT ;GET SYMBOL TABLE BOTTOM
MVI A,0FFH ;check to see if there were...
CMP M ;...any symbols in the program
JZ DLP4 ;no, don't print symbol table
SHLD SYM ;SET SYMBOL POINTER
LHLD SYMTP ;GET SYMBOL TABLE TOP
MVI M,0FFH ;END OFF SYMBOL TABLE
DLP1: LHLD SYM ;GET SYMBOL TABLE POINTER
CALL PSYM ;PRINT SYMBOL
LHLD SYM
LXI D,SYMSIZ+1 ;OFFSET TO REF LINK
DAD D
MOV E,M
INX H
MOV D,M ;GET REF BLOCK ADDR
XCHG ;INTO HL
SHLD REF
CALL PREFS ;PRINT REFERENCES
LHLD SYM ;GET SYMBOL TABLE POINTER
LXI D,SSIZ ;SIZE OF SYM TABLE ENTRY
DAD D
SHLD SYM
MOV A,M ;GET BYTE
CPI 0FFH ;END OF TABLE?
JNZ DLP1 ;LOOP
DLP2: CALL EJECT ;PAGE EJECT
LDA DISKOUT ;GET DISK OUTPUT SWITCH
ORA A ;DISK OUTPUT BEING USED?
JZ DLP3 ;NO, ISSUE END MSG & RETURN TO CPM
LXI H,DISKBUF ;GET OUTPUT DISK BUFFER
LXI D,OFCB ;AND OUT FCB
CALL DCLOSE ;AND CLOSE OUTPUT DISK FILE
DLP3: LXI D,TFCB ;CLOSE THE...
MVI C,CLOSE ;...INPUT...
CALL CPM ;...FILE.
LXI D,DONEMSG ;TELL OPERATOR...
MVI C,PSTRING ;...THAT PGM IS...
CALL CPM ;...DONE
JMP BOOT ;AND RETURN TO CP/M
DLP4: LXI H,NOSYMS ;get no symbol message
MVI B,28 ;NUMBER OF CHAR IN MSG
DLP5: MOV E,M ;print the...
CALL PBYT ;...message
INX H
DCR B
JNZ DLP5
JMP DLP2 ;go close files
;********************************;
;
; SYMBOL PRINT ROUTINE
;
;********************************;
PSYM: MVI B,SYMSIZ ;SYMBOL SIZE
PSYM2: MOV E,M ;GET BYTE
CALL PBYT ;PRINT BYTE
INX H
DCR B
JNZ PSYM2
MVI E,' '
CALL PBYT ;PRINT 2 SPACES
CALL PBYT
RET
;********************************;
;
; REFERENCE PRINT ROUTINE
;
;********************************;
PREFS: MVI A,LREFS/NREFS ;NUMBER OF BLOCKS TO PRINT ON ONE LINE
STA NLINS ;TO NLINS
PREF0: LHLD REF ;GET REF BLOCK ADDR
INX H
INX H ;BUMP TO FIRST REF NUMBER
SHLD TEMP ;SAVE REF NUM ADDR
MVI A,(REFSZ-2)/2 ;NUMBER OF REF SLOTS
STA SYMCT ;SAVE IN SYMCT
PREF: LHLD TEMP ;GET REF SLOT ADDR
MOV E,M
INX H
MOV D,M ;GET REF
LXI H,0000 ;ZERO?
CALL CPHL
JZ CRLF ;YES, DONE
XCHG ;GET NUM IN HL
CALL DECOT ;CONVERT
LXI H,DEC ;POINT TO DEC STRING
MVI M,' ' ;BLANK LEADING ZERO
MVI B,5 ;NUMBER OF DIGITS + 1 IN REF NUM
PREF2: MOV E,M
CALL PBYT ;PRINT BYTE
INX H
DCR B
JNZ PREF2 ;PRINT REFERENCE NUMBER
LHLD TEMP ;GET REF SLOT ADDR
INX H
INX H ;BUMP TO NEXT SLOT
SHLD TEMP
LDA SYMCT ;GET COUNT
DCR A ;DECREMENT
STA SYMCT
JNZ PREF
LHLD REF ;GET REF BLOCK ADDRESS
MOV E,M
INX H
MOV D,M ;GET LINK TO NEXT BLOCK
LXI H,0000
CALL CPHL ;ANY MORE BLOCKS?
JZ CRLF ;NO, EXIT
XCHG ;YES, SET NEXT BLOCK POINTER IN REF
SHLD REF
LDA NLINS
DCR A ;DECREMENT LINES COUNT
STA NLINS
JNZ PREF0 ;AND PRINT MORE ON SAME LINE
CALL CRLF ;PRINT CR,LF
MVI B,SYMSIZ+2 ;INDENT CONTINUATION LINE...
PREF3: MVI E,' ' ;...WITH SPACES
CALL PBYT ;PRINT SPACES
DCR B
JNZ PREF3 ;PRINT 6 SPACES
JMP PREFS
;********************************;
;
; CHARACTER PARSING ROUTINES
;
;********************************;
LALPH: LXI H,SBUF ;POINT TO SYMBOL BUFFER
MVI C,SYMSIZ
MVI A,' ' ;FILL SYMBOL...
LALX: MOV M,A ;...WITH...
INX H ;...BLANKS
DCR C
JNZ LALX ;CLEAR SYMBOL BUFFER
LXI H,SBUF
SHLD SYMPT
MVI A,00
STA SYMCT ;RESET SYMBOL POINTER+COUNT
LDA CHAR ;GET CHARACTER AGAIN
CALL GTSYM ;COLLECT IDENTIFIER
LALC: CALL GETBT ;GET A BYTE FROM SOURCE FILE
CALL SAVBT ;SAVE BYTE IN PRINT BUFFER
CALL CKNUM ;TEST FOR NUMBER
JNC LAL3 ;YES, CONTINUE
CALL CKALP ;TEST FOR ALPHABETIC
JNC LAL3 ;YES, CONTINUE
CALL CRES ;TEST FOR RESERVED WORD
JC LAL1 ;NO, CONTINUE
LAL0: LDA CHAR ;GET CHARACTER THAT ENDED ID
JMP MAIN2 ;CONTINUE SCAN
LAL1: CALL FIND ;SEE IF DEFINED
JC LAL2 ;NO, CONTINUE
CALL ADDRF ;YES, ADD REFERENCE
JMP LAL0 ;DONE
LAL2: CALL ENSYM ;ENTER SYMBOL DEFINITION
CALL ADDRF ;ADD REFERENCE
JMP LAL0 ;CONTINUE
LAL3: CALL GTSYM ;COLLECT IDENTIFIER
JMP LALC ;CONTINUE
LNUM: CALL GETBT ;GET BYTE
CALL SAVBT ;SAVE BYTE IN PRINTER BUFFER
CALL CKNUM ;TEST FOR NUMERIC
JNC LNUM ;YES, CONTINUE
CALL CKALP ;TEST FOR ALPHABETIC
JNC LNUM ;YES, CONTINUE
JMP MAIN2 ;CONTINUE WITH MAIN SCAN
LQUOT: CALL GETBT ;GET A BYTE
CALL SAVBT ;SAVE BYTE IN PRINTER BUFFER
CPI '''' ;SEE IF STRING QUOTE
JNZ LQUOT ;NO, KEEP LOOPING
CALL GETBT ;GET NEXT BYTE
CALL SAVBT ;SAVE BYTE
CPI '''' ;TEST FOR DOUBLES
JZ LQUOT ;YES, START SCAN AGAIN
JMP MAIN2 ;NO, CONTINUE IN MAIN SCAN
LSEMI: CALL GETBT ;GET A BYTE
CALL SAVBT ;SAVE BYTE
CPI 0DH ;WAIT FOR CR
JNZ LSEMI ;CONTINUE
JMP MAIN2 ;ENTER MAIN LOOP
LCR: CALL PLINE ;PRINT LINE
LHLD LCNT ;GET LINE NUMBER
INX H ;BUMP LINE NUMBER
SHLD LCNT ;STORE
JMP MAIN
LLF: PUSH PSW ;save char
LDA FTPRN ;is it file...
ORA A ;...type PRN?
JZ LLF2 ;yes, skip 1rst 16 char
POP PSW ;restore char
JMP MAIN
LLF2: POP PSW ;RESTORE CHARACTER
MVI B,16 ;# OF CHAR TO SKIP OVER
LLF3: CALL GETBT ;get next byte
CALL SAVBT ;put in print buf
CPI 0DH ;carriage return?
JZ LCR ;yes, get next line
DCR B ;skipped all char?
JNZ LLF3 ;no, continue skipping
JMP MAIN ;CONTINUE
LIGN: JMP MAIN ;RE-ENTER MAIN LOOP
LSPC EQU LIGN
LTAB EQU LIGN
LDOL EQU LIGN
LDEL EQU LIGN
;********************************;
;
; SUBROUTINES
;
;********************************;
;******************************************************************
;
; SETUP
;
; INITIALIZATION
;
; 1. displays program logo and version
; 2. checks for input file type PRN.
; -if file type PRN, sets PRN switch.
; 3. if oper specified FN.FT CON, then sets console
; output switch on. Goes to step 5.
; 4. else check for disk output option.
; -if not disk output, default to printer output.
; -go to step 5.
; -else check to see if cross reference file exists.
; -if it exists, ask operater if it is to
; be erased.
; -if no erase, terminate program
; -else erase cross reference file.
; -then create new cross reference disk file.
; -initialize output character pointer to disk buffer.
; 5. open input disk file.
; 6. initialize printer buffer, address pointers for symbol table
; and reference table, set line counter to 1.
; 7. return to caller
;
;******************************************************************
SETUP: LXI D,LOGO ;get program logo msg
MVI C,PSTRING ;BDOS PRINT STRING
CALL CPM ;PRINT LOGO
LDA TFCB+1 ;get first char of file name
CPI '?' ;help function?
JNZ SETUP1 ;no, go check input file type
LXI D,HELP ;display help message
JMP FERR1
SETUP1: LDA TFCB+9 ;get first char of file type
CPI 'P' ;is it type PRN?
JNZ SETUP2 ;no, don't set switch
LDA TFCB+10 ;get 2nd char of file type
CPI 'R'
JNZ SETUP2
LDA TFCB+11 ;get 3rd char of file type
CPI 'N'
JNZ SETUP2
XRA A
STA FTPRN ;turn on prn file type
SETUP2: LDA TFCB+17 ;get 1rst char of 2nd fcb
CPI 'C' ;output to console?
JNZ SETUP3 ;no, don't turn on switch
LDA TFCB+18 ;get 2nd char of 2nd fcb
CPI 'O' ;output to console?
JNZ SETUP3 ;no, don't turn on switch
MVI A,0FFH ;turn on...
STA CONSOLE ;...console output
JMP SETUP6 ;go open input file
SETUP3: LDA TFCB+17 ;get 1rst char of 2nd fcb
CPI 'D' ;output to be written to disk?
JNZ SETUP6 ;no, go open input file.
STA DISKOUT ;turn on disk output switch
LDA TFCB+16 ;get output file drive number
STA OFCB ;move to output fcb
LXI D,TFCB ;point to fcb
CALL FOPEN ;open disk input file
LXI D,TFCB+1 ;point to input file name
MVI B,8 ;length of file name
LXI H,OFCB+1 ;point to output fcb file name
CALL MOVE ;move input file name to output fcb
LXI D,OFCB ;does output file...
MVI C,OPEN ;...already...
CALL CPM ;...exist?
CPI 0FFH ;open succeed?
JZ SETUP4 ;no, file does not exist
LXI D,OFCB ;close...
MVI C,CLOSE ;...the open...
CALL CPM ;...file.
LXI D,MSG1 ;ask operator...
MVI C,PSTRING ;...if old file...
CALL CPM ;...is to be...
MVI C,CONIN ;...deleted
CALL CPM
ANI 05FH ;make upper case
CPI 'Y' ;operator say yes?
JNZ BOOT ;no, terminate
LXI D,CONCRLF ;write carriage return...
MVI C,PSTRING ;...line feed to console
CALL CPM
LXI D,OFCB ;point to fcb to delete file
MVI C,DELETE ;delete the...
CALL CPM ;...file
CPI 0FFH ;delete succeed?
LXI D,EMSG2 ;get err msg in case of failure
JZ FERR1 ;failure, print msg & quit
SETUP4: LXI D,OFCB ;point to output fcb
MVI C,MAKE ;create new...
CALL CPM ;...cross reference file.
CPI 0FFH ;create succeed?
LXI D,EMSG3 ;get err msg in case of failure
JZ FERR1 ;create failed, print msg & quit
LXI H,DISKBUF ;get addr of disk buffer
SHLD DCHAR ;init disk char pointer
SETUP6: LXI D,TFCB ;POINT TO FCB
CALL FOPEN ;OPEN FCB
LXI H,PBUF
SHLD LPNT ;SET PRINT POINTER
LXI H,00001 ;SET LINE COUNTER...
SHLD LCNT ;...TO ONE.
LXI H,SYMT ;GET ADDRESS OF SYMBOL TABLE
SHLD SYM
SHLD SYMBT
SHLD SYMTP ;SET SYMBOL TABLE POINTERS
LHLD MEMSZ ;GET AVAILABLE MEMORY ADDRESS
DCX H
SHLD REF
SHLD REFBT
SHLD REFTP ;SET REFERENCE TABLE POINTERS
RET
;********************************;
;
; CHECK FOR RESERVED WORD
;
;********************************;
CRES: LXI H,RTAB ;POINT TO RESERVED WORD TABLE
SHLD TEMP ;SAVE IN TEMP WORD
CRES1: LHLD TEMP ;GET TABLE POINTER
LXI D,SBUF ;POINT TO SYMBOL
MVI B,5 ;SYMBOL SIZE
CRES2: LDAX D ;GET SYMBOL BYTE
CMP M ;COMPARE AGAINST TABLE ENTRY
RC ;LESS, NOT IN TABLE
JNZ CRES3 ;GREATER, GET NEXT TABLE ENTRY
INX D ;BUMP POINTERS
INX H
DCR B ;DECREMENT BYTE COUNT
JNZ CRES2 ;KEEP TESTING
JMP CRES4 ;FOUND
CRES3: LHLD TEMP ;GET TABLE POINTER
LXI D,RSIZ ;SIZE OF ENTRY
DAD D ;BUMP POINTER
SHLD TEMP ;STORE NEW POINTER
MOV A,M ;GET TABLE BYTE
CPI 0FFH ;END OF TABLE?
JNZ CRES1 ;NO, LOOP
STC ;SET CARRY (NOT IN TABLE)
RET
CRES4: ORA A ;RESET CARRY
RET
;********************************;
;
; FIND SYMBOL IN TABLE
;
;********************************;
FIND: LHLD SYMBT ;GET BEGIN OF SYM TABLE
SHLD SYM ;SET TEMP POINTER
FIND1: LHLD SYM ;GET TEMP POINTER
LXI D,SBUF ;POINT TO CURRENT SYMBOL
MVI B,SYMSIZ ;SYMBOL SIZE
FIND2: LDAX D ;GET BYTE FROM SBUF
CMP M ;COMPARE TO SYM TABLE BYTE
RC ;GREATER, NOT IN TABLE
JNZ FIND3 ;LESS, GET NEXT TABLE ENTRY
INX D ;BUMP POINTER
INX H ;BUMP POINTER
DCR B ;DECREMENT BYTE COUNT
JNZ FIND2 ;LOOP
RET ;TRUE ZERO, FOUND
FIND3: LHLD SYM ;GET CURRENT POINTER
LXI D,SSIZ ;SYMBOL TABLE ENTRY SIZE
DAD D ;BUMP POINTER
XCHG ;INTO DE
LHLD SYMTP ;GET TOP OF SYMBOL TABLE
CALL CPHL ;TEST FOR END OF TABLE
JZ FIND4 ;YES, DONE
JC FERR ;TABLE OVERFLOW, ERROR
XCHG ;CURRENT POINTER INTO HL
SHLD SYM ;SET CURRENT POINTER
JMP FIND1 ;LOOP
FIND4: STC ;SET CARRY FOR NOT FOUND
LHLD SYMTP ;GET CURRENT TOP
SHLD SYM ;SET CURRENT POINTER
RET
FERR: LXI D,EMSG1 ;SYMBOL TABLE ERR MSG
FERR1: MVI C,PSTRING ;WRITE CONSOLE
CALL CPM ;ISSUE ERROR MESSAGE
JMP BOOT ;EXIT
FERR2: LXI D,EMSG6 ;no room for symbol table
JMP FERR1
;********************************;
;
; ADD REFERENCE TO REF TABLE
;
;********************************;
ADDRF: LHLD SYM ;GET SYMBOL POINTER
LXI D,SYMSIZ+1 ;OFFSET PAST SYMBOL&FLAGS
DAD D
MOV E,M
INX H
MOV D,M ;GET REFERENCE POINTER
LXI H,0000
CALL CPHL ;TEST FOR ZERO REF PTR
JZ BLDRF ;YES, BUILD REFERENCE ENTRY
LINK1: XCHG ;REF PTR IN HL
MOV E,M ;GET REF LINK
INX H
MOV D,M ;INTO DE
DCX H ;REPOSITION HL
PUSH H ;SAVE REF PTR
LXI H,0000
CALL CPHL ;IF LINK IS ZERO
POP H
JNZ LINK1 ;NON ZERO, GET NEXT LINK
SHLD REF ;SAVE REF POINTER
INX H
INX H ;SKIP TO FIRST REF NUMBER
MVI B,(REFSZ-2)/2 ;NUMBER OF REF NUMBERS/ENTRY
LINK3: MOV E,M ;GET REF NUMBER
INX H
MOV D,M
DCX H ;REPOSITION
PUSH H ;SAVE REF NUM ADDR
LXI H,0000
CALL CPHL ;SEE IF REF NUM IS ZERO
POP H
JZ ENREF ;YES, ENTER REFERENCE
INX H
INX H ;SKIP TO NEXT REF NUM
DCR B ;DECREMENT COUNT
JNZ LINK3 ;TRY AGAIN AT NEXT SLOT
CALL ADBLK ;ADD NEW REF BLOCK
LHLD REF ;GET REF POINTER
INX H
INX H ;SKIP TO FIRST REF SLOT
ENREF: PUSH H ;SAVE REF SLOT ADDR
LHLD LCNT ;GET LINE NUMBER
XCHG ;INTO DE
POP H ;GET REF SLOT ADDR
MOV M,E
INX H
MOV M,D ;STORE LINE REF
RET ;DONE
;********************************;
;
; BUILD REF TABLE BLOCK
;
;********************************;
BLDRF: LHLD SYM ;GET SYMBOL POINTER
LXI D,SYMSIZ+1 ;OFFSET TO REF POINTER
DAD D
SHLD REF ;SET TEMP REF POINTER TO HERE
CALL ADBLK ;ADD BLOCK
LHLD REF ;GET REAL REF POINTER
INX H
INX H ;POSITION TO FIRST REF SLOT
JMP ENREF ;ADD REFERENCE
ADBLK: LHLD REFBT ;GET REF BOTTOM
LXI D,REFSZ ;SUBTRACT REF SIZE
MOV A,L
SUB E
MOV L,A
MOV A,H
SBB D
MOV H,A
SHLD TEMP ;SAVE NEW REF BOTTOM
XCHG ;INTO DE ALSO
LHLD SYMTP ;GET SYMBOL TOP
CALL CPHL ;CHECK FOR BUMP
JZ FERR2 ;YES, NO ROOM
JNC FERR2 ;NO ROOM
LHLD TEMP ;GET REF BOTTOM
XCHG ;INTO DE
LHLD REF ;GET REF POINTER
MOV M,E ;SET LINK
INX H
MOV M,D ;TO NEW REF BLOCK
LHLD TEMP ;GET NEW REF BLOCK ADDR
SHLD REF ;STORE IN REF
MVI B,REFSZ ;SIZE OF REF BLOCK
MVI A,00
ADB2: MOV M,A ;ZERO THE REF BLOCK
INX H
DCR B
JNZ ADB2
LHLD TEMP ;GET NEW REF BOTTOM
SHLD REFBT ;SET REFBT
RET
;********************************;
;
; ENTER SYMBOL IN SYM TABLE
;
;********************************;
ENSYM: LHLD SYM ;GET SYMBOL POINTER
XCHG ;INTO DE
LHLD SYMTP ;GET SYMBOL TABLE TOP
CALL CPHL ;CHECK FOR END OF TABLE
JZ NWSYM ;YES, ADD SYMBOL AT END
LXI D,SSIZ ;SYMBOL TABLE ENTRY SIZE
DAD D ;CALCULATE NEW END OF TABLE
XCHG ;INTO DE
LHLD REFBT ;REFERENCE TABLE BOTTOM
CALL CPHL ;TEST FOR TABLE OVERFLOW
LXI D,EMSG7 ;ADDR OF ERR MSG IN OF OVERFLOW
JZ FERR1 ;FULL, ERROR
JC FERR1 ;YES, ERROR
LHLD SYMTP ;GET TABLE TOP
LXI D,SSIZ-1 ;BUMP TO END OF ENTRY
DAD D
SHLD TO ;STORE IN TO ADDRESS
LXI D,SSIZ
MOV A,L
SUB E
MOV L,A
MOV A,H
SBB D
MOV H,A ;SUBTRACT SIZE OF ONE ENTRY
SHLD FROM ;STORE AS FROM ADDRESS
LHLD SYM ;GET CURRENT POINTER
SHLD LIMIT ;STORE AS LIMIT ADDRESS
CALL MVUP ;MOVE TABLE UP IN MEMORY
NWSYM: LHLD SYM ;GET CURRENT POINTER
LXI D,SBUF ;POINT TO SYMBOL
MVI B,SYMSIZ ;SIZE OF SYMBOL
CALL MOVE ;COPY SYMBOL TO TABLE
MVI A,0
MOV M,A
INX H
MOV M,A
INX H
MOV M,A ;SET POINTERS TO 0000
LHLD SYMTP ;GET SYMBOL TABLE TOP
LXI D,SSIZ ;GET SYMBOL ENTRY SIZE
DAD D ;BUMP
SHLD SYMTP ;STORE EW TOP
RET
;********************************;
;
; MOVE SYMBOL TABLE UP
;
;********************************;
MVUP: LHLD TO ;GET TO POINTER
MOV B,H
MOV C,L ;INTO BC
LHLD FROM ;GET FROM POINTER
XCHG ;INTO DE
LHLD LIMIT ;GET LIMIT ADDRESS
MVUP2: LDAX D ;GET FROM BYTE
STAX B ;STORE AT TO ADDRESS
CALL CPHL ;COMPARE FROM TO LIMIT
RZ ;EXIT IF DONE
DCX B ;DECREMENT TO
DCX D ;DECRMENT FROM
JMP MVUP2 ;LOOP
;********************************;
;
; GENERAL PURPOSE MOVE ROUTINE
;
;********************************;
MOVE: LDAX D ;GET BYTE
MOV M,A ;STORE BYTE
INX D
INX H ;BUMP POINTERS
DCR B ;DECREMENT COUNT
JNZ MOVE ;LOOP
RET
;********************************;
;
; BINARY TO DECIMAL CONVERSION
;
;********************************;
DECOT: LXI D,DEC
XCHG
LXI B,10000
CALL DIG
LXI B,1000
CALL DIG
LXI B,100
CALL DIG
LXI B,10
CALL DIG
LXI B,1
CALL DIG
RET
DIG: MVI M,'0'
DI0: MOV A,E
SUB C
MOV E,A
MOV A,D
SBB B
MOV D,A
JM DI2
INR M
JMP DI0
DI2: MOV A,E
ADD C
MOV E,A
MOV A,D
ADC B
MOV D,A
INX H
RET
;********************************;
;
; TEST FOR ALPHABETIC CHAR.
;
;********************************;
CKALP: cpi '$' ;treat '$' like a char
rz
CPI 'A' ;ASCII 'A'
RC ;NO, EXIT
CPI 'Z'+1
CMC
RET
;********************************;
;
; TEST FOR NUMERIC CHAR
;
;********************************;
CKNUM: CPI '0'
RC
CPI '9'+1
CMC
RET
;********************************;
;
; LOOK UP CHAR IN PARSE TABLE
;
;********************************;
LOOK: LXI D,0003 ;TABLE ENTRY SIZE
MOV B,A ;ARGUMENT BYTE IN B
LOOK2: MOV A,M ;GET TABLE BYTE
CPI 0FFH ;END OF TABLE?
JZ LOOKN ;YES, NOT FOUND
CMP B ;COMPARE
JZ LOOKY ;FOUND
DAD D ;BUMP POINTER
JMP LOOK2 ;LOOP
LOOKN: STC ;CARRY = NOT FOUND
RET
LOOKY: INX H ;SKIP TO TABLE BYTE
MOV E,M
INX H
MOV D,M ;TABLE ENTRY IN DE
XCHG ;INTO HL
RET
;********************************;
;
; SAVE BYTE IN LINE BUFFER
;
;********************************;
SAVBT: LHLD LPNT ;GET LINE POINTER
MOV M,A ;SAVE BYTE
INX H ;BUMP POINTER
SHLD LPNT ;SAVE POINTER
call lwrupr ;convert lower to upper case
sta char ;save char in char
RET
;********************************;
;
; PRINT SOURCE LINE WITH NUMBER
;
;********************************;
PLINE: LHLD LCNT ;GET LINE NUMBER
CALL DECOT ;CONVERT TO DECIMAL
LXI H,DEC ;POINT TO DEC STRING
PL2: MOV E,M ;GET STRING BYTE
MOV A,E
CPI 0DH ;DONE?
JZ PL3 ;YES
CALL PBYT ;PRINT BYTE
INX H ;BUMP POINTER
JMP PL2
PL3: MVI E,':'
CALL PBYT ;PRINT ':'
MVI E,' '
CALL PBYT ;PRINT ' '
CALL PBYT ;PRINT SPACE
LXI H,PBUF ;POINT TO PRINT BUFFER
MVI A,00
STA COL ;SET COLUMN COUNT
PL41: MOV E,M ;GET BYTE
MOV A,E
CPI 0DH ;DONE?
JZ PL5
CPI 0AH ;LF?
JZ PL4A ;YES, IGNORE
CPI 09H ;TAB?
JNZ PL42 ;NO, CONTINUE
PUSH H ;SAVE HL
PL43: MVI E,' '
CALL PBYT ;PRINT SPACE
LXI H,COL
INR M
MOV A,M
ANI 07H ;MODULO 8
JNZ PL43
POP H
JMP PL4A
PL42: LDA COL
INR A
STA COL
CALL PBYT ;PRINT BYTE
PL4A: INX H
JMP PL41
PL5: CALL CRLF ;PRINT CR,LF
LXI H,PBUF
SHLD LPNT ;RESET LINE POINTER
RET
;********************************;
;
; COLLECT SYMBOL IN SYM BUF
;
;********************************;
GTSYM: MOV B,A ;SAVE CHAR
LDA SYMCT ;GET SYMBOL COUNT
CPI SYMSIZ ;MAX?
RNC ;YES, DONE
INR A
STA SYMCT
LHLD SYMPT
MOV M,B
INX H ;BUMP SYMBOL POINTER
SHLD SYMPT
RET
;********************************;
;
; PRINTER INTERFACES
;
;********************************;
;********************************;
;
; PRINT A SINGLE BYTE
;
;********************************;
PBYT: PUSH B
PUSH D
PUSH H
PUSH PSW
LDA DISKOUT ;disk output...
ORA A ;...in effect?
JNZ DBYT ;yes, go write to disk
MVI C,05
LDA CONSOLE ;get console out switch
ORA A ;console output?
JZ PBYT2 ;no, print output
MVI C,2 ;console output
PBYT2: CALL CPM
PBYT3: MVI C,11 ;CHECK CONSOLE STATUS
CALL CPM
ORA A ;IF ZERO, OK
JZ PBYTX ;EXIT
MVI C,1
CALL CPM ;READ CONSOLE CHAR
CPI 3
JZ BOOT ;ABORT IF ^C, OTHERWISE IGNORE
PBYTX: POP PSW
POP H
POP D
POP B
RET
;**************************************;
;
; DBYT
;
; PUT OUTPUT CHARACTER
; INTO DISK BUFFER.
; INPUT=E(OUTPUT CHAR)
;
; 1. move character to buffer.
; 2. if at end of buffer, go
; write out disk buffer.
; 3. else add 1 to disk buffer
; pointer.
; 4. subtract 1 from number of
; positions left in buffer.
; 5. go check if operator pressed
; control C.
;
;***************************************;
DBYT: MOV A,E ;save char to be put in buffer
LHLD DSKCNT ;get num of char left in buf
XCHG ;put num in D,E
LHLD DCHAR ;point to next char in buf
MOV M,A ;put char in disk buf
DCR E ;at end of buf?
JNZ DBYT1 ;no, don't write buffer
DCR D ;at end of buf?
JZ PUTREC ;yes, go write buffer
DBYT1: INX H ;point to next char in buf
SHLD DCHAR ;save next pos
XCHG ;put num of char left in H,L
SHLD DSKCNT ;save num of remaining char
JMP PBYT3 ;go check console status
;****************************************************************
; PUTREC
; WRITE OUT DISK BUFFER TO DISK
;
; 1. initialize start of disk buffer address and number
; of sectors to write out.
; 2. get current disk sector buffer address
; 3. add 128 to it and save for DMA of sector after
; current sector.
; 4. do DMA for current sector buffer address
; 5. write current disk sector
; 6. if not last sector repeat steps 2 thru 5.
; 7. set number of characters positions left in buffer
; to size of buffer.
; 8. set disk output buffer pointer to front of buffer.
; 9. go check to see if operator pressed control C.
;
;***************************************************************
PUTREC: LXI H,DISKBUF ;address of disk buffer
SHLD BUFADR ;save it for later DMA's
MVI B,OUTSECT ;number of disk sectors to write
PUTRC2: PUSH B ;save sector count
LHLD BUFADR ;get disk buffer address
XCHG ;put it in D,E for DMA
LXI H,80H ;put 128 H,L
DAD D ;add 128 to disk buf adr for next DMA
SHLD BUFADR ;save it for next DMA
MVI C,SETDMA ;point DMA to...
CALL CPM ;...correct buffer
LXI D,OFCB ;get output disk fcb
MVI C,WRITE ;write sector...
CALL CPM ;...to disk
ORA A ;was write successfull?
POP B ;restore num of sectors left
LXI D,EMSG4 ;get err msg in case write failed
JNZ FERR1 ;disk write failed, display err msg, quit
DCR B ;written 16 sectors yet?
JNZ PUTRC2 ;no, continue writing disk sectors
LXI H,OUTSECT*128 ;put disk buffer size into H,L
SHLD DSKCNT ;set num of char left in buf to buffer size
LXI H,DISKBUF ;point to front...
SHLD DCHAR ;...of disk buffer
JMP PBYT3 ;go check console status for ^C
;*********************************;
;
; ISSUE PAGE EJECT
;
;*********************************;
EJECT: MVI E,0CH ;printer eject command
CALL PBYT
MVI E,00H
MVI B,10
EJECT2: CALL PBYT ;PRINT 10 NULLS
DCR B
JNZ EJECT2
MVI A,00
STA LINES ;SET LINE COUNT
RET
;********************************;
;
; ISSUE CR, LF & TEST PAGE
;
;********************************;
CRLF: MVI E,0DH
CALL PBYT
MVI E,0AH
CALL PBYT
LDA LINES
INR A
STA LINES ;INCREMENT LINE COUNT
MVI A,LPAGE ;get number of lines
ORA A ;is it zero?
LDA LINES
RZ ;YES, RETURN
CPI LPAGE ;TEST LINE COUNT
CZ EJECT ;IF EQ TO LPAGE THEN NEW PAGE
RET
;********************************;
;
; CHARACTER PARSING TABLE
;
;********************************;
CTAB1: DB 0DH
DW LCR
DB 0AH
DW LLF
DB ''''
DW LQUOT
DB ';'
DW LSEMI
DB ' '
DW LSPC
DB 09H
DW LTAB
DB '$'
DW LDOL
DB '('
DW LDEL
DB ')'
DW LDEL
DB '+'
DW LDEL
DB '-'
DW LDEL
DB '*'
DW LSEMI
DB '/'
DW LDEL
DB ','
DW LDEL
DB ':'
DW LDEL
DB EOF
DW DONE
DB 0FFH
DW 0000H
EOF EQU 1AH ;EOF CODE
;********************************;
;
; RESERVED WORD TABLE
;
;********************************;
RTAB: DB 'A '
DB 'ACI '
DB 'ADC '
DB 'ADD '
DB 'ADI '
DB 'ANA '
DB 'AND '
DB 'ANI '
DB 'B '
DB 'C '
DB 'CALL '
DB 'CC '
DB 'CM '
DB 'CMA '
DB 'CMC '
DB 'CMP '
DB 'CNC '
DB 'CNZ '
DB 'CP '
DB 'CPE '
DB 'CPI '
DB 'CPO '
DB 'CZ '
DB 'D '
DB 'DAA '
DB 'DAD '
DB 'DB '
DB 'DCR '
DB 'DCX '
DB 'DI '
DB 'DS '
DB 'DW '
DB 'E '
DB 'EI '
DB 'ELSE '
DB 'END '
DB 'ENDIF'
DB 'ENDM '
DB 'EQU '
DB 'H '
DB 'HLT '
DB 'IF '
DB 'IN '
DB 'INR '
DB 'INX '
DB 'JC '
DB 'JM '
DB 'JMP '
DB 'JNC '
DB 'JNZ '
DB 'JP '
DB 'JPE '
DB 'JPO '
DB 'JZ '
DB 'L '
DB 'LDA '
DB 'LDAX '
DB 'LHLD '
DB 'LXI '
DB 'M '
DB 'MACRO'
DB 'MOD '
DB 'MOV '
DB 'MVI '
DB 'NOP '
DB 'NOT '
DB 'OR '
DB 'ORA '
DB 'ORG '
DB 'ORI '
DB 'OUT '
DB 'PAGE '
DB 'PCHL '
DB 'POP '
DB 'PSW '
DB 'PUSH '
DB 'RAL '
DB 'RAR '
DB 'RC '
DB 'RET '
DB 'RLC '
DB 'RM '
DB 'RNC '
DB 'RNZ '
DB 'RP '
DB 'RPE '
DB 'RPO '
DB 'RRC '
DB 'RST '
DB 'RZ '
DB 'SBB '
DB 'SBI '
DB 'SET '
DB 'SHL '
DB 'SHLD '
DB 'SHR '
DB 'SP '
DB 'SPHL '
DB 'STA '
DB 'STAX '
DB 'STC '
DB 'SUB '
DB 'SUI '
DB 'TITLE'
DB 'XCHG '
DB 'XOR '
DB 'XRA '
DB 'XRI '
DB 'XTHL '
DB 0FFH ;END OF RESERVED WORD TABLE
RSIZ EQU 05 ;SIZE OF TABLE ENTRY
;********************************;
;
; MISCELLANEOUS DATA
;
;********************************;
MSG1: DB 'DISK CROSS REFERENCE FILE EXISTS - ERASE IT(Y/N)?','$'
EMSG0: DB '++ERROR++ INPUT FILE DOES NOT EXIST', 0DH, 0AH, '$'
EMSG1: DB 'SYMBOL TABLE ERROR',0DH,0AH,'$'
EMSG2: DB 'FAILED TO DELETE EXISTING CROSS REFERENCE FILE',0DH,0AH,'$'
EMSG3: DB 'FAILED TO CREATE CROSS REFERENCE FILE',0DH,0AH,'$'
EMSG4: DB 'DISK WRITE FAILED - OUT OF SPACE?',0DH,0AH,'$'
EMSG5: DB 'CLOSE FAILED ON DISK CROSS REFERENCE FILE',0DH,0AH,'$'
EMSG6: DB '++ERROR++ NOT ENOUGH MEMORY FOR SYMBOL TABLE',0DH,0AH,'$'
EMSG7: DB '++ERROR++ SYMBOL TABLE OVERFLOW',0DH,0AH,'$'
LOGO: DB 0Dh,0Ah,'CPM ASSEMBLER CROSS REFERENCE LIST Ver 1.41',0Dh,0Ah,'$'
DONEMSG: DB 'CROSS REFERENCE LIST IS DONE',0DH,0AH,'$'
NOSYMS: DB 'NO SYMBOLS IN THIS PROGRAM'
CONCRLF DB 0DH,0AH,'$'
SSIZ EQU SYMSIZ+3 ;SYMBOL TABLE ENTRY SIZE
SYMBT: DS 2 ;SYMBOL TABLE BOTTOM ADDRESS
SYMTP: DS 2 ;SYMBOL TABLE TOP ADDRESS
REFBT: DS 2 ;REFERENCE TABLE BOTTOM ADDRESS
REFTP: DS 2 ;REFERENCE TABLE TOP ADDRESS
SYM: DS 2 ;CURRENT SYMBOL TABLE ADDRESS
REFSZ EQU 2+(NREFS*2) ;NUMBER OF BYTES IN REF BLOCK
REF: DS 2 ;CURRENT REFERENCE TABLE ADDRESS
FROM: DS 2 ;MOVE POINTER
TO: DS 2 ;TO POINTER
LIMIT: DS 2 ;LIMIT POINTER
COL: DS 1
CHAR: DS 1
LCNT: DS 2 ;LINE COUNTER
LPNT: DS 2
DEC: DS 5
DB 0DH
PBUF: DS 132
SYMCT: DS 1
SYMPT: DS 2
SBUF: DS SYMSIZ ;SYMBOL BUFFER
NLINS: DB 0 ;BUFFERS TO PRINT ON LINE
LINES: DB 0 ;PRINT LINE COUNT
;********************************;
;
; OPERATING SYSTEM EQUATES
;
;********************************;
BOOT EQU 0000H ;REBOOT ENTRY POINT
CPM EQU 0005H ;CPM ENTRY POINT
MEMSZ EQU 0006H ;END OF MEMORY POINTER
TFCB EQU 005CH ;TRANS. FCB
CONIN EQU 01 ;CONSOLE INPUT FUNCTION CODE
PSTRING EQU 09 ;PRINT STRING FUNCTION CODE
OPEN EQU 15 ;OPEN FUNCTION CODE
CLOSE EQU 16 ;CLOSE FILE FUNCTION CODE
DELETE EQU 19 ;DELETE FILE FUNCTION CODE
READ EQU 20 ;READ DISK FUNCTION CODE
WRITE EQU 21 ;WRITE DISK FUNCTION CODE
MAKE EQU 22 ;MAKE FILE FUNCTION CODE
SETDMA EQU 26 ;SET DMA FUNCTION CODE
;********************************;
; F O P E N ;
; ROUTINE TO OPEN A DISK FILE ;
; ;
; INPUT: DE=A(FCB) ;
;********************************;
FOPEN: MVI C,OPEN ;OPEN CODE
CALL CPM ;ISSUE OPEN
CPI 0FFH ;ERROR?
RNZ ;NO ERROR
LXI D,EMSG0
JMP FERR1
;********************************;
; ;
; ROUTINE TO CLOSE OUTPUT DISK ;
; CROSS REFERENCE FILE ;
; INPUT: DE=ADDR(FCB) ;
; HL=ADDR(BUFFER) ;
;********************************;
DCLOSE: PUSH D ;save fcb address
PUSH H ;save buffer address
LHLD DSKCNT ;put number of char left...
XCHG ;...in buffer into D,E
LHLD DCHAR ;point to next char in output buf
MVI A,1AH ;put a control Z in accum
DCLSE2: MOV M,A ;fill...
INX H ;...rest of...
DCR E ;...buffer...
JNZ DCLSE2 ;...with...
DCR D ;...control Z's.
JNZ DCLSE2
POP H ;point to...
DCLSE4: XCHG ;...output buffer
LXI H,128 ;put 128 into H,L
DAD D ;add 128 to disk buf addr for next DMA
SHLD BUFADR ;save it for next DMA after this one
MVI C,SETDMA ;...disk buffer for...
CALL CPM ;...last disk write
POP D ;do last...
PUSH D ;....(D,E contains OFCB)...
MVI C,WRITE ;...disk...
CALL CPM ;...write
;Check to see if last record has been written. Do this by comparing
;address of next available char to address of buffer for next disk write.
;If address of next available char is equal or greater, close file.
LHLD DCHAR ;put high order address
XCHG ;...of last char+1...
MOV A,D ;...into ACCUM
LHLD BUFADR ;get addr of next disk buffer
CMP H ;compare to last char+1 in buffer
JC DCLSE5 ;if next addr is greater, close file
JNZ DCLSE4 ;if not equal, continue
MOV A,E ;put low order address of last char+1
CMP L ;into accum and test
JNC DCLSE4 ;if not less, do another write
DCLSE5: POP D ;close the...(D,E contains OFCB)
MVI C,CLOSE ;...output disk
CALL CPM ;...cross ref file
CPI 0FFH ;close successfull?
RNZ ;yes, return
LXI D,EMSG5 ;no, display error msg...
JMP FERR1 ;... and quit
;********************************;
; G E T B T ;
; ROUTINE TO READ A BYTE ;
; ;
; OUTPUTS: A=BYTE ;
; ;
; 1. is current byte pointer at ;
; end of buffer? ;
; -yes, Read disk records ;
; into buffer. ;
; 2. move character from buffer ;
; to ACCUM. ;
; 3. add 1 to character pointer ;
; and save pointer. ;
; 4. return to caller ;
; ;
;********************************;
GETBT: LXI H,TBUF+(INSECT*128);end of input buf addr
XCHG ;BUFFER END ADDR. IN DE
LHLD INPTR ;CURRENT POINTER IN HL
CALL CPHL ;TEST FOR END OF BUFFER
CZ GETREC ;YES, READ DISK RECORDS
MOV A,M ;GET BYTE
INX H ;BUMP POINTER
SHLD INPTR ;SAVE POINTER
ORA A ;CLEAR CARRY
RET ;RETURN CARRY RESET
;***********************************************************
; GETREC
;Read the number of input records specified by INSECT. The
;buffer starts at TBUF. Before each DMA, the buffer address
;is incremented by 128 and saved in IDADDR. This address
;will be used for the DMA after the current sector is read.
;The logic is:
; 1. get current buffer address
; 2. add 128 to it and save it
; 3. issue DMA for current buffer address
; 4. read the disk record,
; -if end of file goto step 7.
; 5. decrement number of sectors to read
; 6. if not number of sectors not zero
; -repeat above
; 7. reset character pointer to first buffer
; 8. return to caller.
;***********************************************************
GETREC: MVI B,INSECT;number of sectors to read
LXI H,TBUF ;get address of disk input buffer
SHLD IDADDR ;initialize current buffer address
GETRC2: LHLD IDADDR ;get addr of input buffer
XCHG ;put it in D,E
LXI H,128 ;add 128 to input buf
DAD D ;...addr for read after next
SHLD IDADDR ;save it read after next
PUSH B ;save sector count
PUSH D ;save current buf ptr in case EOF occurrs
MVI C,SETDMA;POINT TO INPUT BUFFER...
CALL CPM
MVI C,READ ;READ CODE
LXI D,TFCB ;FCB ADDRESS
CALL CPM ;ISSUE READ
POP D ;restore current buf pointer
POP B ;restore sector count
CPI 00 ;ERROR?
JNZ GETRC4 ;YES
DCR B ;read all of the sectors?
JNZ GETRC2 ;no, continue reading
GETRC3: LXI H,TBUF ;RESET BUFFER POINTER
SHLD INPTR
RET ;RETURN TO CALLER
GETRC4: XCHG ;POINT TO FIRST CHAR PAST BUF
MVI M,26H ;PUT TWO...
INX H ;...CONTROL Z's
MVI M,26H ;...AFTER LAST REC IN FILE
JMP GETRC3 ;GO RESET BUFFER POINTER
;********************************;
; CONVERTS LOWER TO UPPER CASE ;
; INPUT: A=BYTE(upper/lower;
; OUTPUTS: A=BYTE UPPER ;
;********************************;
lwrupr: cpi 'A'+20h ;is it upper case?
cmc ;complement carry
rnc ;yes, return with carry reset
Cpi 'Z'+21h ;over lower case 'Z'?
rnc ;no, return no carry
sui 20h ;convert to upper case
ret
;********************************;
; MISCELLANEOUS SUBROUTINES ;
;********************************;
;********************************;
; C P H L ;
; ROUTINE TO COMPARE HL VS DE ;
; OUTPUT: HL=DE, ZERO=ON ;
; HL<>DE, ZERO=OFF ;
;********************************;
CPHL: MOV A,H
CMP D
RNZ
MOV A,L
CMP E
RET
;********************************;
; D A T A ;
;********************************;
OFCB: DB 0 ;disk output fcb, default drive
DS 8 ;file name
DB 'XRF' ;file type
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
DCHAR: DW DISKBUF ;pointer for disk buffer
BUFADR: DS 2 ;pointer to disk output buffer for DMA
IDADDR: DS 2 ;POINTER TO DISK INPUT BUFFER FOR DMA
DSKCNT: DW OUTSECT*128 ;number of char left in disk buffer
INPTR: DW TBUF+(INSECT*128);POINTER TO CHAR IN INPUT BUFFER
DISKBUF DS OUTSECT*128 ;output disk buffer
TBUF: DS INSECT*128 ;DISK INPUT BUFFER
EOFCHR: DB 26H,26H ;control Z's in case last block is
;filled with data
CONSOLE DB 0 ;console output switch
DISKOUT DB 0 ;disk output switch
FTPRN: DB 1 ;prn file type
TEMP: DS 2 ;TEMP SAVE WORD
DS 64 ;stack contains 32 words
STACK EQU $
;***********************************************
;
; SYMBOL TABLE AREA
;
; THE SYMBOL TABLE MUST BE THE
; LAST BYTE BEFORE THE HELP MESSAGE
;
;***********************************************
ORG ($ AND 0FFF0H) + 10H ;FORCE 16 BYTE BOUNDARY
SYMT: DB 0FFH
HELP: DB 0DH,0AH,'This program can be used to'
DB ' create a cross reference listing',0DH,0AH
DB 'of CPM assembler programs.'
DB ' The input can be either the assembler',0DH,0AH
DB 'language source code(FN.ASM) or the assembly listing(FN.PRN).',0DH,0AH
DB 'The output can be printed on the CPM list device, displayed on',0DH,0AH
DB 'the console, or written to disk(file type will be XRF). It is',0DH,0AH
DB 'invoked by keying:',0DH,0AH,0AH
DB 09H,'XREF FN.ASM (OUTPUT ON LIST DEVICE)',0DH,0AH
DB 09H,'XREF FN.PRN CON (OUTPUT ON THE CONSOLE)',0DH,0AH
DB 09H,'XREF FN.ASM D (OUTPUT ON DISK-DEFAULT DRIVE)',0DH,0AH
DB 09H,'XREF FN.PRN B:D (OUTPUT ON DISK-DRIVE SPECIFIED)',0DH,0AH,'$'
END