home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
cpm
/
utils
/
asmutl
/
xref241.lbr
/
XREF241.AQM
/
XREF241.ASM
Wrap
Assembly Source File
|
1985-02-09
|
31KB
|
1,352 lines
; TITLE XREF.ASM VER 2.41 01/30/83
;
; for assembly with LASM.COM
;
; cross reference program
; for asm and mac files
;
; version 2.41
;
; jeff kravitz
;
; modified by john mahr
; ray malitzke z80, m80
;
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 01 ;number of disk sectors written from buffer
INSECT EQU 08 ;number of disk sectors read into buffer
;
; main loop
;
; ASEG
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: 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 or initialization
;
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)
;
;
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
;
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 '8080 '
DB 'A '
DB 'ACI '
DB 'ADC '
DB 'ADD '
DB 'ADI '
DB 'AF '
DB 'ANA '
DB 'AND '
DB 'ANI '
DB 'ASEG '
DB 'B '
DB 'BC '
DB 'BIT '
DB 'C '
DB 'CALL '
DB 'CC '
DB 'CCF '
DB 'CM '
DB 'CMA '
DB 'CMC '
DB 'CMP '
DB 'CNC '
DB 'CNZ '
DB 'COMME'
DB 'COMMO'
DB 'COND '
DB 'CP '
DB 'CPD '
DB 'CPDR '
DB 'CPE '
DB 'CPI '
DB 'CPL '
DB 'CPO '
DB 'CSEG '
DB 'CZ '
DB 'D '
DB 'DAA '
DB 'DAD '
DB 'DB '
DB 'DC '
DB 'DCR '
DB 'DCX '
DB 'DE '
DB 'DEC '
DB 'DEFB '
DB 'DEFL '
DB 'DEFM '
DB 'DEFW '
DB 'DI '
DB 'DJNZ '
DB 'DS '
DB 'DSEG '
DB 'DW '
DB 'E '
DB 'EI '
DB 'ELSE '
DB 'END '
DB 'ENDC '
DB 'ENDIF'
DB 'ENDM '
DB 'ENTRY'
DB 'EQ '
DB 'EQU '
DB 'EX '
DB 'EXX '
DB 'EXITM'
DB 'EXT '
DB 'EXTRN'
DB 'GE '
DB 'GLOBA'
DB 'GT '
DB 'H '
DB 'HL '
DB 'HIGH '
DB 'HALT '
DB 'IF '
DB 'IFB '
DB 'IFDEF'
DB 'IFE '
DB 'IFF '
DB 'IFNB '
DB 'IFNDE'
DB 'IFT '
DB 'IF1 '
DB 'IF2 '
DB 'IM '
DB 'IN '
DB 'INC '
DB 'INCLU'
DB 'IND '
DB 'INDR '
DB 'INIR '
DB 'INR '
DB 'INX '
DB 'IRP '
DB 'IRPC '
DB 'IX '
DB 'IY '
DB 'JC '
DB 'JM '
DB 'JMP '
DB 'JNC '
DB 'JNZ '
DB 'JP '
DB 'JPE '
DB 'JPO '
DB 'JR '
DB 'JZ '
DB 'L '
DB 'LALL '
DB 'LD '
DB 'LDA '
DB 'LDAX '
DB 'LDD '
DB 'LDDR '
DB 'LDI '
DB 'LDIR '
DB 'LE '
DB 'LHLD '
DB 'LIST '
DB 'LOCAL'
DB 'LOW '
DB 'LT '
DB 'LXI '
DB 'M '
DB 'MACRO'
DB 'MOD '
DB 'MOV '
DB 'MVI '
DB 'NAME '
DB 'NC '
DB 'NE '
DB 'NEG '
DB 'NOP '
DB 'NOT '
DB 'NUL '
DB 'NZ '
DB 'OR '
DB 'ORA '
DB 'ORG '
DB 'ORI '
DB 'OTDR '
DB 'OTIR '
DB 'OUT '
DB 'OUTI '
DB 'OUTD '
DB 'PAGE '
DB 'PCHL '
DB 'P '
DB 'PE '
DB 'PO '
DB 'POP '
DB 'PRINT'
DB 'PSW '
DB 'PUBLI'
DB 'PUSH '
DB 'RADIX'
DB 'RAL '
DB 'RAR '
DB 'RC '
DB 'REPT '
DB 'RES '
DB 'RET '
DB 'RETI '
DB 'RL '
DB 'RLA '
DB 'RLC '
DB 'RLCA '
DB 'RLD '
DB 'RM '
DB 'RNC '
DB 'RNZ '
DB 'RP '
DB 'RPE '
DB 'RPO '
DB 'RR '
DB 'RRA '
DB 'RRC '
DB 'RRCA '
DB 'RRD '
DB 'RST '
DB 'RZ '
DB 'SALL '
DB 'SBB '
DB 'SBC '
DB 'SBI '
DB 'SCF '
DB 'SET '
DB 'SHL '
DB 'SHLD '
DB 'SHR '
DB 'SLA '
DB 'SP '
DB 'SPHL '
DB 'SRA '
DB 'SRL '
DB 'STA '
DB 'STAX '
DB 'STC '
DB 'SUB '
DB 'SUBTT'
DB 'SUI '
DB 'TITLE'
DB 'XALL '
DB 'XCHG '
DB 'XLIST'
DB 'XOR '
DB 'XRA '
DB 'XRI '
DB 'XTHL '
DB 'Z '
DB 'Z80 '
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 2.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
;
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
;
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 $ ;10h + (0fff0h and $) ;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 XREF