EdAsm/EDASM.SRC/LINKER/linker.aii

1 line
108 KiB
Plaintext

LINK_S_P1 PROC ORG $2000
; ### COMMENT - MACRO to create STR/.STRING directive equivalence.
; Remove this MACRO if the file M16.UTIL is ever INCLUDED.
MACRO
STR &string
LCLC &sset
&sset SETC &SETTING('STRING')
STRING PASCAL
DC.B &string
STRING &sset
MEND
; AsmIIGS directives to set equivalent 6502/65C02 mode.
MACHINE M6502
LONGA OFF
LONGI OFF
; This EdAsm/Asm816 source code file was converted to AsmIIGS
; by EdAsmCvtIIGS version 1.2 on 4/4/12 at 7:22:42 AM
INCLUDE 'equates.aii'
FileDataBufSiz EQU $2000-srcDataBuf ;20 mempages=5K
;
; Initial code disassembled with the ORCA.DisAsm
; Source files for the Linker is of type REL
; The Linker can produce BIN, REL or SYS object files
;
; Init the Linker
LinkerEntry
LDX #0
STX LinkerEntry ;Ensure a fresh copy is loaded
PHP ;Save status reg
PLA
STA SaveA
SEI ;Don't interrupts please
LDA #0
@loop STA STACK,X ;Zero 6502 H/W stack
INX
BNE @loop
DEX
TXS ;=$FF
LDA SaveA
PHA ;RESTORE status reg
PLP
LDA #$00
STA MINIVERS ;minimum interpreter version
LDA #$10
STA IVERSION ;interpreter version
LDA #%00000011 ;reserve Pages 6-7
STA MemoryMap
; setup memory map
LDA #%10101000
AND #%00000111
TAX ;(X)=0
LDY #0
TYA ;(A)=0
@loop1 ORA BitsTab,Y
INY
DEX
BPL @loop1
EOR #$FF ;(A)=%01111111
LDX #$15
AND MemoryMap,X ;Mark page $A8
STA MemoryMap,X ; as free
LDA #$00
DEX
@zloop STA MemoryMap,X ;Pages $08-$A7
DEX ; are free
BNE @zloop
; Init various flags & variables
LDA #$80 ;Set the following
STA MapOption ; options to ON
STA SortOption
STA XRefOption
STA EntryRefOption
LDA #$00 ;Set the following
STA PageOption ; options to OFF
STA Option_D ;reserved for future
STA IsOptions
STA WhichType
STA IsNumSort
STA Origin ;Zero this
STA Origin+1
LDA #1
STA LineCnt
STA PageCnt
; Try to open a default command (TXT) file named "EDASM.AUTOLINK"
LDY AUTOLNKS
@cploop LDA AUTOLNKS,Y
STA pathNameBuf,Y
DEY
BPL @cploop
JSR PRODOS8
DC.B $C8 ;OPEN
DC.W OpenCmdRecP8
BEQ DoPhase0
CMP #$46 ;fileNotFound?
BNE NoGood ;some other errors
BEQ FnotF
ShowErr JSR PrintError ;(A)=err code, don't come back
FnotF LDY #$00 ;Print Banner & prompt
JSR DisplayMsg ; for command filename
LDA #'?'+$80
STA PROMPT
JSR GetLine ;Use monitor's input rtn to get filename
STX pathNameBuf ;Save len byte
LDA InBuf ;Did user choose to Abort
CMP #CTRLC+$80 ; the linking process?
BNE @cloop2
JMP Abort ;Yes
@cloop2 LDA InBuf,X ;Copy the filename
AND #$7F ; typed in & ensure all
STA pathNameBuf+1,X ; its chars are std ASCII
DEX
BPL @cloop2
JSR PRODOS8
DC.B $C8 ;OPEN
DC.W OpenCmdRecP8
BEQ DoPhase0
CMP #$40 ;badPathSyntax
BEQ ShowErr
CMP #$44 ;pathNotFound
BEQ ShowErr
CMP #$45 ;volNotFound
BEQ ShowErr
CMP #$46 ;fileNotFound
BEQ ShowErr
NoGood JSR ErrHandler ;Don't come back
;=================================================
; Phase 0: Setup environment for the Linker
; Each record in the Command File is a CR-terminated text line (msb off)
; Each text line is either
; a command to the Linker or
; the pathname of a source file of type REL
; Directives/Commands to the Linker must be preceded by
; at least 1 space while pathnames have no leading space(s)
; ($20C7)
DoPhase0
LDA OpenCmdRecP8+C_OUTREF ;Copy this to the fields
STA MarkCmdRecP8+C_REFNUM ; of other ProDOS parameter
STA NewLineRecP8+C_REFNUM ; blocks b4 we start to read
STA ReadCmdRecP8+C_REFNUM ; the CMD file line by line
; Ensure that all future READ operations on the Command
; File is terminated by a CR or an EOF
JSR PRODOS8
DC.B $C9 ;NEWLINE
DC.W NewLineRecP8
BNE NoGood
LDA #BIN_type ;Default OBJECT filetype
STA TargetObjType
LDY #$03 ;Display "Phase0: Commands..."
JSR DisplayMsg
JSR DisplayCR
; This loop only processes directives & ignores the pathnames
@mainlp JSR AbortPause
JSR ReadOneCmd ;Is 1st char a CR/SPACE?
BNE NOTCMD ;No, it's a PN of a src (REL) file
JSR ShowLineBuf ;Show cmd
CMP #CR
BNE @1 ;1st char not CR => SPACE
JMP CmdFileErr ;CR => null cmd line
@1 JSR SkipSpaces
JSR ChkDirective ;Is it a directive?
BCS @mainlp ;Not valid, ignore
PHA ;index into JMP table
JSR WhiteSpc
JSR AdvCP ;Ensure cp is @ 1st char of directive
PLA
JSR HandleDirective ;Process directive
JMP @mainlp ;Next directive
; If 1st char is not CR/SPACE, then it is a pathname of a SRC file
NOTCMD BIT MapOption ;Output a LinkMAP? (default is ON)
BPL @exit ;No
JSR OpenLinkMap ;Open LINKMAP file for output
@exit JMP DoPhase1
;=================================================
; JMP via an RTS to parse the operand field of a directive
HandleDirective
TAX
LDA CmdTabHi,X ;Directive JMP table
PHA
LDA CmdTabLo,X
PHA
RTS
;=================================================
; BIN command/directive
; Input
; WhichType=0 OBJECT file type not set
; Output
; WhichType=1
; TrgtFTyp=BIN
; NB. Only one BIN/REL/SYS directive may be declared
CmdBIN LDA WhichType ;Has the OBJ type been set?
BEQ @1 ;No
JMP DupCmdErr
@1 LDA #$01
STA WhichType ;Flag it's set
LDA #BIN_type
STA TargetObjType
JSR GetObjPathName ;Get Link OBJ/MAP filenames
RTS
;=================================================
; REL command/directive
; Input
; WhichType=0
; Output
; WhichType=$80
; TrgtFTyp=REL
CmdREL LDA WhichType
BEQ @1
JMP DupCmdErr
@1 LDA #$80
STA WhichType
LDA #REL_type
STA TargetObjType
JSR GetObjPathName
RTS
;=================================================
; SYS command/directive
; Input
; WhichType=0
; Output
; WhichType=$02
; TrgtFTyp=SYS
CmdSYS LDA WhichType
BEQ @1
JMP DupCmdErr
@1 LDA #$02
STA WhichType
LDA #SYS_type
STA TargetObjType
JSR GetObjPathName
RTS
;=================================================
; ORG command/directive
; Input
; Output
; Origin=Value of Expression
; NB. Only 1 ORG may be declared and it must be b4
; any SRC pathnames
CmdORG LDA Origin ;Already set?
ORA Origin+1
BEQ @1
JMP DupCmdErr ;Yes -> duplicate cmd
@1 JSR SkipSpaces
JSR ChrGot
BEQ BADORG ;if sp/cr, error
JSR EvalExpr
LDA Value16 ;Chk it's valid
STA Origin
LDA Value16+1
BEQ BADORG ;if < $0100
STA Origin+1
ORA Origin
BEQ BADORG ; or $0000
RTS
BADORG JMP CmdSynErr ;syntax err
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ALN Command/Directive
; Align Origin @ start of next mempage
; Output
; Origin=$xx00
;
; This directive is usually used after a pathname
; and may be used repeatedly
;
CmdALN LDA Origin ;ORG must be set first either by a
ORA Origin+1 ; directive or via SRC file
BNE @1
JMP WrongOrder ;Wrong cmd order
@1 LDA Origin ;Align @ the beginning
BEQ @exit
INC Origin+1 ; of the next mempage
LDA #$00
STA Origin
@exit RTS
;=================================================
; OPT command/directive. Only allowed to be used once
; Default
; OPT +M,+E,+S,+X,-N,-D,-P
; Input
; IsOptions
; Output
; IsOptions=1 - If Directive not declared
;
; One/Some/All of the following flags may be set
; M)apFile - Output LinkMAP file (default ON)
; E)Ref - Add ENTRY records (default ON)
; S)ortLM - Sort LoadMap table (default ON)
; X)Ref - Cross-referenced (default ON)
; N)umSort - Sort LoadMap numerically (default OFF)
; O)ptD - not used (default OFF)
; P)age - Pagination (default OFF)
; ($21A4)
CmdOptions
LDA IsOptions ;First time the directive is declared?
BEQ @1 ;Yes
JMP DupCmdErr ;Duplicate cmd
@1 INC IsOptions ;Flag we have encountered this cmd
JSR SkipSpaces ;Prepare to look at the operand field
@doloop JSR ChrGot
BEQ @ret ;cr/space
CMP #'+' ;ON switch flag?
BNE @off ;No
LDA #$80
STA SWITCH ;flag it is ON
BNE @which ;always
@off CMP #'-'
BNE @bad
LDA #$00 ;OFF
STA SWITCH
@which JSR ChrGet ;Get char after switch flag
BEQ @bad ;It's a cr/space
LDX #0
@cmplup CMP OptionsTab,X
BEQ @gothit
INX
CPX #7
BCC @cmplup
@bad JMP OptionError ;Invalid option/option syntax
@gothit LDA SWITCH
STA OptFlagsTab,X ;$A2-$A8
@skip JSR ChrGet ;Get char
BEQ @ret ;cr/space
CMP #',' ;delimiter
BNE @skip ;ignore all others
INY ;SKIP comma
JMP @doloop ;Loop back for another option
@ret RTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Parse for the pathnames of the OBJ file and LINKMAP txt file.
; Full and partial pathnames are accepted. If there is no
; operand field following the BIN/REL/SYS directive/cmd then
; default filenames are used.
;
; Output
; LinkObjName buf
; ($21ED)
GetObjPathName
JSR SkipSpaces
@cloop JSR ChrGot
BEQ @ws ;cr/space
JSR ChkChar ;Is char valid?
BNE @1 ;No
INY
STA LinkObjName,Y
BNE @cloop
@1 CMP #CR ;Is it a CR?
@ws PHP ;save comparison status
CPY #0 ;Is there an operand?
BEQ @2 ;No
STY LinkObjName ;Len byte
@2 PLP
BEQ @ret ;Yes, it's a CR, so done
CMP #',' ;Check for the delimiter
BNE @FnotF ;Not found
LDX #0
INY ;SKIP the comma
@sloop JSR ChrGot
BEQ @gotws ;cr/space
JSR ChkChar ;Is char valid?
BNE @FnotF ;No, err
INX
INY
STA LinkMapName,X
BNE @sloop
@gotws CPX #0 ;If no user-defined LINKMAP file,
BEQ @ret ; specified use default name
STX LinkMapName ;Len byte
@ret RTS
@FnotF LDA #$40 ;badPathSyntax
JSR ErrHandler ;Don't come back
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Check if a char is valid
; Valid chars are: / . 0-9 A-Z
; Input
; (A)=ascii char
; Output
; Z=1 if char is valid
; ($2232)
ChkChar
CMP #'/'
BEQ @ret
CMP #'.'
BEQ @ret
JSR IsCharDec ;Is it a decimal digit?
BCC @valid ;Yes
CMP #'A'
BCC @ret
CMP #'Z'+1
BCC @valid
CMP #'A'
RTS
@valid STA PROMPT
CMP PROMPT ;Ensure Z=1
@ret RTS
;=================================================
; Copy default OBJECT file name to the PathName buf
; ($224F)
MoveObjName
LDY LinkObjName
@mvLup LDA LinkObjName,Y
STA pathNameBuf,Y
DEY
BPL @mvLup
RTS
;===============================
; Copy default LINKMAP file name to the PathName buf
; ($225C)
MoveMapName
LDY LinkMapName
@mvLup2 LDA LinkMapName,Y
STA pathNameBuf,Y
DEY
BPL @mvLup2
RTS
;===============================
; Open for new LINKMAP text file for writing
; Input
; Output
; ($2269)
OpenLinkMap
JSR MoveMapName ;Set PN to LINKMAP's
JSR PRODOS8 ;Kill the old copy (if any)
DC.B $C1
DC.W DestroyRecP8 ;DESTROY
JSR PRODOS8
DC.B $C0 ;CREATE
DC.W CreateMapRecP8
BNE @Err
JSR PRODOS8
DC.B $C8 ;OPEN
DC.W Open2RecP8
BEQ @NoErrs
@Err JSR ErrHandler ;Don't come back
@NoErrs LDA Open2RecP8+C_OUTREF
STA WriteMapRecP8+C_REFNUM
LDA #0
STA MapIndex ;Double as # of bytes to write
STA MapIndex+1 ;HOB=Always 0
RTS
;=================================================
; Using info fr the ESD (if any) of the SRC files,
; build 3 arrays called ENTRY, EXTRN & SymbolicName tables.
; entRecP - Point to an element of the ENTRY table of 24-byte records
; xtrnRecP - Point to an element of the EXTRN table of 8-byte records
; symP - Point to an element of the SymbolicName table of 16-byte records
; ModuleNbr - src file # assigned during processing
; CurrORG - starting PC of current src file
; ($2294)
DoPhase1
LDY #$04 ;Building ENTRY/EXTERN tables
JSR DisplayMsg
JSR DisplayCR
LDY #$04
JSR StoreMsgY ;Store same msg to LINKMAP
LDA #<EntryTab
STA entRecP ;array of ENTRY recs @ $4700
LDA #>EntryTab
STA entRecP+1
LDA #<xternTab ;array of XTRN recs @ $7100
STA xtrnRecP
LDA #>xternTab
STA xtrnRecP+1
LDA #<symbolTab ;array of SymbolicName recs @ $9200
STA symP
LDA #>symbolTab
STA symP+1
LDA #0
STA ModuleNbr ;start w/module 0
LDA Origin
STA CurrORG
LDA Origin+1
STA CurrORG+1
JMP Phs11
; Process a SRC file. The only directive allowed
; is ALN which instructs the Linker to adjust
; the PC to the start of next mem page
Phs1Loop
JSR AbortPause
JSR ReadOneCmd
BNE Phs11 ;Not a cr/space => we've a PN
CMP #CR
BEQ GoPhase2 ;Empty line -> no more cmds
JSR IsAlign ;Is it an ALN directive?
BCC @1 ;Yes -> align mem
JMP DoBreak ;Abort!
@1 BEQ @2 ;ALN option
JMP WrongOrder ;No, invalid cmd order
@2 LDA CurrORG ;Already @ a mempage bdry?
BEQ Phs1Loop ;Yes
INC CurrORG+1 ;Next mempage
LDA #$00
STA CurrORG
BEQ Phs1Loop ;always
GoPhase2 JMP DoPhase2
; The name of a SRC file is already in CmdLine buffer
; Open the SRC file and setup some variables
; using the info fr the opened SRC file.
;
; CmdLineBuf - Pathname of SRC file
; entRecP - ptr to a rec of ENTRY array
; xtrnRecP - ptr to a rec of EXTRN array
; symP - ptr to a rec of SymbolicName array
;
; Origin - ORG of 1st SRC file (if not) set by an ORG directive
; CurrORG - Starting PC assigned to curr SRC file
; MarkSrcRecP8+c.mark - file posn of source file
; srcP - pointer into a chunk of source file
;
; Z80 - End of chunk of RLD data read
; Z82 - Start of RLD data read
Phs11 JSR ShowLineBuf
JSR OpenSrcFile ;Open SRC file and get info
BCC Phs12
JSR ErrHandler ;Don't come back
Phs12 LDA Origin ;Was it set?
ORA Origin+1
BNE ORGset ;Yes
LDA srcORG ;Use the ORG as recorded
STA Origin ; in the FIRST SRC file
STA CurrORG ; as our Origin & use it as
LDA srcORG+1 ; the starting PC as well
STA Origin+1 ;NB. Once set, it will remain unchanged
STA CurrORG+1 ; throughout linking process
ORGset LDA #2
CLC
ADC srcCodeLen ;Len of code image
STA MarkSrcRecP8+C_MARK ;Set file posn to SRC file's
LDA #0 ; relocation dictionary (RLD)
ADC srcCodeLen+1
STA MarkSrcRecP8+C_MARK+1 ; which is just after the code image
LDA OpenSrcRecP8+C_OUTREF
STA MarkSrcRecP8+C_REFNUM
JSR PRODOS8
DC.B $CE ;SET_MARK
DC.W MarkSrcRecP8
BNE GotErr2
JSR ReadMax ;Read max chunk of RLD/ESD
BCC FinalData ;=> The entire RLD/ESD was read
CMP #$10 ;Did we encounter an EOF?
BEQ MoreData ;No, more data chunks
GotErr2 JSR ErrHandler ;(A)=$4C, so let EI takes care of it
; A fixed chunk (of 5K) had been read so there may be more
; data to be read. There seems to be no provision dealing
; with files in which the END of RLD is not within
; the first 5K of RLD/ESD data i.e. the RLD is very big.
; The code below doesn't seem to be able to handle this
; situation. Is there a bug here?
; The code below will never be executed if sizeof RLD+ESD < 5K
MoreData
JSR GetEndRLD ;Scan for end of RLD
LDA srcP+1 ;Is srcP still at the BO
CMP #>srcDataBuf ; the srcfile data buffer?
BNE SizeChk ;No
LDA srcP ;(Shouldn't srcP be compared to $2000?)
CMP #<srcDataBuf ; which is EO srcDataBuf+1
BNE SizeChk
BigESD JMP RLDESDErr ;SRC file's ESD too large
; This code is only executed if the size of the RLD is less
; than the size of the srcDataBuf located @ $0C00 (which is 5K)
; srcP is pointing @ EO RLD
SizeChk LDA #<srcDataBuf ;START addr
CLC
ADC RWFileRecP8+C_TRANSCNT ;Actual # of bytes read
STA Z80 ;Point @ EO data chunk + 1
LDA #>srcDataBuf
ADC RWFileRecP8+C_TRANSCNT+1 ; (or EO file data buf + 1=$2000)
STA Z80+1 ;END addr
LDA #<srcDataBuf
STA Z82 ;DEST addr
LDA #>srcDataBuf
STA Z82+1
; Calc the size of ESD data in FileData buf
; The code below is definitely buggy.
LDA Z80
SEC
SBC srcP ;Pointing @ EO RLD
STA RWFileRecP8+C_TRANSCNT ;=len of ESD already in buf + 1 (EO RLD marker)
LDA Z80+1 ;(should srcP be incr 1 more?)
SBC srcP+1
STA RWFileRecP8+C_TRANSCNT ;Bug! Should be sta RWFileRecP8+c.transCnt+1
; Move ESD block forward in filedata buf (incl EO RLD marker)
JSR MoveData
LDA #<srcDataBuf ;Prepare to append more ESD data
CLC
ADC RWFileRecP8+C_TRANSCNT ; fr src file by reading 'em
STA RWFileRecP8+C_DATABUF ; into this starting location
LDA #>srcDataBuf
ADC RWFileRecP8+C_TRANSCNT ;Bug! Should be adc RWFileRecP8+c.transCnt+1
STA RWFileRecP8+C_DATABUF+1
; Calculate # of bytes to be read in
; order to fill the rest of FileData
; buf with more ESD records
LDA #<FileDataBufSiz
SEC
SBC RWFileRecP8+C_TRANSCNT
STA RWFileRecP8+C_REQCNT ;=$1400-(# of bytes of
LDA #>FileDataBufSiz
SBC RWFileRecP8+C_TRANSCNT+1 ; data currently in mem)
STA RWFileRecP8+C_REQCNT+1
JSR GetMoreCode ;Attempt to read another chunk
BCC FinalData ;Last chunk so that's ok
CMP #$10 ;More data on disk?
BEQ BigESD ;Yes, ESD too large
BNE GotErr2 ;Always-error
; Last chunk of RLD/ESD data had been read
; The code below seems ok
FinalData
JSR GetEndRLD ;Point to end of RLD
LDA OpenSrcRecP8+C_OUTREF
JSR CloseAnyFile ;Close SRC file
INC srcP ;Skip the EO RLD marker which
BNE BUMP1 ; is a $00 to point @ appended ESD
INC srcP+1
BUMP1 LDY ModuleNbr ;Current file module #
LDA xtrnRecP ;Ptr to 1st EXTRN record
STA srcModTabLo,Y ; for this module
LDA xtrnRecP+1
STA srcModTabHi,Y
; Add records to the Symbol, ENTRY/EXTRN
; tables using information from an ESD record.
; Careful note should be paid to the fact
; that an ENTRY record & a Symbol record has the
; same data in their respective first field.
ScanESD
JSR AbortPause
LDY #Str15.sizeof-1 ;FOR Y= 15 to 1
LDA #SPACE
@bloop STA (entRecP),Y
STA (symP),Y
DEY
BNE @bloop
; Y=0 on fall thru
; NB: All chars of symbolic name record will have their msb off.
; The SymbolicName record is a p-string (likely to be a
; truncation of the original symbolic name in ESD)
MakeRecords
LDA (srcP),Y ;Get 1st char of symbolic name
BNE @1
JMP DoneESD ;EO ESD => Done processing this file
@1 PHP ;save status of its msb
AND #$7F
INY
STA (entRecP),Y ;Copy the char to both ENTRY and
STA (symP),Y ; SymbolicName records
PLP ;Is its msb off?
BPL CheckSymType ;Yes, last char of symbolic name
CPY #Str15.sizeof-1 ;max len of linker symbol
BCC MakeRecords ;Next char
; Only the first 15 chars are copied. We skip the rest of chars.
; However, we still need to locate the eo the symbolicname
; in order to get @ the symbol-type flag etc.
@sloop LDA (srcP),Y ;Get symbolicname's char
INY
TAX ;Is this the last char?
BMI @sloop ;No
CheckSymType
TYA ;(Y)=index symbol-type flag byte
LDY #EntryRecord.symbolName
STA (entRecP),Y ;Set the len byte of symbolName
STA (symP),Y ; fields of both recs
TAY
LDA (srcP),Y
STA ESDWrkRec+ESDRecord.flags
; The next 2 fields depends on the symbol type above.
; If symbol is flagged as EXTRN, first field is the symbol
; # referred to by an RLD entry. The 2nd field must be zero.
; If symbol is flagged as ENTRY, they are the 2 bytes of
; relocateable address.
INY
LDA (srcP),Y
STA ESDWrkRec+ESDRecord.externNum ;or ESDRecord.relAddr
INY
LDA (srcP),Y
STA ESDWrkRec+ESDRecord.unused
LDA ESDWrkRec+ESDRecord.flags
AND #entry ;Is it an ENTRY symbol-type?
BNE DoEntry ;Yes
LDX #xtrnRecP
BIT Z9E ;Include code fr this file?
BPL DoXtrn ;Yes
JMP NxtEntryZ ;No recs will be added to the 3 tables
;================================================
; Process an EXTRN symbol-type rec in ESD of a src file
DoXtrn LDA #0 ;Zero the curr ENTRY slot
LDY #EntryRecord.sizeof
@zloop STA (entRecP),Y ; which had been partially
DEY ; filled with the symbolicname
BPL @zloop
; Create a EXTRN record in table @ $7100
; Each record is 8 bytes
; Initial Layout of each record is as follows:
; offset Description
; 0 DW ptr to a record in SymbolicName table ($9200) or
; ptr to another EXTRN rec if the SymbolicName
; matched with that in one of the ENTRY recs
; 2 DW Ptr to an ENTRY record; NULL initially
; 4 DB file # of SRC file (also called module #)
; 5 DB FlagByte
; 6 DB symbol # referred to by an RLD record
; 7 DB 0
; First we assume the symbol name is not in the Symbol table
; by setting first field to point to the new symbolic name record
; which had not been "added" to the its table.
LDY #XtrnRecord.symNamePtr ;XtrnRecord.next?
LDA symP
STA (xtrnRecP),Y ;Point to the new record of
LDA symP+1 ; Symbol table @ $9200
INY
STA (xtrnRecP),Y
INY ;=2
LDA #NULL
STA (xtrnRecP),Y ;XtrnRecord.entryPtr = NULL
INY
STA (xtrnRecP),Y
INY ;=4
LDA ModuleNbr
STA (xtrnRecP),Y ;XtrnRecord.fileNum = file # of the SRC file
LDA ESDWrkRec+ESDRecord.flags
ORA #undefined+unreferenced
INY ;=5
STA (xtrnRecP),Y ;XtrnRecord.flags
INY ;=6
LDA ESDWrkRec+ESDRecord.externNum
STA (xtrnRecP),Y ;Symbol # referred to by an RLD record
INY ;=7
LDA #$00
STA (xtrnRecP),Y ;ESDRecord.unused = 0;
JSR ScanEntryTable ;Is this symbol already in ENTRY table?
BNE CHKSYMTBL ;No
JSR AppendNode ;Yes, add this EXTRN rec to singly-linked list
JMP DoneXtrn ;Add this EXTRN rec to its table
CHKSYMTBL
JSR ScanSymbolTab ;Is symbol already in SymbolicName table?
BNE AddSymbolTab ;No => add the newly-built Symbol rec to its table
; The symbolic name is already in the Symbol table so we have
; to change the first field of the XTRN record to point
; to the "found" record.
LDY #XtrnRecord.next ;XtrnRecord.symNamePtr
LDA Z88 ;Set this link to point
STA (xtrnRecP),Y ; to SymbolicName record that is
INY
LDA Z88+1 ; already in Symbol array
STA (xtrnRecP),Y
JMP DoneXtrn ;Don't add newly-built Symbol rec to its table
; We are extending the Symbol table by one record.
; This is done by incrementing symP by the appropiate
; # of bytes i.e. symP++ (in C Syntax)
AddSymbolTab
JSR AdvNxtSymbol ;Adv to next empty slot of SymbolicName array
LDA symP+1 ;Can we extend the SymbolicName array further?
CMP #>XA8E0 ;(Linker's HiMem is set @ $A8E0)
BCC DoneXtrn
BNE @full
LDA symP
CMP #<XA8E0
BCC DoneXtrn
@full JMP SymbolTabFull ;Yes
; Do a XtnP++ to point @ the next empty slot in EXTRN array
DoneXtrn
JSR AdvNxtExtrn
JMP NxtEntryZ ;Prepare to process next rec in appended ESD
;================================================
; Process an ENTRY symbol-type record in ESD of src file
; The 1st field is already done
; Layout of 24-byte records in ENTRY table @ $4700
; offset
; 0 STR up to 16 chars including len byte
; 16 DB file # of src file (start fr 0)
; 17 DB symbol-type
; 18 DW relocated addr
; 20 DW 0 (Ptr to EXTRN record) - first/head
; 22 DW 0 (Ptr to EXTRN record) - last/tail
; When control is transferred here, the 2nd field
; of the ESDRecord is a 2-byte offset wrt the SRC
; file's recorded ORG
DoEntry BIT Z9E ;Include code fr this file?
BMI DOENTRY1 ;No
LDA ESDWrkRec+ESDRecord.relAddr+1
CMP srcORG+1 ;Origin as recorded in SRC file
BCC DOENTRY1
LDA objCurrSize+1 ;addr+1 of last byte of code image
SEC
SBC ESDWrkRec+ESDRecord.relAddr+1
BMI DOENTRY1 ;Is addr to be relocated btwn
BNE CalcAddr ; addrs of 1st & last byte of image?
LDA ESDWrkRec+ESDRecord.relAddr
CMP objCurrSize
BCS DOENTRY1 ;Out of range
; Calc relocated addr of the instruction
; First do an equivalent to a subtraction
; to obtain the instruction' offset wrt
; the src file's Origin
CalcAddr
;Do a 2's complement of SRC file's Origin
LDA ESDWrkRec+ESDRecord.relAddr
CLC
ADC NegSrcORG
STA ESDWrkRec+ESDRecord.relAddr
LDA ESDWrkRec+ESDRecord.relAddr+1
ADC NegSrcORG+1
STA ESDWrkRec+ESDRecord.relAddr+1
;Calc the relocated addr
LDA ESDWrkRec+ESDRecord.relAddr
CLC
ADC CurrORG
STA ESDWrkRec+ESDRecord.relAddr
LDA ESDWrkRec+ESDRecord.relAddr+1
ADC CurrORG+1
STA ESDWrkRec+ESDRecord.relAddr+1
DOENTRY1
LDY #EntryRecord.fileNum
LDA ModuleNbr ;SRC file #
STA (entRecP),Y
INY
LDA ESDWrkRec+ESDRecord.flags
ORA #unreferenced ;This is a new record which has ($40)
STA (entRecP),Y ; yet to be referenced
INY
LDA ESDWrkRec+ESDRecord.relAddr
STA (entRecP),Y
INY
LDA ESDWrkRec+ESDRecord.relAddr+1
STA (entRecP),Y
LDA #NULL ;FOR Y=20 TO 23
@zloop INY
CPY #EntryRecord.sizeof
STA (entRecP),Y ;Set both links to NULL as well
BCC @zloop
LDY #0
TYA ;Zero len byte so that the scanning
STA (entRecP),Y ; below will skip this ENTRY rec
JSR ScanEntryTable ;Is this symbol already in ENTRY table?
PHP ;save for later
LDA (symP),Y ;Get a copy of len byte from Symbol record
STA (entRecP),Y ; & restore to ENTRY record (NB. Y=0)
PLP
BNE NxtEntry ;Not in ENTRY table
JSR StoreDupSym ;Record duplicate symbol
; Do a EntP++ to point @ the next empty slot in ENTRY table
NxtEntry
JSR AdvNxtEntry
; ($2502)
NxtEntryZ
JSR NxtESDRec ;Point @ next rec in appended ESD
LDA $01,X ;Since (X)=$8A,$8C, the locations
CMP GoShowMsgZ,X ; $360D+$8A/$8C=$3697/$3699 are accessed
BEQ SymbolTabFull ;($3697)=$60 and ($3699)=$00; bug?
JMP ScanESD ;Loop back to process the ESD record
SymbolTabFull
LDY #$0A ;Report "symbol table is full"
JSR GoShowMsg
; We have finishing processing the ESD of the curr file.
; Do some housekeeping b4 processing the next file.
; NB. If a SRC pathname is preceded by an asterik,
; its SymbolicNames will be referenced but no
; object code will be incorporated into the
; final OBJ file.
DoneESD
BIT Z9E ;Was SRC PN preceded by a *?
BMI NxtSrc ;Yes => its code will not be incorporated in OBJ file
LDA srcCodeLen
CLC
ADC CurrORG ;Starting PC for
STA CurrORG ; the next SRC file
LDA srcCodeLen+1
ADC CurrORG+1
STA CurrORG+1
NxtSrc INC ModuleNbr
LDA ModuleNbr
CMP #maxSrcFiles
BCS TooMany
JMP Phs1Loop ;Process next SRC file
TooMany LDY #$0B ;Report "Too many SRC files"
JSR GoShowMsg
;=================================================
; Get the end of Relocation Dictionary of the SRC file
; Each record in the Relocation Dictionary is 4 bytes long
; Input
; srcP - ptr to beginning of an RLD chunk
; Output
; (Y)=0
; srcP - End of RLD if found
; Z=1
; X - not used
;
; Possible bug here. The code should check that srcP
; should not exceed upper limit of srcDataBuf which is
; $2000 unless it's assumed that RLD is always < 5K. For
; such cases, since each RLD record is 4 bytes, the max #
; of RLD records in a SRC file = (5x1024)/4 -1 = 1279
; This rtn should be re-written to handle files with huge RLDs
; When the end of the RLD is not found, it should check that
; srcP == (srcDataBuf+FileDataBufSiz) by returning a flag to
; the caller.
; ($2539)
GetEndRLD
LDY #0
@scan1 LDA (srcP),Y ;Get RLD-flag byte
AND #%00000001 ;Is it EO RLD?
BEQ @done ;Yes
LDA #RLDRecord.sizeof ;Point @ next RLD record
CLC
ADC srcP
STA srcP
LDA #0
ADC srcP+1
STA srcP+1
JMP @scan1 ;Continue scanning
@done RTS
;=================================================
; Phase 2 of the Linking process
; This rtn will attempt to resolve EXTRN's by checking
; if its symbolic name is in the ENTRY table.
; If REF/EXTRN symbol cannot be resolved, the first 2 bytes
; of EXTRN record are overwritten:
; 0 EXTRN #
; 1 first char's msb is set to 1
; NB. After phase 1, some recs in EXTRN table are
; already in a singly-linked list. Their SymbolicName
; fields would have been changed to point to another
; EXTRN rec or is set to NULL if they happen to be
; the last node of the list.
; The msb of their flagbyte would be 0 (symbol is defined)
;($2552)
DoPhase2
LDA #0
LDY #EntryRecord.symbolName
STA (entRecP),Y ;Zero the len byte of ENTRY record
LDY #XtrnRecord.flags ; and flag byte of EXTRN record
STA (xtrnRecP),Y ;These recs are empty slots
LDY #$05 ;Print Resolving REF/EXTRN...
JSR DisplayMsg
JSR DisplayCR
LDY #$05
JSR StoreMsgY ;Store same msg
LDA #<xternTab
STA xtrnRecP ;Point to start
LDA #>xternTab
STA xtrnRecP+1 ; of EXTRN table
LDA #0
STA xtrnNbr ;EXTRN cnt (or EXTRN #)
; Phase2 main loop
@mainlp JSR AbortPause
LDY #XtrnRecord.flags
LDA (xtrnRecP),Y ;Get flag byte
BEQ @done ;Done w/all recs in EXTRN table
AND #%10000000 ;Is symbol undefined?
BEQ @next ;No, skip this EXTRN rec
LDY #XtrnRecord.symNamePtr
LDA (xtrnRecP),Y ;Get ptr to its symbolicname
STA symP
INY
LDA (xtrnRecP),Y
STA symP+1
JSR ScanEntryTable ;Is symbol already in ENTRY table?
BNE @noHit ;No
JSR AppendNode ;Add to singly-linked list of EXTRN recs
JMP @next ;Prepare to process next record
; The EXTRN symbol was not found in ENTRY table
@noHit LDY #XtrnRecord.flags
LDA (xtrnRecP),Y ;Get flag byte fr EXTRN record
ORA #%00000010 ;Flag as "No such label"
STA (xtrnRecP),Y
BIT WhichType ;Is object file of type REL?
BPL @notdef ;No
JSR MarkNoSymbol ;Modify SymbolicName & update EXTRN recs
JMP @next
@notdef JSR StoreUndefSym ;Report undefined symbol
@next JSR AdvNxtExtrn ;Next EXTRN record
JMP @mainlp ;Loop back
; We have finished scanning through all EXTRN recs
@done BIT WhichType ;Is OBJECT file of type REL?
BPL @exit ;No, exit this phase
; Write a tempESD file of unreferenced ENTRY & unresolved EXTRN
; records by scanning thru their respective tables
JSR MakeTmpESD ;Open tempESD file for writing
JSR WriteXtrnTmpESD ;Use info fr unresolved EXTRNs &
JSR WriteEntryTmpESD ; unreferenced ENTRYs to write file
JSR CloseTmpESD ;Mark EO ESD and close tempESD file
@exit JMP DoPhase3
;===============================
; An EXTRN Symbol cannot be found in ENTRY table
; Modify its EXTRN rec & associated Symbol rec
; Input
; xtrnRecP - Ptr to a record of EXTRN table
; xtrnNbr - EXTRN count
; Output
; symP - Ptr to a record of SymbolicName table
; (Y)=0
; The structure of SymbolicName table will be modified.
; Only 2 bytes are changed viz.
; offset 0 - len byte -> EXTRN #
; offset 1 - 1st char whose msb is off -> msb on
; ($25C6)
MarkNoSymbol
LDY #XtrnRecord.symNamePtr
LDA (xtrnRecP),Y
STA symP
INY
LDA (xtrnRecP),Y
STA symP+1
LDY #SymbolRecord.symbolName+1
LDA (symP),Y ;Is msb of its 1st char off?
BPL @1 ;Yes
DEY
LDA (symP),Y ;No, get EXTRN #
JMP @3
@1 INC xtrnNbr ;EXTRN #
BNE @2
JMP ExtrnErr ;>255 EXTRN's in REL output ESD
@2 ORA #$80 ;Set 1st char's msb to 1
STA (symP),Y
LDA xtrnNbr ;EXTRN #
@3 LDY #XtrnRecord.externNum
STA (xtrnRecP),Y
LDY #SymbolRecord.externNum
STA (symP),Y ;Overwrite its len byte w/EXTRN #
RTS
;===============================
; Check if a SymbolicName is present in
; one of the recs of ENTRY array ($4700)
; Input
; symP - ptr to a SymbolicName rec
;
; Output
; Z=1 - Yes
; Z88 - Ptr to the ENTRY record
; (Y)=0
; Uses a brute force method to search for the key
; The search is conducted record by record until
; no more records are left to be processed
; ($25F3)
ScanEntryTable
LDA #<EntryTab ;Start search fr BO ENTRY table
STA Z88
LDA #>EntryTab
STA Z88+1
@scan1 LDY #EntryRecord.symbolName
LDA (symP),Y ;Get len byte of symbolicname
CMP (Z88),Y
BNE @noHit ;Definitely no match
CMP #Str15.sizeof
BCC @doCmp
LDA #Str15.sizeof-1 ;At most 15 chars to be compared
@doCmp TAX
@cmpLup INY
LDA (symP),Y ;Compare symbolic names
CMP (Z88),Y
BNE @noHit ;No match
DEX
BNE @cmpLup ;continue
LDY #0 ;Z=1 ==> hit
RTS
@noHit LDA #EntryRecord.sizeof
LDX #Z88 ;Ptr to be adjusted
JSR AdvNextRecZ ;Adv to next ENTRY record (Z88++)
LDY #0
LDA (Z88),Y ;Get symbol's len byte fr ENTRY rec
BNE @scan1 ;Not EOT, so try again
LDY #0
LDA #1 ;Z=0 ==> Not found
RTS
;=================================================
; Check if EXTRN name is in Symbol table ($9200)
; Return a ptr to the "found" Symbol record if
; there is a match. In this case, the caller
; should not add the new Symbol record to its table.
; Input
; Output
; (symP) - ptr to the new symbolicname which is
; to be added to the Symbol Table.
; On return
; (Y)=0
; Z=1 match
; (Z88) - ptr to symbolicName record
; ($2629)
ScanSymbolTab
LDA #<symbolTab
STA Z88
LDA #>symbolTab
STA Z88+1
JMP @ckend
@mainlp LDY #SymbolRecord.symbolName
LDA (symP),Y ;Get its len byte
CMP (Z88),Y
BNE @nohit
CMP #SymbolRecord.sizeof
BCC @cmp
LDA #SymbolRecord.sizeof-1 ;Compare first 15 chars
@cmp TAX
@cmplp INY
LDA (symP),Y
CMP (Z88),Y
BNE @nohit ;No match
DEX
BNE @cmplp
LDY #0 ;Z=1
RTS
@nohit LDA #SymbolRecord.sizeof
LDX #Z88
JSR AdvNextRecZ ;Adv to next SymbolicName record
@ckend LDA Z88 ;Is EOT?
CMP symP ;NB. This rec has yet to be "added"
BNE @mainlp
LDA Z88+1 ; to the SymbolicName table
CMP symP+1
BNE @mainlp ;No, keep searching
LDY #0
LDA #1 ;Z=0
RTS
;=================================================
; Modify the ENTRY and EXTRN records by setting up
; the necessary links.
; If more than one EXTRN records refer to the ENTRY
; rec, then we setup a singly-linked list to link
; all the EXTRN recs. The field "head" will
; point to the first EXTRN rec & the field "tao;"
; point to the last EXTRN rec in the singly-linked list
;
; Input
; (xtrnRecP) - Ptr to a EXTRN record
; (Z88) - Ptr to an ENTRY record
; Output
;
; Prepare to add a new node (in the form of an EXTRN rec)
; to the singly-linked list. The pointer to a SymbolicName
; rec (symNamePtr) in the EXTRN rec is now called "next"
; (variant rec in Pascal, union in C).
; ($2668)
AppendNode
LDY #XtrnRecord.next ;XtrnRecord.symNamePtr
LDA #NULL
STA (xtrnRecP),Y ;Set "next" link to NULL
INY
STA (xtrnRecP),Y
INY ;2
LDA Z88 ;Ptr to ENTRY record whose symbolicname
STA (xtrnRecP),Y ; matches that of the current ESD entry
INY ;3
LDA Z88+1
STA (xtrnRecP),Y
LDY #XtrnRecord.flags
LDA (xtrnRecP),Y
AND #$FF-undefined ;Indicate the symbol is now defined $7F
STA (xtrnRecP),Y
AND #fwdreferenced ;Has the meaning of this bit changed?
LDY #EntryRecord.flags
EOR (Z88),Y
AND #fwdreferenced
BEQ @1 ;Yes
JSR StoreSizErr ;size mismatch (8-bit vs 16-bit)
@1 LDY #EntryRecord.flags
LDA (Z88),Y
AND #unreferenced
BEQ @2 ;=> have been referenced before
EOR (Z88),Y ;Clear the unreferenced bit
STA (Z88),Y ; but retain the other bits
; The ENTRY rec is referenced the FIRST time so set its
; "head" and "tail" fields to point to the same EXTRN rec
LDY #EntryRecord.head
LDA xtrnRecP ;Get ptr to EXTRN record
STA (Z88),Y
INY ;=21
LDA xtrnRecP+1
STA (Z88),Y
INY ;=22
LDA xtrnRecP ;Ptr to same EXTRN record
STA (Z88),Y
INY ;23
LDA xtrnRecP+1
STA (Z88),Y
RTS
; The ENTRY symbol has been referenced at least once.
; We add the new node (EXTRN record) to the end of the
; singly-linked list of EXTRN records.
@2 LDY #EntryRecord.tail
LDA (Z88),Y ;Get ptr to previous EXTRN record
STA Z82 ;Save it for later
LDA xtrnRecP
STA (Z88),Y ;Set the link to point
INY ;23
LDA (Z88),Y ; to this EXTRN record
STA Z82+1
LDA xtrnRecP+1 ; which is now the last node
STA (Z88),Y ; in the singly-linked list
LDY #XtrnRecord.next
LDA xtrnRecP ;(Z82) - previously the "tail" EXTRN record
STA (Z82),Y ;Replace its "next" link (which was NULL)
INY
LDA xtrnRecP+1 ; with ptr to this EXTRN record
STA (Z82),Y
RTS
;===============================
; Copy the temporary ESD file name to pathame buf
; ($26D1)
MovTmpESDName
LDY TempESD ;len byte
@mvLoop LDA TempESD,Y
STA pathNameBuf,Y
DEY
BPL @mvLoop
RTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Open a temporary (binary) ESD file for output
; This rtn will be called if there are unresolved
; EXTRN symbols
;
; Output
; (Z86) - ptr to tmpESD data buffer
; Write3RecP8+c.refNum - EXTRN # used to write tempESD file
; ($26DE)
MakeTmpESD
JSR MovTmpESDName ;Set PN to "EDASM.TempESD"
JSR PRODOS8
DC.B $C1 ;DESTROY
DC.W DestroyRecP8
LDA #0
STA CreateRecP8+C_AUXID ;auxtype
STA CreateRecP8+C_AUXID+1
LDA #BIN_type
STA CreateRecP8+C_FILEID
JSR PRODOS8
DC.B $C0 ;CREATE
DC.W CreateRecP8
BEQ @1
JSR ErrHandler ;Don't come back
@1 JSR PRODOS8
DC.B $C8 ;OPEN
DC.W Open3RecP8
BEQ @2
JSR ErrHandler ;Don't come back
@2 LDA Open3RecP8+C_OUTREF
STA Write3RecP8+C_REFNUM ;write RN for tempESD file
;===============================
SetDataBufPtr
LDA #<X9100 ;Reset to BO data buf
STA Z86 ; b4 next ESD rec is created
LDA #>X9100
STA Z86+1
RTS
;===============================
; Scan through the ENTRY table for recs whose
; SymbolicName remained unreferenced. Output info
; to tempESD file
; Input
; Output
; ($2719)
WriteEntryTmpESD
LDA #<EntryTab
STA Z8E ;Point @ BO ENTRY table
LDA #>EntryTab
STA Z8E+1 ;=> re-cycled zp loc
@scanlp JSR AbortPause
LDY #EntryRecord.flags
LDA (Z8E),Y ;Get ENTRY record's flag byte
BIT EntryRefOption ;Include ENTRY records in tempESD file?
BMI @1 ;Yes
AND #unreferenced ;Is its SymbolicName still unreferenced?
BNE @1 ;Yes
JMP @skip
@1 JSR MovSymESDBuf ;Copy symbolicname to tmpESD buf
TYA ;Save len of symbolicname
PHA
LDY #EntryRecord.flags
LDA (Z8E),Y ;Get ENTRY record's flag byte again
AND #$FF-undefined-unreferenced
STA ESDWrkRec+ESDRecord.flags ;Clear undefined/unreferenced bits
INY
LDA (Z8E),Y
STA ESDWrkRec+ESDRecord.relAddr
INY
LDA (Z8E),Y
STA ESDWrkRec+ESDRecord.relAddr+1
PLA
TAY ;Restore Y-reg
JSR AddESDBuf ;Add ENTRY data to tempESD data buf
JSR WriteESDRec ;Write out to tempESD file
@skip LDA #EntryRecord.sizeof
LDX #Z8E
JSR AdvNextRecZ ;Next ENTRY record
LDY #EntryRecord.symbolName
LDA (Z8E),Y ;Is EOT?
BNE @scanlp ;No
RTS
;===============================
; Scan through the EXTRN table for recs whose
; SymboliName remained undefined. Output info
; to tempESD file
; Input
; Output
; ($2763)
WriteXtrnTmpESD
LDA #<xternTab
STA xtrnRecP
LDA #>xternTab
STA xtrnRecP+1
@scanlp JSR AbortPause
LDY #XtrnRecord.flags
LDA (xtrnRecP),Y
BEQ @ret
AND #undefined ;$80
BEQ @next ;No
LDY #XtrnRecord.symNamePtr
LDA (xtrnRecP),Y ;Get ptr to symbolicname which
STA symP ; is stored in the Symbol Table
INY
LDA (xtrnRecP),Y
STA symP+1
LDY #SymbolRecord.symbolName+1
LDA (symP),Y ;Get its 1st char
BPL @next
AND #$7F
STA (symP),Y ; & reset its msb
LDA #SPACE
@cklup INY
CMP (symP),Y ;Look for 1st trailing blank
BEQ @Got1
CPY #Str15.sizeof-1
BCC @cklup
INY ;No trailing blanks
@Got1 DEY
TYA ;len of symbolicname
LDY #SymbolRecord.externNum
STA (symP),Y ;Overwrite the EXTRN # with len byte
JSR MakeESDRec ;Create a ESD rec (variable in size)
JSR WriteESDRec ;Write ESD data to file
@next JSR AdvNxtExtrn ;Next EXTRN record
JMP @scanlp
@ret RTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Input
; (Z86) - ptr to tmpESD buffer
; Output
; ($27AC)
CloseTmpESD
LDA #$00 ;Marks eo ESD
TAY
STA (Z86),Y
INC Z86
BNE @1
INC Z86+1
@1 JSR WriteESDRec ;Flush the tempESD file
LDA Write3RecP8+C_REFNUM ;Close tempESD file
JSR CloseAnyFile
RTS
;=================================================
; Write out data to tempESD binary file
; Input
; (Z86)-ptr to record in tempESD table
; Output
; ($27C1)
WriteESDRec
LDA Z86 ;Calculate # of bytes to write
SEC
SBC #<X9100
STA Write3RecP8+C_REQCNT
LDA Z86+1
SBC #>X9100
STA Write3RecP8+C_REQCNT+1
JSR PRODOS8
DC.B $CB ;WRITE
DC.W Write3RecP8
BEQ @NoErrs
JSR ErrHandler ;Don't come back
@NoErrs JMP SetDataBufPtr
;===============================
; Copy symbolicname to tmpESD data buffer
; Input
; (symP) - ptr to symbolicname record
; (Z86) - ptr to tempESD buffer ($9100)
; Output
; (Y) - len of symbolicname
; ($27DE)
MovSymESDBuf
LDY #SymbolRecord.symbolName
LDA (symP),Y ;Get len byte of symbolicname
CMP #SymbolRecord.sizeof
BCC @1
; Transfer a p-string to the temp ESD data buf
; The chars of the resulting string except the
; last one will have their msbs on.
LDA #SymbolRecord.sizeof-1
@1 TAX ;make into a counter
@cploop INY
LDA (symP),Y ;Get char
ORA #$80 ;Set msb on
DEY
STA (Z86),Y
INY
DEX
BNE @cploop
DEY
AND #$7F
STA (Z86),Y ;msb of last char is off
INY ;len of symbolicname
RTS
;===============================
; Make an ESD record for output (of unresolved EXTRNS)
; NB. An ESD record has 3/4 fields, the first one of
; which is a string of chars whose last char has its
; msb set. It is followed by 3 bytes.
; Input
; xtrnRecP - ptr to record in EXTRN table
; Z86 - ptr to record in tempESD table
; Output
; ($27FC)
MakeESDRec
JSR MovSymESDBuf
TYA ;len of symbolicname
PHA
LDY #XtrnRecord.flags
LDA (xtrnRecP),Y
AND #$FF-undefined-unreferenced-nosuchlabel
STA ESDWrkRec+ESDRecord.flags
LDY #XtrnRecord.externNum
LDA (xtrnRecP),Y
STA ESDWrkRec+ESDRecord.externNum
LDA #0
STA ESDWrkRec+ESDRecord.unused
PLA
TAY
;
; Common code for appending an ESD rec using
; info fr a rec of EXTRN/ENTRY table
; Input
; (Y) - len of symbolicname
; (Z86) - ptr to record in tempESD table
AddESDBuf
LDA ESDWrkRec+ESDRecord.flags
STA (Z86),Y
INY
LDA ESDWrkRec+ESDRecord.externNum
STA (Z86),Y
INY
LDA ESDWrkRec+ESDRecord.unused
STA (Z86),Y
INY
TYA ;size of ESD record (which is variable)
LDX #Z86
JSR AdvNextRecZ ;Adv the ptr to next ESD rec
RTS
;===============================
; Input
; Output
; Store duplicate ENTRY symbol associated messages
; ($2831)
StoreDupSym
JSR StorErr
LDY #$12 ;dup ENTRY symbol
JSR StoreMsg
JSR StoreName
LDY #$13 ;of module #
JSR StoreMsg
JSR StoreFileNum
LDY #$14 ;in module #
JSR StoreMsg
LDY #EntryRecord.fileNum
LDA (entRecP),Y ;REL file #
LDY #0 ;zero ten's digit
JSR Cnv2S ;Store 2 ASCII char in LINKMAP
JSR StoreCR
RTS
;===============================
; Input
; Output
; Store undefined EXTERN symbol associated messages
; ($2856)
StoreUndefSym
JSR StorErr
LDY #$15 ;undef EXTRN symbol
JSR StoreMsg
LDA symP ;ptr to symbolicname
STA Z88
LDA symP+1
STA Z88+1
JSR StoreName ;Store symbolic name
LDY #$14 ; in module #
JSR StoreMsg
LDY #XtrnRecord.fileNum
LDA (xtrnRecP),Y ;Get src file #
LDY #0 ;Zero ten's digit
JSR Cnv2S ;Convert to 2-byte ASCII char
JSR StoreCR
RTS
;===============================
; Input
; Output
; ($287B)
StoreSizErr
JSR StorErr
LDY #$1D ;mismatch REF-DEF size
JSR StoreMsg
JSR StoreName
LDY #$14 ; in module #
JSR StoreMsg
LDY #XtrnRecord.fileNum
LDA (xtrnRecP),Y ;Get REL file #
LDY #0 ;Zero ten's digit
JSR Cnv2S ;Convert
JSR StoreCR
RTS
;===============================
; Store "ERR:" to LINKMAP file
; Input
; Output
StorErr
LDA #'E'
JSR StoreChar
LDA #'R'
JSR StoreChar
JSR StoreChar
LDA #':'
JMP StoreChar
;===============================
; Store to LINKMAP file
; Input
; (Y) = message #
; Output
StoreMsgY
BIT MapOption ;Store into LINKMAP file ?
BPL doRTS ;No, ret
JSR StoreMsg
JMP StoreCR
;===============================
; Output a Message to LINKMAP file
; Input
; Output
; (Y)-index into message sub-tables
; You may think of (Y) as being the err #
; ($28B4)
StoreMsg
LDA MsgTabLo,Y
STA msgP
LDA MsgTabHi,Y
STA msgP+1
LDY #0
@loop LDA (msgP),Y
CMP #'\' ;end of msg
BEQ doRTS
JSR StoreChar
INY
JMP @loop ;next char
doRTS RTS
;=================================================
; Phase 3 of the Linking process
; Relocate the object code. The RLD of each SRC file
; is used to relocate the code from each file. Code
; fr SRC files whose names are preceded by a * in
; the cmd file are not included in the OBJECT file.
; Mem reserved for the Symbol table ($9200-$92FF) is
; re-used as a data buffer. 256 bytes of the code image
; of a SRC file are read into this area first b4
; being move forward into previous mem page ($9100)
; for patching.
;
;
; Input
; Output
; ModuleNbr - # of SRC file
; CurrORG - Starting PC for curr SRC file
; (objCodeLen)
; (LowerBound)
; (UpperBound,9C)
; ($28CE)
DoPhase3
LDY #$06 ;Report "Relocating objcode..."
JSR DisplayMsg
JSR DisplayCR
LDY #$06
JSR StoreMsgY ;save a copy in LINKMAP
LDA #0
STA ModuleNbr
STA objCodeLen ;EO REL-type OBJECT file
STA objCodeLen+1
LDA Origin
STA CurrORG ;Starting PC
LDA Origin+1
STA CurrORG+1
JSR MoveObjName ;Set PN to "EDASM.LINKOBJ"
JSR PRODOS8
DC.B $C1 ;DESTROY
DC.W DestroyRecP8
LDA Origin
STA CreateRecP8+C_AUXID
LDA Origin+1
STA CreateRecP8+C_AUXID+1 ;auxtype
LDA TargetObjType ;filetype of OBJECT file
STA CreateRecP8+C_FILEID
JSR PRODOS8
DC.B $C0 ;CREATE
DC.W CreateRecP8
BNE @1
JSR PRODOS8 ;OPEN the OBJECT file
DC.B $C8
DC.W Open3RecP8
BEQ @2
@1 JSR ErrHandler ;Don't come back
@2 LDA Open3RecP8+C_OUTREF ;OBJECT file
STA Write3RecP8+C_REFNUM ;RN to write OBJECT file
BIT WhichType ;What is the OBJECT file type?
BPL @4 ;=>BIN/SYS
; Write the header of OBJ file which is a 2-byte value
; denoting the length of its code image.
LDA #$00 ;REL OBJECT file
STA X9100
STA X9100+1
STA Write3RecP8+C_REQCNT+1 ;Write 2 zeroes for
LDA #$02 ; the code image len
STA Write3RecP8+C_REQCNT
JSR PRODOS8
DC.B $CB ;WRITE
DC.W Write3RecP8
BEQ @3
JSR ErrHandler ;Don't come back
@3 LDA WriteMapRecP8+C_REFNUM
JSR CloseAnyFile
JSR OpenTmpRLD ;Open a new tempRLD file 4 writing
@4 JSR ResetFilePos ;Set file posn to BO cmd file
; Skip all directives at the start cmd file
; to get at the SRC pathnames
@skip JSR ReadOneCmd ;Do we have a SRC filename?
BNE Phs3Loop ;If not cr/space => pathname
CMP #CR
BNE @skip ;A leading space, skip to the directive
JMP WrongOrder ;Invalid cmd order
; Mainloop for phase 3
; Buffers used for :
; reading RLD = $0C00-$1FFF
; Patching code = $9100-$91FF
; reading code = $9200-$92FF
Phs3Loop
JSR ShowLineBuf ;Show PN of the SRC file being processed
JSR OpenSrcFile ;Open it for reading
BIT Z9E ;Is src PN preceded by *?
BPL @1 ;No
LDA OpenSrcRecP8+C_OUTREF ;Close it
JSR CloseAnyFile
JMP NxtModule ;Skip reading from it
@1 LDA #2
CLC
ADC srcCodeLen ;Set file posn to start of
STA MarkSrcRecP8+C_MARK
LDA #0
ADC srcCodeLen+1
STA MarkSrcRecP8+C_MARK+1 ; Relocation Dictionary
LDA OpenSrcRecP8+C_OUTREF
STA MarkSrcRecP8+C_REFNUM
STA ReadCodeRecP8+C_REFNUM
JSR PRODOS8
DC.B $CE ;SET_MARK
DC.W MarkSrcRecP8
BEQ Phs31
Jmp2EH JSR ErrHandler ;Don't come back
Phs31 JSR ReadMax ;Have we read entire RLD?
BCC @1 ;Yes
JSR ErrHandler ;Don't come back
@1 LDA #2 ;Set file posn to BO
STA MarkSrcRecP8+C_MARK ; code image of SRC file
LDA #0
STA MarkSrcRecP8+C_MARK+1
JSR PRODOS8
DC.B $CE ;SET_MARK
DC.W MarkSrcRecP8
BNE Jmp2EH
LDA #0
STA LowerBound
STA LowerBound+1
STA UpperBound
STA UpperBound+2
JSR Read1PageCode ;Read the first $100 bytes of code image
; Loop to process all recs in the RLD of curr SRC file
Phs3Loop1
JSR AbortPause
LDY #RLDRecord.flags
LDA (srcP),Y ;Get flag byte fr RLD record
STA RLD_Flags
BNE @1
JMP FlushLoop ;EO RLD => done w/this SRC file
; The code below doesn't check for overflow
; What happens if field offset is a # > $6EFF?
@1 LDY #RLDRecord.codeOffset
LDA (srcP),Y
STA Z80 ;Field offset in code image
CLC
ADC #<X9100
STA Z86 ;location to patch???
INY
LDA (srcP),Y
STA Z80+1
ADC #>X9100
STA Z86+1 ;$9100-$FFFF?
; Check if the field offset is within the "window"
; bounds LowerBound and UpperBound. Since no effort is made
; to check the lower bound, it is assumed that the
; field offset is past this when (Z80) < UpperBound
; It is also assumed that all records (in the RLD) have been
; arranged with field offsets in ascending order
@chkLoop
LDA Z80 ;Is field offset < upper bounds?
CMP UpperBound
LDA Z80+1
SBC UpperBound+2
BCC @2 ;Yes, within the "window"
JSR FlushCode ;No, read another page of code
JMP @chkLoop ; and check again
; The ptr Z86 could be calculated using the formula
; (Z86)=(Z80) - (LowerBound) + $9100
@2 SEC
LDA Z86
SBC LowerBound
STA Z86 ;Z86 -= LowerBound
LDA Z86+1 ;If there is no overflow above,
SBC LowerBound+1
STA Z86+1 ; then $9100 =< (Z86) =< $91FF
BIT WhichType ;an REL object file?
BPL @3 ;No => BIN/SYS
LDY #RLDRecord.codeOffset+1
LDA Z80 ;Field offset
CLC
ADC objCodeLen ;Len of Code Image of
PHA
LDA Z80+1 ; REL OBJECT file excluding
ADC objCodeLen+1 ; that of curr SRC file
STA (srcP),Y ;Patch field offset of RLD record
DEY ;Y=1
PLA
STA (srcP),Y
@3 BIT RLD_Flags ;Is size of relocatable field 2?
BMI @6 ;Yes
LDY #0 ;Get original addr (lo/hi)
LDA (Z86),Y ; byte fr the code image
BIT RLD_Flags ;Is it hi-8 of addr?
BVS @4 ;Yes
; (A) has the lo-8 of the addr (fr a > byte operator)
; Since only the lobyte is used to patch the code
; any value for the hibyte can be used. So let's
; use 0 as RelAdrHi
STA RelAdr
LDA #$00
STA RelAdr+1
JSR GetRelAdr ;Calc/get relocated addr
LDY #0
LDA RelAdr ;Use the lo 8-bit to
STA (Z86),Y ; patch the code image
JMP @next ;Skip code below
; (A) has the hi-8 of the addr (fr a < byte operator)
; For this case, we need both the low & high bytes
; of the original addr if relocation rec is not
; flagged as EXTRN symbol-type
@4 STA RelAdr+1 ;hi-byte
LDY #RLDRecord.low8bits
LDA (srcP),Y ;lo 8-bits/EXTRN symbol #
STA RelAdr
LDA RLD_Flags ;Get RLD flag byte
AND #$10 ;Is field EXTRN 16-bit reference?
BEQ @5 ;No
LDA #$00
STA RelAdr ;Overwrite EXTRN symbol #
; On fall thru, the relocated addr will not be
; calculated but obtained from an ENTRY rec if
; it is available.
@5 JSR GetRelAdr ;Calc/get the relocated addr
LDY #0
LDA RelAdr+1
STA (Z86),Y ;Patch code image
JMP @next ;Skip code below
; Size of relocatable field is 2
; Get relocated addr fr the RLD rec
@6 LDY #0
LDA RLD_Flags ;Get RLD rec's flag byte
AND #$20 ;Normal/Reversed order?
BNE @7
LDA (Z86),Y ;Little Endian (reversed order)
STA RelAdr
INY
LDA (Z86),Y
STA RelAdr+1
JSR GetRelAdr ;Calc/get relocated addr
LDY #0
LDA RelAdr
STA (Z86),Y ;Patch the code
INY
LDA RelAdr+1
STA (Z86),Y
JMP @next ;=>next RLD
; Handle a Big Endian
@7 LDA (Z86),Y
STA RelAdr+1 ;hiaddr
INY
LDA (Z86),Y
STA RelAdr ;loaddr
JSR GetRelAdr ;Calc/get relocated addr
LDY #0
LDA RelAdr+1
STA (Z86),Y ;Patch the code
INY
LDA RelAdr
STA (Z86),Y
@next LDA #RLDRecord.sizeof
LDX #srcP
JSR AdvNextRecZ ;Adv srcP to next RLD rec
JMP Phs3Loop1 ; & loop back to process it
;===============================
;
; Flush object code if neccessary. Move buffered code
; forward into "window" ($9100-$91FF) so that another
; page of code image can be read into the $9200 data
; buffer. The variables LowerBound & UpperBound are
; edges of this "window".
; Normally (UpperBound - LowerBound) = $100 except when
; the last (partial) page of code is read. In this
; case (UpperBound - LowerBound) < $100
; Input
; LowerBound -
; UpperBound -
; Output
; UpperBound -
;
FlushCode
LDA UpperBound ;Do we need to flush OBJECT code b4
ORA UpperBound+2 ; b4 we "move" our window forward?
BEQ @1 ;No, we are still @ BO of SRC file
JSR WritePatchedCode ;Yes
@1 LDY #0 ;Move buffered Code Image
@mvlup LDA X9200,Y ; forward into our "window"
STA X9100,Y ; @ $9100-$91FF so we can
INY
BNE @mvlup
JSR Read1PageCode ; load another page into $9200 buf
LDA UpperBound
STA LowerBound
LDA UpperBound+2
STA LowerBound+1
INC UpperBound+2 ; Incr by 1 page
LDA UpperBound
CMP srcCodeLen ;Has the entire code image
LDA UpperBound+2
CMP srcCodeLen+1 ; of this SRC file been read?
BCC doRTS1 ;No
LDA srcCodeLen
STA UpperBound ;This is the upper limit of
LDA srcCodeLen+1 ; the "window" of code
STA UpperBound+2
doRTS1 RTS
;===============================
; Write out object code @ $9100
; Input
; LowerBound -
; UpperBound -
; Output
WritePatchedCode
SEC
LDA UpperBound
SBC LowerBound
STA Write3RecP8+C_REQCNT ;# of bytes to write
LDA UpperBound+2
SBC LowerBound+1
STA Write3RecP8+C_REQCNT+1 ; usually $100 bytes
JSR PRODOS8
DC.B $CB ;WRITE
DC.W Write3RecP8
BEQ doRTS1
JM2EH JSR ErrHandler ;Don't come back
;================================================
; Read $100 bytes of data into buffer starting @ $9200
; fr SRC file. The symbol table @ $9200 is re-used
; as a read data buffer.
; Output
; Z=1
; (A) = $4C if EOF or
; = $00 read succeeded
Read1PageCode
LDA #0
STA ReadCodeRecP8+C_REQCNT
LDA #1
STA ReadCodeRecP8+C_REQCNT+1
LDA #<X9200 ;Use this as our R/W Data Buf
STA ReadCodeRecP8+C_DATABUF
LDA #>X9200
STA ReadCodeRecP8+C_DATABUF+1
JSR PRODOS8
DC.B $CA ;READ
DC.W ReadCodeRecP8
BEQ doRTS1 ;If no errs, just return
CMP #$4C ;EOF?
BNE JM2EH ;No -> err handler
RTS ;We have read the entire SRC file
; We have finish patching this file so read the rest
; of the SRC file and write it out to OBJ file.
FlushLoop
LDA UpperBound
CMP srcCodeLen
BNE @1
LDA UpperBound+2
CMP srcCodeLen+1
BEQ @done ;Done w/this SRC file
@1 JSR FlushCode ;Keep flushing objcode N reading
JMP FlushLoop ; code image until we are done
@done JSR WritePatchedCode ;Append rest of OBJECT code
LDA ReadCodeRecP8+C_REFNUM
JSR CloseAnyFile
JSR AppendTmpRLD ;Append patched RLD @ srcDataBuf
LDX ModuleNbr
LDA CurrORG ;Starting posn counter
STA orgAdrLo,X ; for this SRC file
LDA CurrORG+1
STA orgAdrHi,X
JSR CalcFilePos ;adj PC?
LDA CurrORG+1
STA EndAddrHi,X
LDA CurrORG
STA EndAddrLo,X
BNE @2
DEC EndAddrHi,X ;End posn counter
@2 DEC EndAddrLo,X ; for this SRC file
NxtModule
INC ModuleNbr ;Next SRC module
DoNxtCmd
JSR ReadOneCmd ;Is it a pathname?
BNE ToLoopBack ;Yes, prepare to loop back
CMP #CR
BEQ DonePhs3 ;Empty line => Finish all cmds
JSR IsAlign ;Is it Align directive?
BCC @1 ;Proceed to check further
JMP DoBreak ;Don't comeback
@1 BEQ @ckAln ;Yes, it's an ALN option
JMP WrongOrder ;cmd order err
@ckAln LDA CurrORG ;Already aligned @ start of mempage?
BEQ DoNxtCmd ;Yes, read another cmd line
LDX #0
TXA
@zloop STA X9100,X ;zero this
INX
BNE @zloop
LDA #0
SEC
SBC CurrORG
STA Write3RecP8+C_REQCNT ;# of zero bytes to fill
STA srcCodeLen ; Re-used
LDA #0
STA Write3RecP8+C_REQCNT+1
STA srcCodeLen+1 ;Used by code at $2BA2
JSR PRODOS8
DC.B $CB ;WRITE
DC.W Write3RecP8
BNE JM2EH2
JSR CalcFilePos ;Adj PC
JMP DoNxtCmd ;Read next cmd line
ToLoopBack
JMP Phs3Loop ;Loop back to process next SRC file
JM2EH2 JSR ErrHandler ;Don't come back
;===============================
; Adjust file posn
; Input
; Output
; (objCodeLen) - curr val of code image len
; ($2BA2)
CalcFilePos
LDA srcCodeLen
CLC
ADC CurrORG
STA CurrORG ;CurrORG += srcCodeLen
LDA srcCodeLen+1
ADC CurrORG+1
STA CurrORG+1
BIT WhichType ;is object file of type REL ?
BPL @ret ;No -> exit
CLC
LDA srcCodeLen
ADC objCodeLen
STA objCodeLen ;objCodeLen += srcCodeLen
LDA srcCodeLen+1
ADC objCodeLen+1
STA objCodeLen+1
@ret RTS
; Prepare to exit Phase 3
DonePhs3
BIT WhichType ;an REL object file?
BPL @isREL ;No
; Write RLD marker ($00) to the OBJ file
LDY #0
STY srcDataBuf
STY WriteTmpRecP8+C_REQCNT+1
INY
STY WriteTmpRecP8+C_REQCNT ;# of bytes to write=1
JSR WrtTempRld ;Marks EO RLD file
@isREL BIT WhichType ;Is it a REL object file?
BMI DoPhase4 ;Yes
JMP ClsObjFile
;=================================================
; Phase 4 of the Linking process done only if
; the OBJECT file is of type REL
; Contents of TempRLD and TempESD files are appended
; to the relocatable OBJECT file
; Input
; Output
; ($2BDF)
DoPhase4
LDY #$07
JSR DisplayMsg
JSR DisplayCR
LDA WriteTmpRecP8+C_REFNUM ;RN of tempRLD file
STA SMarkBOFRecP8+C_REFNUM
JSR PRODOS8
DC.B $CE ;SET_MARK
DC.W SMarkBOFRecP8 ;Set file posn to BO tempRLD file
BEQ @1
JSR ErrHandler ;Don't come back
@1 JSR AppendTmpRLDESD ;Append tempRLD to OBJ file
LDA WriteTmpRecP8+C_REFNUM
JSR CloseAnyFile ;Now close tempRLD file
JSR AbortPause
JSR MovTmpESDName ;Set PN to TempESD
JSR PRODOS8
DC.B $C8 ;OPEN
DC.W Open2RecP8
BEQ @2
JSR ErrHandler ;Don't come back
@2 LDA Open2RecP8+C_OUTREF
STA WriteTmpRecP8+C_REFNUM
JSR AppendTmpRLDESD ;Append TempESD to REL OBJECT file
LDA WriteTmpRecP8+C_REFNUM
JSR CloseAnyFile ;Now close tempESD
LDA Open3RecP8+C_OUTREF
STA SMarkBOFRecP8+C_REFNUM ;Posn to BO REL OBJECT file
JSR PRODOS8
DC.B $CE ;SET_MARK
DC.W SMarkBOFRecP8
BEQ @3
JSR ErrHandler ;Don't come back
@3 LDA objCodeLen ;Write the CodeImage Len
STA X9100
LDA objCodeLen+1 ; of REL OBJECT file
STA X9100+1
LDA #0
STA Write3RecP8+C_REQCNT+1
LDA #2 ; which is 2 bytes
STA Write3RecP8+C_REQCNT
JSR PRODOS8
DC.B $CB ;WRITE
DC.W Write3RecP8
BEQ @4
JSR ErrHandler ;Don't come back
@4 JSR AbortPause
JSR OpenMapAppend ;Open LINKMAP file in append mode
JMP ClsObjFile
;===============================
;
; Read entire contents of tempRLD/tempESD and append
; it to the OBJECT file (which is of type REL)
;
; Input
; Output
; ($2C5A)
AppendTmpRLDESD
LDA WriteTmpRecP8+C_REFNUM ;RN of tempRLD/tempESD file
STA RWFileRecP8+C_REFNUM
JSR ReadChunk ;Read data chunk fr input file
PHP ;Save for later
BCC @1
CMP #$10
BEQ @1 ;Not EOF
JSR ErrHandler ;Don't come back
@1 LDA Open3RecP8+C_OUTREF ;OBJECT file's RN
STA RWFileRecP8+C_REFNUM ;Write same data chunk
LDA RWFileRecP8+C_TRANSCNT
STA RWFileRecP8+C_REQCNT
LDA RWFileRecP8+C_TRANSCNT+1
STA RWFileRecP8+C_REQCNT+1 ; to the OBJECT file
JSR PRODOS8
DC.B $CB ;WRITE
DC.W RWFileRecP8
BEQ @2
JSR ErrHandler ;Don't come back
@2 PLP ;Has last chunk been read?
BCS AppendTmpRLDESD ;No, do another chunk
RTS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ClsObjFile
LDA Open3RecP8+C_OUTREF ;Finally, close OBJECT file
JSR CloseAnyFile
BIT WhichType ;Was it relocatable OBJECT file?
BPL @skipMsg ;No
LDY #$07 ;Report "Phase 4 : Generating..."
JSR StoreMsgY
@skipMsg
BIT MapOption ;Output to LINKMAP?
BMI @sort ;Yes
JMP Phs5Done
@sort BIT SortOption ;Sort LoadMap table?
BMI DoPhase5 ;Yes
JMP Phs5Done
;=================================================
; Phase 5 of the Linking process
; Sort Relocated Adr table
; First create a LoadMap table of 4-byte records
; The LoadMap table starts @ $9100
; Layout of each record is:
; DW ptr to an ENTRY table rec
; DW relocated addr stored in the ENTRY table rec
;
; Output:
; (entRecP) - ptr to a rec in ENTRY table
; (Z86) - ptr to a rec in LoadMap table
; (Z80) - ptr to EO LoadMap table
; ($2CAB)
DoPhase5
LDY #$08
JSR DisplayMsg
JSR DisplayCR
LDY #$08
JSR StoreMsgY
LDA #<EntryTab ;NB. The ENTRY table is still in mem
STA entRecP ;Set up a ptr to its beginning
LDA #>EntryTab
STA entRecP+1
LDA #<X9100 ;4-byte records in LoadMap table
STA Z86
LDA #>X9100
STA Z86+1
LDA #0 ;Total # of records in
STA NumRecs ; ENTRY table to be sorted
STA NumRecs+1
; The code below builds the unsorted LoadMap table
@build JSR AbortPause
LDY #EntryRecord.symbolName
LDA (entRecP),Y ;EO ENTRY table?
BEQ @nomore ;Yes
LDA entRecP
STA (Z86),Y ;Points to record in ENTRY table
INY
LDA entRecP+1
STA (Z86),Y
LDY #EntryRecord.relAddr
LDA (entRecP),Y ;Get relocated addr associated with
PHA
INY
LDA (entRecP),Y ; the SymbolicName of the ENTRY rec
LDY #LoadMapRecord.sizeof-1
STA (Z86),Y ; and store in LoadMap record
PLA
DEY
STA (Z86),Y
LDA #LoadMapRecord.sizeof
LDX #Z86
JSR AdvNextRecZ ;Adv to next LoadMap rec
JSR AdvNxtEntry ;Adv to next ENTRY record
INC NumRecs ;rec count
BNE @1
INC NumRecs+1
@1 JMP @build ;Continue to build LoadMap table
; Initial LoadMap table has been build
@nomore LDY #LoadMapRecord.entryPtr
TYA ;(A)=0
STA (Z86),Y ;Mark EO LoadMap table
INY
STA (Z86),Y ; with a NULL
LDA Z86
STA Z80 ;(Z80)=EO LoadMap table
LDA Z86+1
STA Z80+1
JSR SortLoadMap ;Sort it
JMP Phs5Done
;===============================
; Sort the Load (addr) Map
; Shell-Metzner Sort
; Input
; Output
; ($2D19)
SortLoadMap
LDA NumRecs ;Jump := # of elements N
STA Jump
LDA NumRecs+1
STA Jump+1
; While Jump <> 0
WhileLoop
LSR Jump+1 ;Jump := Jump div 2
ROR Jump
LDA Jump
ORA Jump+1
BNE @1 ;Not done yet
RTS
@1 SEC
LDA NumRecs
SBC Jump
STA EndIndex
LDA NumRecs+1
SBC Jump+1
STA EndIndex+1
LDX #0
STX StartIndex+1
INX
STX StartIndex
ForLoop JSR AbortPause
; FOR JJJ := 1 to NumRecs-Jump
LDA StartIndex
STA JJJ
LDA StartIndex+1
STA JJJ+1
; REPEAT
RepeatLoop
CLC
LDA JJJ
ADC Jump
STA III ;I := J+Jump
LDA JJJ+1
ADC Jump+1
STA III+1
LDX #3
@cploop LDA JJJ,X
STA J_TH,X
DEX
BPL @cploop
; Mulby4 and add to X9100-4 ($90FC)
; Calculate indices to the elements to be compared
; (J_TH) - Ptr to j-th element
; (I_TH) - Ptr to i-th element
LDX #2
@mulLoop
ASL J_TH,X ;x4
ROL J_TH+1,X
ASL J_TH,X
ROL J_TH+1,X
CLC
LDA #<X9100-4
ADC J_TH,X
STA J_TH,X
LDA #>X9100-4
ADC J_TH+1,X
STA J_TH+1,X
DEX
DEX
BEQ @mulLoop
BIT IsNumSort ;alphabetic sort?
BPL AlfaSort ;Yes
; Sort load addresses numerically in ascending order
LDY #3
LDA (J_TH),Y ;Get load addr (Hibyte)
CMP (I_TH),Y
BEQ @eq
BCS @gt ;Greater than
@lt JMP NEXTJ ;Less than
@eq DEY
LDA (I_TH),Y ;Get load addr (lobyte)
CMP (J_TH),Y
BCS @lt ;Less than
@gt LDY #3
BNE SwapLoop ;Always -> Swap the records
; Sort SymbolicName alphabetically
; IF ENTRY[J].name > ENTRY[I].name then SWAP(Ary[J], Ary[I])
; The 1st field of an ENTRY rec is a 16-byte p-string
AlfaSort
LDY #0
LDA (J_TH),Y ;Get ptr to j-th
TAX ; ENTRY rec
INY
LDA (J_TH),Y
STA ENTRPJ+1
STX ENTRPJ
LDA (I_TH),Y
TAX
DEY ;=0
LDA (I_TH),Y ;Get ptr to i-th
STA ENTRPI ; ENTRY rec
STX ENTRPI+1
LDA (ENTRPJ),Y ;Get len byte of symbolic name
CMP (ENTRPI),Y
BEQ @LtOrEq
BCC @LtOrEq
LDA (ENTRPI),Y ;The len of this symbolic name is shorter
@LtOrEq TAX ;# of chars to compare
INY ;=1
@CmpLup LDA (ENTRPJ),Y ;Get char fr symbolic name
CMP (ENTRPI),Y
BNE @NoHit ;No match
INY
CPY #Str15.sizeof ;At most 15 chars will be compared
BCS NEXTJ ;All chars matched
DEX
BNE @CmpLup
LDA #SPACE
CMP (ENTRPJ),Y
BEQ NEXTJ
SEC ;flag we have to do a swap
@NoHit BCC NEXTJ ;C=0 -> 1st symbolic name < 2nd
; Swap the records in LoadMap
; Too costly to swap those in ENTRY table
LDY #3
SwapLoop
LDA (J_TH),Y ;Swap the ptrs as
TAX
LDA (I_TH),Y
STA (J_TH),Y ; well as the corr load addrs
TXA
STA (I_TH),Y
DEY
BPL SwapLoop
SEC
LDA JJJ ;J > Jump
SBC Jump
STA JJJ
LDA JJJ+1
SBC Jump+1 ;J := J - Jump
STA JJJ+1 ;Is J > Jump?
BMI NEXTJ ;No, less than
ORA JJJ
BEQ NEXTJ ;No, J := Jump
JMP RepeatLoop
; UNTIL JJJ =< Jump
NEXTJ INC StartIndex
BNE @1
INC StartIndex+1
@1 LDA StartIndex+1 ;Finish w/FOR loop?
CMP EndIndex+1
BCC @next
BEQ @3
@2 JMP WhileLoop ;No
@3 LDA EndIndex
CMP StartIndex
BCC @2
@next JMP ForLoop
;-----
Phs5Done
BIT MapOption ;Write LINKMAP?
BMI DoPhase6 ;Yes
JMP OK2Exit
;=================================================
; Phase 6 of the Linking process
; Makes use of LoadMap table to store info
; into the LINKMAP txtfile
; ($2E17)
DoPhase6
LDY #$09
JSR DisplayMsg
JSR DisplayCR
LDY #$09
JSR StoreMsg
JSR StoreCR
JSR ResetFilePos ;Reset to start of cmd line file
JSR StoreCR
JSR StoreCR
LDA #0
STA ModuleNbr
STA numSrcFiles ;reset counter
STA PageOption ;Don't output to printer
Phs6Loop
JSR AbortPause
JSR ReadOneCmd
BNE @doPN ;If non-blank & not cr, it's a PN
CMP #CR ;Is 1st char a CR?
BNE @1 ;No, a leading space, ignore it
JMP xfile ;No more directives
@1 JSR StoreCommand ;Just store command in LINKMAP file
JMP Phs6Loop ;Get another command
; Got the Pathname of a SRC file
@doPN JSR StoreCR
JSR StoreCR
LDY #$18 ;MOD ORG etc
JSR StoreMsg
LDY #$19 ;# ADR ADR etc
JSR StoreMsg
JSR StoreCR
JMP WrtLM1 ;-> proceed to start storing info
; Loop to get the PN of another src file
NxtSrcFile
JSR AbortPause
JSR ReadOneCmd
BNE WrtLM1 ;Not cr/space
CMP #CR
BEQ xfile ;No more commands => done
JSR StoreAddrs ;Set module's Addr Range
BEQ WrtLM2 ;always
; Start writing info into LINKMAP file
WrtLM1 JSR StoreSpace
LDA ModuleNbr
JSR StoreByte
JSR StoreSpace
JSR StoreSpace
LDX numSrcFiles ;Get SRC file index
WrtLM2 LDA orgAdrHi,X ;Starting Addr
JSR StoreByte
LDA orgAdrLo,X ; of this src module
JSR StoreByte
LDA #'-'
JSR StoreChar
LDA EndAddrHi,X ;Its Ending Addr
JSR StoreByte
LDA EndAddrLo,X
JSR StoreByte
JSR StoreSpace
JSR StoreSpace
LDY #0
@ploop JSR ChrGot ;Store its pathname
CMP #CR
BEQ @nxtFile
JSR StoreChar
INY
BNE @ploop
@nxtFile
JSR StoreCR
CPX numSrcFiles
BNE @nxtFile1
SED
LDA ModuleNbr
CLC
ADC #1
STA ModuleNbr
CLD
INC numSrcFiles
@nxtFile1
JMP NxtSrcFile ;Loop back for next module
xfile BIT XRefOption ;Did user ask for cross-ferencing?
BPL ExitPhase6 ;No
LDA #$80
STA PageOption
JSR doPageFeed ;Store column header details etc...
BIT SortOption ;Did we sort the LoadMap table?
BPL WrEntryRecs ;No
; Use Sorted LoadMap table
LDA #<X9100
STA Z86
LDA #>X9100 ;Points to BO LoadMap table
STA Z86+1
LMWrtLoop
JSR AbortPause
LDY #0
LDA (Z86),Y ;Get ptr to ENTRY record
STA Z88
INY
LDA (Z86),Y
STA Z88+1 ; and store it here
ORA Z88 ;EO ENTRY table?
BEQ ExitPhase6 ;Yes
JSR StoreEntryInfo ;Write details of ENTRY rec into LINKMAP
LDA #4 ;Pointer size
LDX #Z86 ; Z86++
JSR AdvNextRecZ ;Next LoadMap record
JMP LMWrtLoop
; Use ENTRY table instead of LoadMap table
WrEntryRecs
LDA #<EntryTab
STA Z88
LDA #>EntryTab
STA Z88+1
@wrLoop JSR AbortPause
LDY #0
LDA (Z88),Y ;EOT?
BEQ ExitPhase6 ;Yes
JSR StoreEntryInfo ;Store details of ENTRY rec into LINKMAP
LDX #Z88
LDA #EntryRecord.sizeof
JSR AdvNextRecZ ;Next ENTRY record
JMP @wrLoop ;Continue until EO ENTRY Table
;===============================
; Prepare to exit Linker
; Input
; Output
ExitPhase6
LDA #FF
JSR StoreChar
JSR StoreCR
LDA WriteMapRecP8+C_REFNUM ;Close LINKMAP txt file
STA CloseAnyRecP8+C_REFNUM
JSR PRODOS8
DC.B $CC ;CLOSE
DC.W CloseAnyRecP8
BEQ OK2Exit
JSR ErrHandler ;Don't come back
OK2Exit JMP DoExit ;Do an orderly exit
;===============================
; Get ORiGin and END address of the module
; Z=0, (X)=0
; ($2F43)
StoreAddrs
LDY #$05 ;Write 5 blanks to LINKMAP
JSR StoreYSpaces
LDX numSrcFiles ;Get SRC file index (1-49)
DEX ;index previous SRC module
LDY EndAddrHi,X
LDA EndAddrLo,X
TAX
INX
BNE @1
INY
@1 STX orgAdrLo
STY orgAdrHi
LDX numSrcFiles
LDY orgAdrHi,X
LDA orgAdrLo,X
TAX
BNE @2
DEY
@2 DEX
STX EndAddrLo
STY EndAddrHi
LDX #$00
RTS
;===============================
; Store info from ENTRY record
; Input
; Output
; ($2F74)
StoreEntryInfo
JSR WrtFlag ;Store space/?
JSR StoreAddress ;Relocated addr
JSR StoreFileNum ;File #
JSR StoreSpace
JSR StoreName ;Symbolicname
JSR StoreSpace
JSR StoreRefs ;list of references
JSR StoreCR
RTS
;===============================
; Store a byte as a couple of ASCII Hex digits
; Input
; (A)=byte
StoreByte
PHA
LSR A
LSR A
LSR A
LSR A
JSR StoreHex
PLA
AND #$0F
JSR StoreHex
RTS
;===============================
; Store char into LINKMAP buffer. If char is CR, the
; entire text line will be written out to file.
; Otherwise, it will be stored into the buffer
; Input
; WrMapFIdx - Write Map file buf index
; (A) = char to store
; Output
; A,X preserved
; Y may not be used
; ($2F9C)
StoreChar
AND #$7F
STA SaveA ;Save A,X regs
STX SaveA+1
LDX MapIndex
STA MapDataBuf,X ;store in buf
INC MapIndex ;incr # of chars/buf index
CMP #CR
BNE @Rst ;Delay write
; Flush it
JSR PRODOS8
DC.B $CB ;WRITE
DC.W WriteMapRecP8
BEQ @noErrs
JSR ErrHandler ;Don't come back
@noErrs STA MapIndex ;Zero write buf index
@Rst LDX SaveA+1 ;Restore A,X regs
LDA SaveA
RTS
;===============================
; Convert a 8-bit binary value into its
; ASCII representation of 1's and 0's
; Input
; Output
; ($2FC2) - Not used
Cnv2BinStr
LDX #8
@cnvlup ASL A ;Get bit into Carry
PHA
LDA #$00
ROL A ;Catch the bit
ADC #'0' ;'0' or '1'
JSR StoreChar
PLA
DEX
BNE @cnvlup ;Next bit
RTS
;===============================
; Store a CR to LINKMAP file
; Input
; Output
; ($2FD3)
StoreCR LDA #CR
JSR StoreChar
INC LineCnt
LDA LineCnt
CMP #60
BNE @ret
JSR doPageFeed ;Write column header
@ret RTS
;===============================
; Output a column header into LINKMAP file
; Input
; Output
doPageFeed
LDA #FF ;Output a formfeed char
JSR StoreChar
LDA #3
STA LineCnt
SED
CLC
LDA #1
ADC PageCnt
STA PageCnt
CLD
BIT PageOption
BPL @1
LDY #$1A ;Write 'ADR M# SYMBOL...' header
JSR StoreMsg ; string to LINKMAP file
LDA PageCnt
JSR StoreByte
@1 JSR StoreCR
JSR StoreCR
RTS
;===============================
; Input
; Output
; ($300B)
WrtFlag
LDY #EntryRecord.flags
LDA (Z88),Y
AND #unreferenced
BEQ StoreSpace ;Use a space for referenced symbols
LDA #'?'
BNE StorChar ;Use a Qn mark for unreferenced ones
;===============================
; Store a space into LINKMAP txt file buffer
StoreSpace
LDA #SPACE
StorChar
JSR StoreChar
RTS
;===============================
; Input
; (A)=$00-$0F
; Output
StoreHex
ORA #'0'
CMP #'9'+1
BCC @1
ADC #$06
@1 JSR StoreChar
RTS
;===============================
; Store a list of references to a relocated addr
; into the LINKMAP file
; $40 set -> not referenced by any module
; Input
; (Z88) - Ptr to an ENTRY record
; Output
; Trashed
; (xtrnRecP) - Ptr to an EXTRN record
; ($3029)
StoreRefs
LDY #EntryRecord.flags
LDA (Z88),Y
AND #unreferenced
BEQ @1
LDY #$16
JSR StoreMsg
RTS
@1 LDA Z88 ;NB. (Z88) is ptr to ENTRY record
STA xtrnRecP ;Use this zpage temporarily
LDA Z88+1
STA xtrnRecP+1
LDY #EntryRecord.head ;Start with the first node
@nloop LDA (xtrnRecP),Y
PHA ;Get ptr to "next" EXTRN record
INY
LDA (xtrnRecP),Y
STA xtrnRecP+1
PLA
STA xtrnRecP
ORA xtrnRecP+1
BEQ @done ;NULL => end of singly linked list
LDY #XtrnRecord.fileNum
LDA (xtrnRecP),Y ;(A)=# to be converted
LDY #0 ;ten's digit
JSR Cnv2S
JSR StoreSpace
LDA MapIndex ;# of bytes in Map file's data buf
LDY #0
CMP #77 ; must not exceed this number
BCC @nloop ;Next node
JSR StoreCR
LDY #26 ;# of spaces
JSR StoreYSpaces
LDY #0
JMP @nloop ;Next Node in linked list
@done RTS
;===============================
; Store REL file # as a 2-byte ASC char in LINKMAP file
; Input
; Output
; ($3073)
StoreFileNum
LDY #EntryRecord.fileNum
LDA (Z88),Y ;REL file #
LDY #0 ;This should be the entry point
Cnv2S CMP #10
BCC @1
SEC
SBC #10
INY ;TEN'S digit
JMP Cnv2S
@1 PHA ;UNIT'S digit
TYA
ORA #'0'
JSR StoreChar
PLA
ORA #'0'
JSR StoreChar
RTS
;===============================
; Store ENTRY record's symbolic name
; Input
; (Z88) - ptr to ENTRY record
; Output
; ($3092)
StoreName
LDY #EntryRecord.symbolName
LDA (Z88),Y ;Get its len byte
CMP #SymbolRecord.sizeof
BCC @1
LDA #SymbolRecord.sizeof-1 ;At most 15 chars
@1 TAX
@mloop INY
LDA (Z88),Y ;symbolname
JSR StoreChar
DEX
BNE @mloop
STY SYMLEN ;# of chars stored so far
SEC
LDA #SymbolRecord.sizeof
SBC SYMLEN
TAY ;# of spaces to store
; Enter here with (Y)=# of spaces to store
StoreYSpaces
LDA #SPACE
JSR StoreChar
DEY
BNE StoreYSpaces
RTS
;===============================
; Store Relocated address in LINKMAP file
; Input
; (Z88) - ptr to an ENTRY record
; Output
; ($30B9)
StoreAddress
LDY #EntryRecord.relAddr+1
LDA (Z88),Y
JSR StoreByte
DEY
LDA (Z88),Y
JSR StoreByte
JSR StoreSpace
RTS
;===============================
; Store command line including terminating CR
; Input
; (cp)
; Output
; ($30CA)
StoreCommand
LDY #0
@loop LDA (cp),Y
AND #$7F
JSR StoreChar
INY
CMP #CR
BNE @loop
RTS
;===============================
; If the flag of an RLD entry of SRC file indicates it is an
; (a) ENTRY symbol, calc relocated addr
; (b) EXTRN symbol, get relocated addr
; fr its associated ENTRY rec &
; we must modify the
; RLD & EXTRN recs
; Input
; RLDFlags
; Output
; RelAdr - value of relocated addr
; ($30D9)
GetRelAdr
LDA RLD_Flags
AND #external ;Is EXTERN symbol?
BNE @xtrn ;Yes
LDA RelAdr ;This is equivalent to a subtraction
CLC
ADC NegSrcORG ;2's complement of
STA RelAdr
LDA RelAdr+1
ADC NegSrcORG+1 ; Origin in SRC file
STA RelAdr+1
LDA RelAdr
CLC
ADC CurrORG
STA RelAdr
LDA RelAdr+1
ADC CurrORG+1
STA RelAdr+1
RTS
; EXTRN symbol
@xtrn LDY ModuleNbr ;Get ptr to the
LDA srcModTabLo,Y ; first EXTRN rec
STA xtrnRecP ; of the SRC file
LDA srcModTabHi,Y
STA xtrnRecP+1
; Search thru the EXTRN recs for the EXTRN symbol #.
; NB. A hit is guaranteed during the search
; through the sub-array of EXTRN recs
LDA #0
STA RelAdr
STA RelAdr+1
LDY #RLDRecord.esdNum
LDA (srcP),Y ;Get the EXTRN symbol #
@srch LDY #XtrnRecord.symbolNum
CMP (xtrnRecP),Y
BEQ @hit ;Matched
JSR AdvNxtExtrn
JMP @srch ;Try next EXTRN rec
@hit LDY #XtrnRecord.flags
LDA (xtrnRecP),Y
AND #$FF-unreferenced ;Clear the bit
STA (xtrnRecP),Y
AND #undefined ;Is the symbolicname still undefined?
BNE @CkFtype ;Yes
LDY #XtrnRecord.entryPtr
LDA (xtrnRecP),Y ;Get ptr to associated
STA Z82 ; ENTRY record
INY
LDA (xtrnRecP),Y
STA Z82+1
LDY #EntryRecord.relAddr
LDA (Z82),Y
STA RelAdr
INY
LDA (Z82),Y
STA RelAdr+1
BIT WhichType ;Is it OBJECT file relocatable?
BPL @doRTS ;No, just ret
; The OBJECT file is of type REL so
; we need to patch the curr RLD rec
LDY #RLDRecord.flags
LDA (srcP),Y ;Mark symbol is no longer an EXTRN-type
AND #$FF-external
STA (srcP),Y ; since symbolicname is defined
LDY #RLDRecord.low8bits
AND #%11000000
CMP #$40 ;lo 8 bits?
BNE @1 ;=>hi 8 bits
LDA RelAdr ;Use lo 8-bits to patch
DC.B $2C
@1 LDA #0 ;Use a zero to patch
STA (srcP),Y ; the RLD record
JMP @doRTS ;Done
; The symbolicname had not been defined
@CkFtype
BIT WhichType ;Is OBJECT file of type REL?
BPL @doRTS ;No
; The target OBJECT file is REL so
; patch the RLD entry of the SRC file
; Once again we assume the RLD is < 5K
; since the patched RLD is only written out
; when processing of the SRC file is complete
LDY #XtrnRecord.externNum
LDA (xtrnRecP),Y ; Take the EXTRN # assigned by the Linker
LDY #RLDRecord.esdNum ; & replace that in the RLD rec which
STA (srcP),Y ; was assigned by the Assembler
@doRTS RTS
;===============================
; Setup to open and write a TempRLD binary file;
; any old file will be deleted prior to this.
; Input
; Output
; Write2P+c.refNum - RN to write tempRLD file
; ($317A)
OpenTmpRLD
LDY TempRLDName
@cloop LDA TempRLDName,Y
STA pathNameBuf,Y
DEY
BPL @cloop
JSR PRODOS8
DC.B $C1
DC.W DestroyRecP8 ;DESTROY
LDA #BIN_type
STA CreateRecP8+C_FILEID
JSR PRODOS8
DC.B $C0 ;CREATE
DC.W CreateRecP8
BEQ @1
JSR ErrHandler ;Don't come back
@1 JSR PRODOS8
DC.B $C8 ;OPEN
DC.W Open2RecP8
BEQ @2
JSR ErrHandler ;Don't come back
@2 LDA Open2RecP8+C_OUTREF
STA WriteTmpRecP8+C_REFNUM ;write RN of tempRLD file
RTS
;===============================
; Append a patched RLD of curr SRC file to the tempRLD file
; Input
; Output
; ($31AE)
AppendTmpRLD
BIT WhichType ;Is OBJECT file of type REL?
BPL doRTS2 ;No
SEC
LDA srcP
SBC #<srcDataBuf
STA WriteTmpRecP8+C_REQCNT ;writelen
LDA srcP+1
SBC #>srcDataBuf
STA WriteTmpRecP8+C_REQCNT+1
; Write to tempRLD file
WrtTempRld
JSR PRODOS8
DC.B $CB ;WRITE
DC.W WriteTmpRecP8
BEQ doRTS2
JSR ErrHandler ;Don't come back
doRTS2 RTS
;===============================
; Open the LINKMAP file and set the
; file posn to its EOF
;
; Input
; Output
; ($31CD)
OpenMapAppend
JSR MoveMapName ;Set PN to LINKMAP
JSR PRODOS8
DC.B $C8 ;OPEN
DC.W Open2RecP8
BEQ @1
JSR ErrHandler ;Don't come back
@1 LDA Open2RecP8+C_OUTREF
STA WriteMapRecP8+C_REFNUM
STA EOFRecP8+C_REFNUM
JSR PRODOS8
DC.B $D1 ;GET_EOF
DC.W EOFRecP8
BEQ @2
JSR ErrHandler ;Don't come back
@2 JSR PRODOS8
DC.B $CE ;SET_MARK
DC.W EOFRecP8 ;Set to EO LINKMAP file
BEQ @ret
JSR ErrHandler ;Don't come back
@ret RTS
;===============================
; Check if cmd line is an ALN Command/Directive
; Input
; Output
; Z=1 & C=0 - yes
; ($31FB)
IsAlign
JSR ShowLineBuf
JSR SkipSpaces
JSR ChkDirective
BCS @ret ;Unknown cmd
CMP #5
CLC
@ret RTS
;=================================================
; Load EDASM's Editor. EdAsm's Command Interpreter
; is always resident in memory.
; ($320A)
;=================================================
LoadEditor
JSR PrefixEdAsm ;Set prefix to EdAsm's dir
BCC @load
LDA #$FE ;EdAsm Command Interpreter's error #
JSR PrintError
LDY #0
LDX EdAsmDir ;Get its len byte
@loop LDA EdAsmDir+1,Y
JSR DisplayChar
INY
DEX
BNE @loop
JSR DisplayCR
LDA #$FD ;Output thru EdAsm's Interpreter
JSR PrintError ; display error rtn
@key1 LDA KBD
BPL @key1
BIT KBDSTROBE ;Clear it
CMP #CR+$80
BNE @key1
JSR DisplayCR
JMP LoadEditor ;Try again
@load LDA #<LoadAdrEditor
STA ReadEditorRecP8+C_DATABUF
LDA #>LoadAdrEditor
STA ReadEditorRecP8+C_DATABUF+1
LDA #<$2000
STA ReadEditorRecP8+C_REQCNT
LDA #>$2000
STA ReadEditorRecP8+C_REQCNT+1
JSR PRODOS8
DC.B $C8 ;OPEN
DC.W OpenEditorRecP8
BEQ @opened
JSR FatalError
@opened LDA OpenEditorRecP8+C_OUTREF ;file is there
STA ReadEditorRecP8+C_REFNUM
JSR PRODOS8 ;READ
DC.B $CA
DC.W ReadEditorRecP8
BEQ @read
JSR FatalError
@read LDA ReadEditorRecP8+C_REFNUM
STA CloseAnyRecP8+C_REFNUM ;file now in memory
JSR PRODOS8
DC.B $CC ;CLOSE
DC.W CloseAnyRecP8
BEQ @setup
JMP FatalError
@setup JSR S2CurrPfx
BCS FatalError
;=================================================
; Setup memory map for the EdAsm's Editor Module
; Memory pages mark as used: $9B-$A7, $B1-$B8, $BF
; EDASM's Interpreter is at $B100-$BD00
;=================================================
LDA #%11111111 ;$FF: pages $A0-A7 are used
STA MemoryMap+20
LDA #%00011111 ;$1F: free pages $98-$9A
STA MemoryMap+19
LDA #%01111111 ;$7F: free pages $B0
STA MemoryMap+22
LDA #%10000001 ;$81: free pages $B9-$BE
STA MemoryMap+23
; TxtBgn=$0801
LDA #CR
DEC TxtBgn ;Put a CR @ mem locations
LDY #$00
STA (TxtBgn),Y
INC TxtBgn ; $0800 and $0801
STA (TxtBgn),Y
RTS
;=================================================
; ($32A4)
FatalError
STA $FE ;Save err code
TSX
STX $FF ;Save stack ptr here
LDX #$80
TXS
LDA RDROM2 ;Read ROM; no write
JSR SETKBD ;reset input to keyboard
JSR SETVID ;reset output to screen
JSR HOME ;clear screen and home cursor
JSR PRERR ;print "ERR"
JMP MON ;std monitor entry w/beep
;=================================================
; Set prefix to EDASM's dir
;=================================================
PrefixEdAsm
JSR PRODOS8
DC.B $C6 ;SET_PREFIX
DC.W EdAsmPfxRecP8
RTS
;=================================================
; Set prefix to current prefix
;=================================================
S2CurrPfx
JSR PRODOS8
DC.B $C6 ;SET_PREFIX
DC.W SetCurrPfxRecP8
RTS
;=================================================
; EDASM Editor's P8 parameter blocks
;=================================================
EditorName
STR 'EDASM.ED'
DC.B $00
; Use to open EdAsm's Editor
OpenEditorRecP8
DC.B $03
DC.W EditorName
DC.W XA900 ;1024-byte buffer required by P8
DC.B $CB ;ref #
; Use to read EdAsm's Editor into memory
ReadEditorRecP8
DC.B $04
DC.B $D0
DC.W $A0A0
DC.W $A0D3 ;Caller must set this
DC.W $CBA0 ;actual len read (ignore)
; Use to set prefix to EdAsm's directory on disk
EdAsmPfxRecP8
DC.B $01
DC.W EdAsmDir
SetCurrPfxRecP8
DC.B $01
DC.W currPfxBuf
;=================================================
; Move a block of src code fr one mem location to
; another mem location (but not including byte @
; location Z80)
; Input
; srcP - Start addr of data
; Z80 - End addr of data
; Z82 - Destination addr
; Output
; (Z82)
; (srcP)
; (Y)=0
MoveData
LDY #0
@mvLup3 LDA (srcP),Y
STA (Z82),Y
INC Z82
BNE @1
INC Z82+1
@1 LDA srcP ;Copy until
CMP Z80
LDA srcP+1
SBC Z80+1 ; (Z80)=(srcP)
INC srcP
BNE @2
INC srcP+1
@2 BCC @mvLup3
RTS
;=================================================
; These rtns adjust the ptrs to the next
; element (record) of their respective arrays (table)
; ($3307)
AdvNxtExtrn
PHA ;Save Acc temporarily
LDA #XtrnRecord.sizeof
LDX #xtrnRecP
JMP AdvNextRec
AdvNxtEntry
PHA
LDA #EntryRecord.sizeof
LDX #entRecP
JMP AdvNextRec
AdvNxtSymbol
PHA ;Save Acc temporarily
LDA #SymbolRecord.sizeof
LDX #symP
;
; (A)=# to add to pointer stored in 2 consecutive mem locations
; (X)=offset into zero page
AdvNextRec
CLC
ADC $00,X
STA $00,X
LDA #0
ADC $00+1,X
STA $00+1,X
PLA ;Restore Acc
RTS
;===============================
; Same logic as above except (X) can be an index into
; ANY zeropage location
; Input
; (A)=# to add to pointer stored in 2 consecutive mem locations
; (X)=offset into zero page
;
; Output
AdvNextRecZ
PHA
JMP AdvNextRec
;===============================
; Ref pg 229 ProDOS Assembler Tools Manual
; Advance srcP to next ESD record
; Input
; Output
; (srcP) = Pointing @ next ESD record or $00
; X - unchanged
NxtESDRec
LDY #0
@loop LDA (srcP),Y ;ENTRY/EXTRN symbolic name
BPL @1 ;Got last char
INY
JMP @loop
@1 INY ;Index past the last char
INY
INY
INY ;Now indexing next ESD rec (if any)
TYA
CLC
ADC srcP ;srcP now pointing @ next ESD
STA srcP
LDA #0
ADC srcP+1 ; record in the curr src file
STA srcP+1
RTS
;=================================================
; There are 3 entry points in this part of the code
; Input
; OpenSrcRecP8+c.outRef - file ref # of src (REL) file
; Output
; C=0 - Last chunk of data had been read
; C=1 & (A)=$10 - Not EOF
; C=1 & (A)=$4C - EOF
; (srcP) points to BO srcDataBuf
; ($3348)
;=================================================
ReadMax
LDA OpenSrcRecP8+C_OUTREF
STA RWFileRecP8+C_REFNUM
; Use this entry point to attempt to read a fixed chunk
; of data (equal to the size of the data buffer) fr a
; ANY file into the beginning of the Data Buffer ($0C00)
; (srcP) points to BO of this data buf (srcDataBuf)
ReadChunk
LDA #<srcDataBuf
STA RWFileRecP8+C_DATABUF
LDA #>srcDataBuf
STA RWFileRecP8+C_DATABUF+1
LDA #<FileDataBufSiz ;# of bytes to be read=5K
STA RWFileRecP8+C_REQCNT
LDA #>FileDataBufSiz
STA RWFileRecP8+C_REQCNT+1
; Use this entry point to read a chunk of data fr ANY file.
; Caller must set the # of bytes to read (reqCnt) in
; RWFile parm block.
; (srcP) is set to point to start of srcDataBuf ($0C00)
GetMoreCode
LDA #<srcDataBuf
STA srcP
LDA #>srcDataBuf
STA srcP+1
JSR PRODOS8
DC.B $CA ;READ
DC.W RWFileRecP8
BNE ReadErrs ;If EOF, (A)=$4C and C=1
; After a successful read, at most NumRead = Request Length
; For this case, there may be more data to be read
LDA RWFileRecP8+C_TRANSCNT+1 ;If actual # of bytes read
CMP RWFileRecP8+C_REQCNT+1 ; = requested len then
BNE LastChunk ; it may not be EOF since
LDA RWFileRecP8+C_TRANSCNT
CMP RWFileRecP8+C_REQCNT
BEQ GotMore ; there may be more data to be read
LastChunk
CLC ;NOT =, ==> last chunk of data read
RTS ; since NumRead < ReqLen
GotMore
LDA #$10 ;= but not EOF, so use $10 to flag it
ReadErrs
SEC
RTS
;=================================================
; Print Message
; The terminating char of each message in this table
; is a backslash
; Input
; (Y) = index into Message Table whose addresses
; are split into 2 sub-tables
; Output
; ($3388)
DisplayMsg
LDA MsgTabLo,Y ;(Y) = message #
STA msgP
LDA MsgTabHi,Y
STA msgP+1
LDY #0
@sloop LDA (msgP),Y
CMP #'\' ;terminator
BEQ @done
JSR CharOut
INY
JMP @sloop
@done RTS
;=================================================
; Setup the pathname buffer using a cmd line
; Input
; Output
; ($33A2)
GetSrcPathName
LDY #-1 ;=0 on fall thru
@mvLoop INY
LDA (cp),Y
AND #$7F ;Ensure filename std ASCII
STA pathNameBuf+1,Y
CMP #CR ;CR
BNE @mvLoop
STY pathNameBuf ;len byte
RTS
;=================================================
; Open a src file by getting its filename from
; the command file.
; Get len of its code image and compute the
; addr past its last byte.
;
; Input
;
; Output
; C=1 - err
; (A)=err code
; (Z9E)=$80 - src file will be read but EXTRN records will
; not be created fr its ESD. Its code will not be included into
; the OBJECT file. ENTRY and Symbol records are created.
; This may be used to facilitate overlays rather than
; hand-patching JSR/JMP etc addresses
; Todo: Check it
; NB: Symbol records are created fr info in the
; appended ESD of all SRC files.
; ($33B4)
OpenSrcFile
LDY #0
STY Z9E
LDA (cp),Y
CMP #'*'
BNE @2
INC cp ;Skip to next char
BNE @1
INC cp+1
@1 LDA #$80 ;Flag code from this SRC file
STA Z9E ; will NOT be included in OBJ file
@2 JSR GetSrcPathName ;First get the SRC file name
JSR PRODOS8
DC.B $C8 ;OPEN
DC.W OpenSrcRecP8
BNE @bad
JSR PRODOS8
DC.B $C4 ;GET_FILE_INFO
DC.W GetFileInfoRecP8
BNE @bad
LDA #$11 ;Anticipate a filetype match
LDY srcType ;Check its filetype
CPY #REL_type
BNE @bad ;filetype mismatch
LDA OpenSrcRecP8+C_OUTREF ;Prepare to read 1st 2 bytes of this
STA ReadCodeLenRecP8+C_REFNUM ; file which is len of code image
JSR PRODOS8 ;READ
DC.B $CA
DC.W ReadCodeLenRecP8
BNE @bad
LDA srcCodeLen
CLC
ADC srcORG ;Value of last ORG in this SRC file
STA objCurrSize
LDA srcCodeLen+1
ADC srcORG+1
STA objCurrSize+1 ;This is actually current size of obj file
LDA srcORG ;Perform 2's complement of the
EOR #$FF
STA NegSrcORG ; the last recorded ORG addr of SRC file
LDA srcORG+1
EOR #$FF
STA NegSrcORG+1
INC NegSrcORG
BNE @good
INC NegSrcORG+1
@good CLC
RTS
@bad SEC
RTS
;===============================
; Read in a line of text from command file
; See description below
; ($3421)
ReadOneCmd
JSR PRODOS8
DC.B $CA ;READ
DC.W ReadCmdRecP8
BEQ ResetCharPos ;Set cp to start of cmdline buf
CMP #$4C ;Is it EOF?
BEQ @ok ;Yes
JSR ErrHandler ;Don't come back
@ok JSR ResetFilePos ;Reset file posn to BO SRC file
LDA #CR ;Store CR @ BO buffer to
STA CmdLineBuf ; denote an empty (blank) line
JMP ResetCharPos ;Set cp to point @ cmd line buf
;===============================
; Reset file position to start of the command file
; Output
; cp - ptr to 1st char of Cmd Line
; (A) - 1st char
; Z=1 - 1st char is CR/SPACE
; Z=0 - Otherwise
; ($343B)
ResetFilePos
JSR PRODOS8
DC.B $CE ;SET_MARK
DC.W MarkCmdRecP8
BEQ ResetCharPos
JSR ErrHandler ;Don't come back
ResetCharPos
LDA #<CmdLineBuf
STA cp
LDA #>CmdLineBuf
STA cp+1
LDY #0
LDA (cp),Y ;Get 1st char of cmd line
CMP #SPACE ;Z=1 if space
BEQ @doRTS
CMP #CR ;Z=1 if CR
@doRTS RTS
;=================================================
; ($3459)
; Close any type of file
; Input
; (A)=file ref #
;
; Output
CloseAnyFile
STA CloseAnyRecP8+C_REFNUM
JSR PRODOS8
DC.B $CC ;CLOSE
DC.W CloseAnyRecP8
BEQ @doRTS
JSR ErrHandler ;Don't come back
@doRTS RTS
;===============================
; Display contents of the Linker's Command Line Buffer
;
; Input
; cp - ptr to the cmdline buf
; (A) & (P) are preserved
; ($3466)
ShowLineBuf
PHP ;Save Status reg
PHA ;Save char
LDA #SPACE
JSR CharOut
JSR CharOut
JSR CharOut
JSR CharOut
JSR CharOut
LDY #0
@loop LDA (cp),Y
AND #$7F
JSR CharOut
INY
CMP #CR ;If not terminating CR,
BNE @loop ; display next char
PLA
PLP
RTS
;=================================================
; Parse directive field
; Input
; cp - pointing @ 1st char of cmdline's
; directive field
; Output
; C=0, (A)-index into JMP table
; C=1 - Unknown command
; ($348C)
;=================================================
ChkDirective
LDX #-1
NxtDrtv LDY #0
@cmLoop INX
LDA DirectivesTab,X
BEQ @err ;EOT
LDA (cp),Y
CMP DirectivesTab,X
BEQ @1 ;Got a match
CPY #3 ;Did we have a 3-char match?
BNE @skip ;No, try next entry
CMP #CR ;EO cmd line?
BEQ @gotHit ;Yes
@1 INY ;bump index to next char
CPY #4
BCC @cmLoop
BEQ @gotHit ;All chars match including trailing space
@skip CPY #3
BEQ NxtDrtv ;Loop back to check another entry
INX
INY
BNE @skip ;Skip rest of entry
@err LDY #$1B ;Unknown command
JSR DisplayMsg
SEC
RTS
@gotHit TXA ;compute index
LSR A
LSR A
CLC
RTS
;=================================================
; Start fr beginning of Cmd Line, skip blanks
; Output
; Z=1 - CR/SPACE
SkipSpaces
LDY #0
@sloop LDA (cp),Y
CMP #SPACE
BNE AdvCP
INY
BNE @sloop
; In case we can't find a non-blank, fall
; thru to start searching fr the 2nd char
; Output
; (Y) - indexing the 1st non-blank
; (A) - CR or blank
WhiteSpc
LDY #0
@loop INY
LDA (cp),Y
CMP #SPACE
BEQ @done
CMP #CR
BNE @loop
@done RTS ;Z=1 if CR/SPACE
;=================================================
; Advance cmd line buffer pointer (cp)
; Input
; (Y) - # of chars to advance
; Output
; (Y) = 0
; ($34D9)
AdvCP
TYA
CLC
ADC cp
STA cp
BCC @1
INC cp+1
@1 LDY #0
RTS
;===============================
; These rtns transfer control
; the monitor's I/O handlers
GetLine BIT RDROM2 ;Read ROM; no write
JMP GETLN ;Use MON's Input line w/prompt
DisplayCR
BIT RDROM2 ;Read ROM; no write
JMP CROUT ;Issue a carriage return
DisplayChar
BIT RDROM2 ;Read ROM; no write
JMP COUT ;As set by EdAsm's Interpreter
;=================================================
; Input
; (A)=char to display
; Preserved
; (A)
CharOut
PHA ;Save char
CMP #'a'
BCC @1
CMP #'z'+1
BCS @1
AND #$DF ;to uppercase
@1 ORA #$80 ;ensure msb on
JSR DisplayChar ;Calls actual output rtn
PLA
PHA
CMP #CR
BNE @2
JSR AbortPause
@2 PLA
RTS
;===============================
; Evaluate operand field
; No fancy stuff like * / + -
; ($3513)
EvalExpr
LDY #0
STY Value16 ;Zero the value
STY Value16+1
DEY ;=-1 cos we are going to incr
JSR ChrGet ; Y-reg b4 getting char fr buf
CMP #'$'
BNE Dec2Int ;Decimal str
; Convert str representing a hexdec value into an integer
Hex2Int JSR ChrGet
BEQ doRTS3 ;cr/space
JSR IsCharHex ;Is char hexdec?
BCS SYNERR1 ;No
JSR ShiftHexDec ;Accomodate the incoming digit
BCC Hex2Int ;Process next char
BCS SYNERR1
doRTS3 RTS
; Not referenced
PLA ;WHAT'S this?
SYNERR1 JSR CmdSynErr ;Syntax err
;=================================================
; Convert string representation of a decimal value to an integer
;
; Input
; Output
; ($3537)
;=================================================
Dec2Int
DEY
@cnv1 JSR ChrGet
BEQ doRTS3 ;If cr/space, ret
JSR IsCharDec ;Is it numeric?
BCS SYNERR1 ;No, err
JSR ShiftDecimal ;Accomodate the incoming digit
BCC @cnv1 ;Get next char
BCS SYNERR1 ;Always
ShiftDecimal
JSR MUL2
BCS @ovflw3 ;Overflow
LDA Value16+1
PHA
LDA Value16
JSR MUL2
BCS @ovflw1 ;Overflow
JSR MUL2
BCS @ovflw1 ;Overflow
ADC Value16
STA Value16
PLA
ADC Value16+1
STA Value16+1
BCS @ovflw3 ;Overflow
JSR ChrGot
SEC
SBC #'0'
CLC
ADC Value16
STA Value16
BCC @ovflw3
INC Value16+1
BEQ @ovflw2 ;Overflow
CLC
RTS
@ovflw1 PLA
@ovflw2 SEC
@ovflw3 RTS
MUL2 ASL Value16
ROL Value16+1
RTS
;=================================================
; Shift in the hex value into running value
; Input
; (A) = '0'-'9' or $3A-$3F
; Output
; (Value) = running hex value
;=================================================
ShiftHexDec
SEC
SBC #'0' ;$00-$0F
ASL A
ASL A
ASL A
ASL A
LDX #4
@rloop ASL A
ROL Value16
ROL Value16+1
DEX
BNE @rloop
RTS
;=================================================
; This rtn has 2 entry points
; Input
; cp = ptr into cmd line buffer
; Output
; Z=1 - char is space or cr
; (A) - char (converted to uppercase)
; ($3595)
;=================================================
ChrGet INY ;bump index first
ChrGot LDA (cp),Y
AND #$7F ;Strip msb of char
CMP #'a'
BCC @1 ;Don't convert to ucase
AND #$DF ;ucase
@1 CMP #SPACE
BEQ @ret
CMP #CR
@ret RTS
;=================================================
; Is char btwn '0'-'9'
; Input
; Output
; C=0 yes
;=================================================
IsCharDec
CMP #'9'+1
BCS NoGud
CMP #'0'
BCC NoGud
CLC
RTS
NoGud SEC
RTS
;=================================================
; Check for hexdec char '0'-'9' and 'A'-'F'
; If char is 'A'-'F', convert to a value
; btwn $3A-$3F and return with C=0
; Input
; Output
;=================================================
IsCharHex
CMP #'A'
BCC IsCharDec ;chk for numeric char
CMP #'F'
BCS NoGud
SBC #$06 ;Make it $3A-$3F
CLC
RTS
;=================================================
; Check for a keypress. If
; Ctrl-C - Abort of linking process
; spacebar - Pause
; ($35BF)
AbortPause
LDA KBD
BPL @ret
BIT KBDSTROBE ;turn off keypressed flag
CMP #CTRLC+$80
BNE @ckspc
LDY #$1C ;Abort err #
JSR DisplayMsg
LDY #$1C
JSR StoreMsg
JMP DoBreak
@ckspc CMP #SPACE+$80 ;Is space bar depressed?
BNE @ret
@wloop LDA KBD ;Yes
BPL @wloop ;Wait for any keypress
@ret RTS
;=================================================
; Output thru EdAsm Interpreter Print Error rtn
; Don't return to the caller
; Input
; (A) - error code
; ($35E2)
ErrHandler JSR PrintError
JMP DoBreak
;=================================================
DupCmdErr
LDY #$10
JMP GoShowMsg
;
OptionError
LDY #$0F
JMP GoShowMsg
CmdFileErr
LDY #$0E
JMP GoShowMsg
WrongOrder
LDY #$02
JMP GoShowMsg
UnknownCmdErr
LDY #$1B
JMP GoShowMsg
RLDESDErr
LDY #$11
JMP GoShowMsg
ExtrnErr
LDY #$17 ;>255 EXTRN's
JMP GoShowMsg
CmdSynErr
LDY #$01
; $360D
GoShowMsgZ
JMP GoShowMsg
GoShowMsg
JSR DisplayMsg
;=================================================
; All the above errors will come here
; Close all files. Check for a ctrl-B
; If so, exit to monitor else re-load EdAsm.ED
; & transfer control to the editor
; Input
; Output
; ($3613)
DoBreak
LDA CmdAdr ;last MLI call return address
PHA
LDA CmdAdr+1
PHA
LDA #$01
STA CloseAllRecP8
LDA #$00
STA CloseAllRecP8+C_REFNUM
JSR PRODOS8
DC.B $CC ;CLOSE
DC.W CloseAllRecP8
PLA
STA CmdAdr+1
PLA
STA CmdAdr ;last MLI call return address
BIT KBDSTROBE ;turn off keypressed flag
BIT RDROM2 ;Read ROM; no write
JSR RDKEY ;Input char with cursor
CMP #CTRLB+$80
BNE Abort
TSX
STX StackSave
LDX #$80
TXS
LDA ROMIN2 ;read ROM/write LCbank2 (RR)
LDA ROMIN2
JMP MON ;std monitor entry w/beep
Abort JSR SetupEditor ;Proceed to load & then
JMP USRADR ; xfer control to EdAsm.Ed
;=================================================
; Put everything back in order
; Input
; Output
; Currently EI's ctrl-Y vector points @ $B198
; If EXEC mode is on, the entry is modified to $B1AB
; which is EdAsm's Interpreter MainLoop.
; ($3655)
;=================================================
DoExit
LDA OpenCmdRecP8+C_OUTREF
JSR CloseAnyFile ;Close the command file
JSR SetupEditor ;Load file and setup its memmap
BIT ExecMode ;Was cmd file EXEC from Editor?
BMI @1 ;Yes
JMP USRADR ;Exit via ctl-Y vector
@1 CLC
LDA USRADR+1 ;Setup the ctl-Y vector
ADC #$13 ;$B1AB-$B198
STA JumpAdr+1 ;Self-modifying code
LDA USRADR+2
ADC #$00
STA JumpAdr+2
BIT ROMIN2 ;read ROM/write LCbank2 (RR)
BIT ROMIN2
LDX #$F8 ;Set H/W stack
TXS
JumpAdr
JMP USRADR ;After patching, no longer JMP via ctl-Y vector
;=================================================
; Load EDASM's Editor & set up its memory map
; Input
; Output
; ($3682)
;=================================================
SetupEditor
JSR LoadEditor ;Load EDASM.ED
LDA #%01111111 ;$7F: free pages $B0
STA MemoryMap+22 ;P8 memory MemoryMap
LDA #%10000001 ;$81: free pages $B9-$BE
STA MemoryMap+23
LDA TxtBgn ;No file in mem
STA TxtEnd
LDA TxtBgn+1
STA TxtEnd+1
RTS ;Location:$3697
;=================================================
; Phase 1 uses 2 bytes from this table. However, the
; locations accessed should be $3698 and $369A
; & not $3697 and $3699. The bytes should be
; addr hi of the EXTRN & ENTRY tables
; ($3698)
L3698 DC.B $71 ;ENTRY table must be < $7100
DC.B $00
DC.B $91 ;EXTRN table must be < $9100
BitsTab DC.B $80,$40,$20,$10,$08,$04,$02,$01
; Default filenames of workfiles
AUTOLNKS STR 'EDASM.AUTOLINK'
DC.B $00
TempESD STR 'EDASM.TEMPESD'
DC.B $00
TempRLDName STR 'EDASM.TEMPRLD'
DC.B $00
;=================================================
DirectivesTab
DC.B 'BIN '
DC.B 'REL '
DC.B 'SYS '
DC.B 'ORG '
DC.B 'OPT '
DC.B 'ALN '
DC.B $00 ;Marks end of table
;
; JMP table ($36EA)
;
CmdTabLo
DC.B CmdBIN-1 ;Lo
DC.B CmdREL-1
DC.B CmdSYS-1
DC.B CmdORG-1
DC.B CmdOptions-1
DC.B CmdALN-1
CmdTabHi
DC.B (CmdBIN-1)>>8 ;Hi
DC.B (CmdREL-1)>>8
DC.B (CmdSYS-1)>>8
DC.B (CmdORG-1)>>8
DC.B (CmdOptions-1)>>8
DC.B (CmdALN-1)>>8
;=================================================
; ($36F6)
OptionsTab
DC.B 'MESXNDP'
DC.B $00
LinkObjName STR 'EDASM.LINKOBJ' ;65-byte buffer for pathname
DS.B $33 ;51
LinkMapName STR 'EDASM.LINKMAP' ;65-byte buffer for pathname
DS.B $33 ;51
CmdLineBuf DCB.B 128,SPACE ;Command Line Buffers
Origin DC.W $A0B0 ;Set by cmd/AuxType of 1st SRC file
srcCodeLen DC.W $A0A0 ;len of code image of SRC file
NegSrcORG DC.W $A0CC ;2's complement of a SRC file's Origin
objCurrSize DC.W $A0BE ;Addr+1 of code image
RelAdr DC.W $A0FF ;Relocated Adr
; Work area for a 3-byte trailer of an ESD record.
; The layout of this work area is as follows:
; offset Meaning
; 0 DB symbol flag's byte
; If ENTRY-type symbol
; 1 DW offset from start of code image
; If EXTRN-type symbol
; 1 DB symbol number referred to by RLD record
; 2 DB 0
ESDWrkRec DS ESDRecord
; DC.B $A0
; DC.B $A0
; DC.B $FE
RLD_Flags DC.B $A0 ;RLD flag-byte
ModuleNbr DC.B $A0 ;source file count/Module Number
numSrcFiles DC.B $A0 ;Counter
TargetObjType DC.B $00 ;OBJECT filetype
; Table of ptrs to 1st EXTRN rec of each SRC file
; within the EXTRN table.
srcModTabLo DS.B 50
srcModTabHi DS.B 50
; Position counter of beginning of code image (ORG ADRS)
; within the OBJECT file for src file module #s 0-49
orgAdrLo DS.B 50
orgAdrHi DS.B 50
; Position counter of end of code image (END ADRS) within
; the OBJECT file for src file module #s 0-49
EndAddrLo DS.B 50
EndAddrHi DS.B 50
;=================================================
; General purpose pathname work area.
; Set this b4 opening a disk file.
; ($393D)
pathNameBuf DS.B 64 ;Should be 65!
MapDataBuf DCB.B 90,SPACE ;data buf for LINKMAP;
SYMLEN DC.B $A0 ;temp store for len of symbolicname
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Use to open source file(s) which are of type REL
OpenSrcRecP8
DC.B $03
DC.W pathNameBuf
DC.W srcIOAddr ;1024-byte buf for ProDOS
DC.B $00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ProDOS parameter blocks for Command File which
; is a TXT file. Each text line is terminated by a CR
OpenCmdRecP8
DC.B $03 ;count
DC.W pathNameBuf ;PathName
DC.W XA900 ;1024-byte buf required by P8
DC.B $00
ReadCmdRecP8
DC.B $04 ;count
DC.B $00
DC.W CmdLineBuf
DC.W 128 ;At most 128 chars/line
DC.W 0 ;# actual read (not referenced)
NewLineRecP8
DC.B $03 ;NEWLINE
DC.B $00
DC.B $7F ;AND mask=ignore msb i.e. both $0D/$8D are accepted
DC.B CR ;newline char
; ($39F0) Use to set file posn to beginning of Command File
MarkCmdRecP8
DC.B $02 ;SETMARK
DC.B $00
DS.B 3 ;This doesn't get changed
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; The P8 record below is used to destroy
; 1) old LINKMAP
; 2) old tempESD
; 3) old OBJECT file (if any)
; 4) old tempRLD
; pathNameBuf must be filled w/the filename before use.
DestroyRecP8
DC.B $01
DC.W pathNameBuf
CloseAnyRecP8
DC.B $01 ;Caller must set the RN
DC.B $00
CloseAllRecP8
DC.B $01 ;Use to close ALL open files
DC.B $00
; This record is not used
L39FC
DC.B $04 ;whats this?
DC.B $00
DC.B $00
DC.B $00
DC.B $00
DC.B $00
DC.B $00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Used to get File Info of a source (REL) file
GetFileInfoRecP8
DC.B 10
DC.W pathNameBuf
DC.B 0
srcType DC.B 0
srcORG DC.W 0 ;auxtype
DC.B 0
DC.W 0
DC.W 0
DC.W 0
DC.W 0
DC.W 0
; Used to set the file position of a src file
MarkSrcRecP8
DC.B $02 ;SETMARK
DC.B $00
DS.B 3 ;Caller must set this
; Used to read the first 2 bytes of a SRC file
; which is the length of its code image
ReadCodeLenRecP8
DC.B $04
DC.B $00
DC.W srcCodeLen ;2-byte data buf
DC.W $0002 ;# of bytes to be read
DC.W $A080 ;actual # read (unused)
; ($3A22) For reading SRC, tempRLD, tempESD
; For appending to OBJECT file.
RWFileRecP8
DC.B $04
DC.B $00
DC.W srcDataBuf ;data buf
DC.W 0 ;Set this b4 calling PRODOS
DC.W 0 ;actual # of bytes read
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Use to open a 1) tempESD 2) OBJECT file
Open3RecP8
DC.B $03
DC.W pathNameBuf
DC.W X3F00 ;1024-byte buf for PRODOS
DC.B 0
; Use to write 1) TempESD 2) OBJECT files
Write3RecP8
DC.B $04
DC.B 0
DC.W X9100 ;Data Buf
DC.W $A0A0 ;write len
DC.W $B1A0 ;Actually written
; Read one page (256 bytes) of code image of current SRC file
ReadCodeRecP8
DC.B $04
DC.B 0
DC.W X9100 ;Data Buf
DC.W $0000
DC.W $A0D5
; Use to create BIN/REL/SYS OBJECT files
; Also use to create TempESD/TempRLD binary files
; The filetype & auxtype must be set first
CreateRecP8
DC.B 7
DC.W pathNameBuf
DC.B $E3 ;full access
DC.B $00 ;filetype
DC.W $0000 ;auxtype
DC.B $01 ;seedling
DC.W 0
DC.W 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; This P8 record is used to open
; 1) LINKMAP text file
; 2) tempRLD
Open2RecP8
DC.B $03
DC.W pathNameBuf
DC.W X4300 ;1024-byte buf
DC.B $00
; This P8 record is used to create LINKMAP file (which is a TXT file)
CreateMapRecP8
DC.B 7
DC.W pathNameBuf
DC.B $E3 ;full access
DC.B TXT_type
DC.W 0
DC.B $01 ;storage type=seedling
DC.W 0
DC.W 0
;=================================================
; Use to write the LINKMAP text file
; WrMapFIdx doubles as # of bytes to write
; besides being used as an index to store the
; chars into the Map File's Data Buf (MapDataBuf)
WriteMapRecP8
DC.B $04
DC.B $00
DC.W MapDataBuf ;data buf addr
MapIndex ;Doubles as # of bytes to write
DC.W $A0C3 ;at most 128 bytes (hi-byte=0)
DC.W $A080
;=================================================
; Use to
; 1) get eof of LINKMAP file, then
; 2) set the file posn to its EOF
EOFRecP8
DC.B $02 ;GET_EOF/SETMARK
DC.B $00
DS.B 3
; Use to write 1) TempRLD 2) TempESD files
WriteTmpRecP8
DC.B $04
DC.B $00
DC.W srcDataBuf ;source data buffer
DC.W 0 ;# of bytes to write
DC.W $A0A0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Use to move the file position to the beginning
; 1) of the tempRLD file
; 2) OBJECT file
SMarkBOFRecP8
DC.B $02
DC.B $00
DS.B 3 ;Not changed
;=================================================
; Message pointers sub-tables
; ($3A78)
MsgTabLo
DC.B L3ADE
DC.B L3B02
DC.B L3B1F
DC.B L3BB7
DC.B L3BDD
DC.B L3BFF
DC.B L3C1E
DC.B L3C3F
DC.B L3C63
DC.B L3C83
DC.B L3CA0
DC.B L3CB7
DC.B L3CCF
DC.B L3CEB
DC.B L3B55
DC.B L3B7B
DC.B L3BA0
DC.B L3D06
DC.B L3D22
DC.B L3D3F
DC.B L3D4B
DC.B L3D58
DC.B L3D8D
DC.B L3D9A
DC.B L3DBE
DC.B L3DD6
DC.B L3DEE
DC.B L3B3A
DC.B L3AB4
DC.B L3D75
MsgTabHi
DC.B L3ADE>>8 ;0
DC.B L3B02>>8 ;1
DC.B L3B1F>>8 ;2
DC.B L3BB7>>8 ;3
DC.B L3BDD>>8 ;4
DC.B L3BFF>>8 ;5
DC.B L3C1E>>8 ;6
DC.B L3C3F>>8 ;7
DC.B L3C63>>8 ;8
DC.B L3C83>>8 ;9
DC.B L3CA0>>8 ;10
DC.B L3CB7>>8 ;11
DC.B L3CCF>>8 ;12
DC.B L3CEB>>8 ;13
DC.B L3B55>>8 ;14
DC.B L3B7B>>8 ;15
DC.B L3BA0>>8 ;16
DC.B L3D06>>8 ;17
DC.B L3D22>>8 ;18
DC.B L3D3F>>8 ;19
DC.B L3D4B>>8 ;20
DC.B L3D58>>8 ;21
DC.B L3D8D>>8 ;22
DC.B L3D9A>>8 ;23
DC.B L3DBE>>8 ;24
DC.B L3DD6>>8 ;25
DC.B L3DEE>>8 ;26
DC.B L3B3A>>8 ;27
DC.B L3AB4>>8 ;28
DC.B L3D75>>8 ;29
; Messages starts here
L3AB4 DC.B 'LINKER ABORTED'
DC.B CR
DC.B 'PRESS RETURN TO CONTINUE\'
DC.B CR
DC.B '\'
L3ADE DC.B 'ProDOS Linker 1.0'
DC.B CR,CR
DC.B 'Command Filename'
DC.B '\' ;end of msg
L3B02 DC.B 'ERR: Syntax error in command'
DC.B '\'
L3B1F DC.B 'ERR: Invalid Command order'
DC.B '\'
L3B3A DC.B 'ERR: Unknown command found'
DC.B '\'
L3B55 DC.B 'ERR: Empty or incomplete command'
DC.B ' file'
DC.B '\'
L3B7B DC.B 'ERR: Invalid option or option syntax'
DC.B '\'
L3BA0 DC.B 'ERR: Duplicate command'
DC.B '\'
L3BB7 DC.B 'Phase 0 : Commands & Options Selected'
DC.B '\'
L3BDD DC.B 'Phase 1 : Building DEF/REF tables'
DC.B '\'
L3BFF DC.B 'Phase 2 : Resolving REF-EXTRNs'
DC.B '\'
L3C1E DC.B 'Phase 3 : Relocating Object code'
DC.B '\'
L3C3F DC.B 'Phase 4 : Generating Object RLD-ESD'
DC.B '\'
L3C63 DC.B 'Phase 5 : Sorting loadmap index'
DC.B '\'
L3C83 DC.B 'Phase 6 : Generating loadmap'
DC.B '\'
L3CA0 DC.B 'ERR: Symbol table full'
DC.B '\'
L3CB7 DC.B 'ERR: Too many REL files'
DC.B '\'
L3CCF DC.B 'ERR: File is not a REL file'
DC.B '\'
L3CEB DC.B 'ERR: REL file is too large'
DC.B '\'
L3D06 DC.B 'ERR: REL file ESD too large'
DC.B '\'
L3D22 DC.B 'Duplicate DEF-ENTRY symbol, '
DC.B '\'
L3D3F DC.B 'of module #'
DC.B '\'
L3D4B DC.B ' in module #'
DC.B '\'
L3D58 DC.B 'Undefined REF-EXTRN symbol, '
DC.B '\'
L3D75 DC.B 'REF-DEF SIZE mismatch, '
DC.B '\'
L3D8D DC.B 'UNREFERENCED'
DC.B '\'
L3D9A DC.B 'ERR: >255 EXTRN''s in REL output ESD'
DC.B '\'
L3DBE DC.B 'MOD ORG END MODULE'
DC.B CR
DC.B '\'
L3DD6 DC.B ' # ADRS ADRS NAME '
DC.B CR
DC.B '\'
L3DEE DC.B ' ADRS M# SYMBOL MODULE'
DC.B ' X-REF LIST '
DC.B ' PAGE '
DC.B '\'
DC.B '14-MAR-84'
DC.B '23:42 '
ENDP
END