mirror of
https://github.com/byteworksinc/Linker.git
synced 2024-11-24 17:30:50 +00:00
085c7c46ca
This is a new feature where the linker will automatically divide the code into load segments, creating as many segments as necessary to fit it. This relieves the programmer from the need to manually figure out how a large program can be divided into segments. Auto-segmentation is triggered by the use of the special load segment name AUTOSEG~~~. Using this approach (rather than a flag in the OMF header) allows auto-segmentation to be used with all existing languages that provide a mechanism for specifying load segment names.
1242 lines
24 KiB
NASM
1242 lines
24 KiB
NASM
keep obj/seg
|
|
mcopy seg.mac
|
|
****************************************************************
|
|
*
|
|
* Segment Processing
|
|
*
|
|
* This module contains the subroutines used to find the next
|
|
* segment that needs to be linked.
|
|
*
|
|
****************************************************************
|
|
copy directPage
|
|
****************************************************************
|
|
*
|
|
* SegCommon - global data for the segment module
|
|
*
|
|
****************************************************************
|
|
*
|
|
SegCommon privdata
|
|
;
|
|
; Scalars
|
|
;
|
|
inFile ds 2 are we processing a file?
|
|
isLibrary ds 2 is the file we are processing a library file?
|
|
largeLibFile ds 2 largest library file number
|
|
libDisp ds 4 disp in library symbol table
|
|
suffix ds 2 suffix letter
|
|
|
|
autoSegCounter ds 2 auto-segmentation counter (hex string)
|
|
autoSegLength ds 4 length of current auto segment
|
|
autoSegNamePtr ds 4 pointer to current auto-segment name
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* AutoSegment - perform auto-segmentation
|
|
*
|
|
* inputs:
|
|
* loadNamePtr - load segment name
|
|
* segLength - # of bytes of code in the segment
|
|
* segAlign - segment alignment factor
|
|
*
|
|
* outputs:
|
|
* loadNamePtr - modified if using auto-segmentation
|
|
*
|
|
****************************************************************
|
|
*
|
|
AutoSegment start
|
|
using SegCommon
|
|
using Common
|
|
using OutCommon
|
|
|
|
move4 loadNamePtr,r0 if load seg name is not 'AUTOSEG~~~'
|
|
ldy #nameSize-2
|
|
lb0 lda [r0],Y
|
|
cmp autoSegStr,Y
|
|
beq lb0a
|
|
rts return
|
|
lb0a dey
|
|
dey
|
|
bpl lb0
|
|
|
|
lda segAlign perform alignment if necessary
|
|
bne lb1
|
|
lda segAlign+2
|
|
beq lb2
|
|
lda #0
|
|
lb1 dec a
|
|
bit autoSegLength
|
|
beq lb2
|
|
ora autoSegLength
|
|
inc a
|
|
sta autoSegLength
|
|
bne lb2
|
|
inc autoSegLength+2
|
|
|
|
lb2 add4 autoSegLength,segLength update auto seg length
|
|
lda autoSegLength+2 if it is over $10000 bytes
|
|
beq lb5
|
|
dec a
|
|
ora autoSegLength
|
|
beq lb5
|
|
move4 segLength,autoSegLength set length to seg length
|
|
|
|
short M update auto-seg counter
|
|
lda autoSegCounter+1
|
|
inc a
|
|
cmp #'9'+1
|
|
bne lb3
|
|
lda #'A'
|
|
lb3 cmp #'F'+1
|
|
bne lb3b
|
|
lda autoSegCounter
|
|
inc a
|
|
cmp #'9'+1
|
|
bne lb3a
|
|
lda #'A'
|
|
lb3a sta autoSegCounter
|
|
lda #'0'
|
|
lb3b sta autoSegCounter+1
|
|
long M
|
|
|
|
ph4 #nameSize make new auto-seg name string
|
|
jsr MLalloc
|
|
sta r4
|
|
sta autoSegNamePtr
|
|
stx r4+2
|
|
stx autoSegNamePtr+2
|
|
ldy #nameSize-2
|
|
lda autoSegCounter
|
|
bra lb4a
|
|
lb4 lda autoSegStr,Y
|
|
lb4a sta [r4],Y
|
|
dey
|
|
dey
|
|
bpl lb4
|
|
! set load seg name to auto-seg name
|
|
lb5 move4 autoSegNamePtr,loadNamePtr
|
|
rts
|
|
;
|
|
; Local constant
|
|
;
|
|
autoSegStr dc c'AUTOSEG~~~'
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* CopyBasename - make a copy of the base name
|
|
*
|
|
* inputs:
|
|
* basename - base keep name
|
|
*
|
|
* outputs:
|
|
* fname - copy of basename
|
|
*
|
|
****************************************************************
|
|
*
|
|
CopyBasename start
|
|
using SegCommon
|
|
|
|
ph4 fname free old buffer
|
|
jsr Free
|
|
lda [basename] get new buffer
|
|
pea 0
|
|
inc A
|
|
inc A
|
|
pha
|
|
jsr MLalloc
|
|
sta fname
|
|
stx fname+2
|
|
sta r4 copy basename to fname
|
|
stx r6
|
|
move4 basename,r0
|
|
jsr MoveName
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* Exists - see if a file exists
|
|
*
|
|
* Inputs:
|
|
* fname - pointer to the file name
|
|
*
|
|
* Returns:
|
|
* 1 if the file exists, else 0
|
|
*
|
|
****************************************************************
|
|
*
|
|
Exists private
|
|
val equ 1 does the file exist?
|
|
|
|
sub (4:fname),2
|
|
|
|
stz val assume the file does not exist
|
|
move4 fname,giPathname if it does exist then
|
|
OSGet_File_Info giRec
|
|
bcs lb1
|
|
inc val ++val
|
|
|
|
lb1 ret 2:val return val
|
|
|
|
giRec dc i'2'
|
|
giPathname ds 4
|
|
ds 2
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* ExistsM - see if a file exists in the memory list
|
|
*
|
|
* Inputs:
|
|
* fname - pointer to the file name
|
|
* memory - is this a +m link?
|
|
*
|
|
* Returns:
|
|
* 1 if the file exists, else 0
|
|
*
|
|
****************************************************************
|
|
*
|
|
ExistsM private
|
|
using Common
|
|
val equ 1 does the file exist?
|
|
|
|
sub (4:fname),2
|
|
|
|
ph4 fname (needed for both if and else branch)
|
|
lda memory if this is a +m link then
|
|
beq lb1
|
|
jsr ScanFastFile scan the FastFile list
|
|
bra lb2 else
|
|
lb1 jsr Exists check the disk
|
|
lb2 sta val
|
|
|
|
ret 2:val return val
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* FileType - get the type of a file
|
|
*
|
|
* Inputs:
|
|
* fname - pointer to the file name
|
|
*
|
|
* Returns:
|
|
* file type (0 for none)
|
|
*
|
|
****************************************************************
|
|
*
|
|
FileType private
|
|
|
|
sub (4:fname),0
|
|
|
|
stz giFiletype assume the file does not exist
|
|
move4 fname,giPathname if it does exist then
|
|
OSGet_File_Info giRec
|
|
|
|
ret 2:giFiletype return giFiletype
|
|
|
|
giRec dc i'3'
|
|
giPathname ds 4
|
|
ds 2
|
|
giFiletype ds 2
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* FindSuffix - find the highest keep suffix
|
|
*
|
|
* Inputs:
|
|
* basename - base file name
|
|
*
|
|
* Outputs:
|
|
* suffix - highest existing obj file suffix letter
|
|
*
|
|
****************************************************************
|
|
*
|
|
FindSuffix private
|
|
using SegCommon
|
|
|
|
lda #'a' set the initial suffix
|
|
sta lsuffix
|
|
lb1 lda lsuffix try it out
|
|
sta suffix
|
|
jsr KeepName
|
|
ph4 fname
|
|
jsr ExistsM
|
|
tax
|
|
beq lb2
|
|
inc lsuffix it works, so try the next one
|
|
bra lb1
|
|
|
|
lb2 lda lsuffix use the last one - it worked (or did
|
|
dec A not exist, as in 'a'-1)
|
|
sta suffix
|
|
rts
|
|
|
|
lsuffix ds 2 local suffix
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* GetName - get the next file name
|
|
*
|
|
* Inputs:
|
|
* sdisp - disp in the name list
|
|
* slist - list of file names
|
|
*
|
|
* Outputs:
|
|
* basename - new file name
|
|
* C - set if a name was found, else clear
|
|
*
|
|
****************************************************************
|
|
*
|
|
GetName start
|
|
|
|
ph4 baseName Free(baseName)
|
|
jsr Free
|
|
stz baseName basename = NULL
|
|
stz baseName+2
|
|
|
|
lda [slist] maxDisp = length(slist)+2
|
|
inc A
|
|
inc A
|
|
sta maxDisp
|
|
ldy sdisp Y = sdisp+2
|
|
iny
|
|
iny
|
|
lb1 cpy maxDisp while (Y < maxDisp)
|
|
blt lb1a
|
|
clc
|
|
rts
|
|
lb1a lda [slist],Y and (slist[Y] = ' ') do
|
|
and #$00FF
|
|
cmp #' '
|
|
bne lb2 ++Y
|
|
iny
|
|
bra lb1
|
|
|
|
lb2 sty nDisp save the starting disp
|
|
lb3 cpy maxDisp while (Y < maxDisp)
|
|
bge lb4
|
|
lda [slist],Y and (slist[Y] <> ' ') do
|
|
and #$00FF
|
|
cmp #' '
|
|
beq lb4
|
|
iny ++Y
|
|
bra lb3
|
|
lb4 sec A = Y-sDisp {length of the new string}
|
|
tya
|
|
sbc nDisp
|
|
dey sdisp = Y-2
|
|
dey
|
|
sty sdisp
|
|
pha baseName = mlalloc(A+2)
|
|
inc A
|
|
inc A
|
|
pea 0
|
|
pha
|
|
jsr MLalloc
|
|
sta baseName
|
|
stx baseName+2
|
|
|
|
lda 1,S set the file name length
|
|
sta [baseName]
|
|
add4 slist,nDisp,r0 set r0 to the start of the name-2
|
|
sub4 r0,#2
|
|
plx move in the new characters
|
|
ldy #2
|
|
short M
|
|
lb5 lda [r0],Y
|
|
sta [baseName],Y
|
|
iny
|
|
dex
|
|
bne lb5
|
|
long M
|
|
sec return found
|
|
rts
|
|
;
|
|
; Local data area
|
|
;
|
|
nDisp ds 4 disp in sname
|
|
maxDisp ds 2 max allowed disp
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* InitPass - initialize pass dependent variables
|
|
*
|
|
****************************************************************
|
|
*
|
|
InitPass start
|
|
using Common
|
|
using SegCommon
|
|
|
|
stz libIndex no libraries scanned
|
|
stz sdisp no chars processed in the source list
|
|
stz inFile not processing a file
|
|
stz fileNumber no files processed, so far
|
|
stz lastFileNumber
|
|
stz dataNumber no data areas processed
|
|
stz lastDataNumber
|
|
|
|
lda #'00' initial auto-seg is 'AUTOSEG~00'
|
|
sta autoSegCounter
|
|
lla autoSegNamePtr,initialAutoSegName
|
|
stz autoSegLength initial auto-seg length is 0
|
|
stz autoSegLength+2
|
|
rts
|
|
;
|
|
; Local constant
|
|
;
|
|
initialAutoSegName dc c'AUTOSEG~00'
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* KeepName - Update the Keep Name
|
|
*
|
|
* inputs:
|
|
* basename - base keep name
|
|
* suffix - suffix letter to use
|
|
*
|
|
* outputs:
|
|
* fname - current keep file name
|
|
* suffix - decremented
|
|
* C - set if there is another dot name, else clear
|
|
*
|
|
****************************************************************
|
|
*
|
|
KeepName private
|
|
using SegCommon
|
|
|
|
lda suffix if suffix = 'a'-1 then
|
|
cmp #'a'-1
|
|
bne kn0
|
|
clc return false
|
|
rts
|
|
|
|
kn0 ph4 fname free old buffer
|
|
jsr Free
|
|
lda [basename] get new buffer
|
|
clc
|
|
adc #4
|
|
pea 0
|
|
pha
|
|
jsr MLalloc
|
|
sta fname
|
|
stx fname+2
|
|
sta r4 copy basename to fname
|
|
stx r6
|
|
move4 basename,r0
|
|
jsr MoveName
|
|
|
|
lda [fname] append .suffix to the names
|
|
inc A
|
|
inc A
|
|
sta [fname]
|
|
tay
|
|
short M
|
|
kn1 lda #'.'
|
|
sta [fname],Y
|
|
iny
|
|
lda suffix
|
|
sta [fname],Y
|
|
long M
|
|
phy
|
|
ph4 fname if not exists(fname) then
|
|
jsr ExistsM
|
|
ply
|
|
tax
|
|
short M
|
|
bne kn2
|
|
lda suffix uppercase suffix
|
|
and #$DF
|
|
sta [fname],Y
|
|
kn2 dec suffix --suffix
|
|
long M
|
|
sec
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* MoveName - move a file name
|
|
*
|
|
* Inputs:
|
|
* r0 - pointer to the name to move
|
|
* r4 - pointer to the new file buffer
|
|
*
|
|
* Notes:
|
|
* This subroutine assumes that the buffer is large
|
|
* enough.
|
|
*
|
|
****************************************************************
|
|
*
|
|
MoveName private
|
|
|
|
lda [r0]
|
|
inc A
|
|
tay
|
|
short M
|
|
lb1 lda [r0],Y
|
|
sta [r4],Y
|
|
dey
|
|
bpl lb1
|
|
long M
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* NextFile - find the next file
|
|
*
|
|
* Inputs:
|
|
* sdisp - disp in the file list
|
|
* slist - file list
|
|
* fname - pointer to the base file name
|
|
* suffix - suffix letter for the next obj file
|
|
*
|
|
* Outputs:
|
|
* C - set if a file was found, else clear
|
|
* inFile - set to 1
|
|
* isLibrary - 1 for a library, 0 for an obj segment
|
|
* fname - pointer to the base file name
|
|
* suffix - suffix letter for the next obj file
|
|
*
|
|
****************************************************************
|
|
*
|
|
NextFile start
|
|
using Common
|
|
using SegCommon
|
|
;
|
|
; If there are more files left in an obj sequence, process the next one. For
|
|
; example, if we just processed foo.root, we need to look for foo.a.
|
|
;
|
|
lda inFile if inFile then
|
|
beq lb1
|
|
inc lastFileNumber update the file number
|
|
lda isLibrary if not isLibrary then
|
|
bne lb0
|
|
jsr Purge mark the old file as purgeable
|
|
stz inFile inFile = false
|
|
jsr KeepName form the next file name
|
|
bcc lb1 if exists(fname) then
|
|
jsr Open open(fname)
|
|
stz isLibrary isLibrary = false
|
|
lda #1 inFile = true
|
|
sta inFile
|
|
sec return more files
|
|
rts
|
|
;
|
|
; If the last file was a library file, close it
|
|
;
|
|
lb0 clc update the file number
|
|
lda lastFileNumber
|
|
dec A
|
|
adc largeLibFile
|
|
sta lastFileNumber
|
|
jsr CloseLibrary close the library file
|
|
;
|
|
; If the next file in the file list is a library, process it.
|
|
;
|
|
lb1 jsr GetName if there are files left then
|
|
jcc li1
|
|
ph4 basename get the next file
|
|
jsr Exists
|
|
tay
|
|
beq lb2
|
|
ph4 basename if filetype = LIB then
|
|
jsr FileType
|
|
cmp #LIB
|
|
bne lb2
|
|
lda #1 isLibrary = true
|
|
sta isLibrary
|
|
! lda #1 inFile = true
|
|
sta inFile
|
|
stz largeLibFile no files processed
|
|
lda lastFileNumber update the source file number
|
|
sta fileNumber
|
|
jsr CopyBasename make a copy of the file name
|
|
jsr OpenLibrary open the library file
|
|
jsr ReadLibraryHeader
|
|
sec return more files
|
|
rts
|
|
;
|
|
; Get the next file name from the list of file names specified on the
|
|
; command line.
|
|
;
|
|
lb2 lda lastFileNumber update the source file number
|
|
sta fileNumber
|
|
jsr FindSuffix find the highest dot suffix
|
|
jsr RootName form root file
|
|
ph4 fname if exists(fname) then
|
|
jsr ExistsM
|
|
tay
|
|
beq lb3
|
|
jsr Open open(fname)
|
|
lda #1 inFile = true
|
|
sta inFile
|
|
stz isLibrary isLibrary = false
|
|
sec return more files
|
|
rts
|
|
lb3 jsr KeepName form .a name
|
|
bcc lb4 if exists(fname) then
|
|
jsr Open open(fname)
|
|
lda #1 inFile = true
|
|
sta inFile
|
|
stz isLibrary isLibrary = false
|
|
sec return more files
|
|
rts
|
|
lb4 lda #1 TermError(1)
|
|
jmp TermError
|
|
;
|
|
; Process a library file from the library directory.
|
|
;
|
|
li1 jsr Unresolved see if we have unresolved references
|
|
bcc nf1
|
|
lda libFromShell see if we are using a {Libraries}
|
|
bne nf1 variable
|
|
jsr GetLibFile find the next library file
|
|
bcs li2
|
|
ph4 r0 none left -> free the buffer & quit
|
|
jsr Free
|
|
bra nf1
|
|
|
|
li2 ph4 baseName Free(baseName)
|
|
jsr Free
|
|
move4 r0,baseName basename = r0
|
|
jsr CopyBaseName make a copy of baseName
|
|
lda #1 isLibrary = true
|
|
sta isLibrary
|
|
! lda #1 inFile = true
|
|
sta inFile
|
|
stz largeLibFile no files processed
|
|
lda lastFileNumber update the source file number
|
|
sta fileNumber
|
|
jsr OpenLibrary open the library file
|
|
jsr ReadLibraryHeader
|
|
sec
|
|
rts
|
|
;
|
|
; There are no more files to process
|
|
;
|
|
nf1 clc return no more files
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* NextLibrarySeg - get the next library segment
|
|
*
|
|
* Inputs:
|
|
* libSymbols - pointer to the symbol table
|
|
* libLength - length of the symbol table
|
|
* libNames - pointer to the names table
|
|
* libDisp - disp of the next symbol to process
|
|
* didLibSegment - did we process one, yet?
|
|
*
|
|
* Outputs:
|
|
* C - set if a segment was found, else clear
|
|
*
|
|
****************************************************************
|
|
*
|
|
NextLibrarySeg start
|
|
using SegCommon
|
|
using Common
|
|
dicName equ 0 disp to the name displacement
|
|
dicFile equ 4 disp to the file number
|
|
dicPriv equ 6 disp to the private flag
|
|
dicSeg equ 8 disp to the segment disp
|
|
dicLength equ 12 length of one entry
|
|
|
|
lb1 cmpl libLength,libDisp if we are at the end of the file then
|
|
bne lb2
|
|
lda didLibSegment if we did not processed a segment then
|
|
bne lb1a
|
|
clc return false
|
|
rts
|
|
lb1a stz libDisp start the scan over
|
|
stz libDisp+2
|
|
stz didLibSegment
|
|
lb2 add4 libSymbols,libDisp,r0 get a pointer to the entry
|
|
add4 libDisp,#dicLength skip to the next entry
|
|
clc push the disp to the name
|
|
ldy #2
|
|
lda libNames
|
|
adc [r0]
|
|
tax
|
|
lda libNames+2
|
|
adc [r0],Y
|
|
pha
|
|
phx
|
|
ldy #dicPriv push the private flag
|
|
lda [r0],Y
|
|
pha
|
|
|
|
ldy #dicFile set the file number
|
|
lda [r0],Y
|
|
clc
|
|
adc lastFileNumber
|
|
sta fileNumber
|
|
lda [r0],Y if file number > largest one so far then
|
|
cmp largeLibFile
|
|
blt lb3
|
|
sta largeLibFile update the largest library file
|
|
|
|
lb3 jsr NeedSegment if we don't need this segment then
|
|
tax
|
|
beq lb1 go get the next one
|
|
|
|
lda #1 note that we did one
|
|
sta didLibSegment
|
|
ldy #dicSeg read the segment
|
|
lda [r0],Y
|
|
tax
|
|
iny
|
|
iny
|
|
lda [r0],Y
|
|
sta r2
|
|
stx r0
|
|
jsr ReadLibrarySegment
|
|
jsr ProcessHeader process the header
|
|
sec return true
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* NextObjSeg - get the next object segment
|
|
*
|
|
* Inputs:
|
|
* seg - pointer to the first byte in the last segment
|
|
* len - # bytes left in the file
|
|
* segDisp - length of the last segment
|
|
*
|
|
* Outputs:
|
|
* seg - pointer to the first byte in the new segment
|
|
* len - # bytes left in the file
|
|
* segLength - # of bytes of code in the segment
|
|
* segDisp - length of the new segment, in bytes
|
|
* sp - pointer to the first byte to process
|
|
* segSpace - reserved space at the end of the segment
|
|
* segType - segment type
|
|
* segName - pointer to the segment name
|
|
* segEntry - disp from start of segment for entry point
|
|
* segAlign - segment alignment factor
|
|
* startpc - pc at the start of the segment
|
|
*
|
|
****************************************************************
|
|
*
|
|
NextObjSeg private
|
|
using ExpCommon
|
|
using Common
|
|
|
|
vc0 sub4 len,segDisp update the # of bytes left
|
|
add4 seg,segDisp move to the start of the next segment
|
|
lda len if we are at the end of the file then
|
|
ora len+2
|
|
bne vc1
|
|
clc return with no segment
|
|
rts
|
|
|
|
vc1 jsr ProcessHeader process the segment header
|
|
cmpl len,segDisp make sure there are enough bytes in the
|
|
bge vc2 file
|
|
lda #4
|
|
jmp TermError
|
|
vc2 stz expSegment make sure the segment has not already
|
|
ph4 segName been included
|
|
ph2 #0
|
|
jsr GetSymbolValue
|
|
lda symbolData
|
|
beq vc2a
|
|
lda symbolFlag
|
|
and #isSegmentFlag
|
|
beq vc5
|
|
vc2a lda pass
|
|
cmp #2
|
|
beq vc3
|
|
lda #pass1Resolved
|
|
bra vc4
|
|
vc3 lda #pass2Resolved
|
|
vc4 and symbolFlag
|
|
bne vc6
|
|
vc5 sec
|
|
rts
|
|
|
|
! handle a duplicate segment
|
|
vc6 lda symbolFile if the segments are in the same file then
|
|
cmp fileNumber
|
|
beq vc0 skip this segment
|
|
lda segType if this segment is private then
|
|
and #$4000
|
|
bne vc5 process the segment
|
|
lda pass if this is pass 1 then
|
|
cmp #1
|
|
jeq vc0 don't flag the error
|
|
ph4 segName
|
|
ph2 #4 flag a duplicate segment error
|
|
jsr Error
|
|
brl vc0
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* NextSegment - find the next segment
|
|
*
|
|
* Outputs:
|
|
* C - set if a segment was found, else clear
|
|
*
|
|
****************************************************************
|
|
*
|
|
NextSegment start
|
|
using SegCommon
|
|
|
|
lda inFile if we are not processing a file then
|
|
bne lb2
|
|
lb1 jsr NextFile get one
|
|
bcc lb4
|
|
lb2 lda isLibrary if we are in a library then
|
|
beq lb3
|
|
jsr NextLibrarySeg get the next library segment
|
|
bcc lb1 if none, go to the next file
|
|
bra lb4 else
|
|
lb3 jsr NextObjSeg get the next obj segment
|
|
bcc lb1 if none, go to the next file
|
|
lb4 anop endif
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* Open - open an object file and prepare it for input
|
|
*
|
|
* Inputs:
|
|
* fname - file name
|
|
*
|
|
* Outputs:
|
|
* seg - pointer to the first byte in the file
|
|
* len - length of the file
|
|
* segDisp - 0
|
|
*
|
|
****************************************************************
|
|
*
|
|
Open private
|
|
using Common
|
|
|
|
jsr Read open the file for input
|
|
lda r8 make sure the file is an obj file
|
|
cmp #OBJ
|
|
beq lb1
|
|
lda #2
|
|
jmp TermError
|
|
lb1 move4 r0,seg set the initial byte pointer
|
|
move4 r4,len set the lengt of the file
|
|
stz segDisp set the "previous" segment disp to 0
|
|
stz segDisp+2
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* ProcessHeader - process the header for the next code segment
|
|
*
|
|
* Inputs:
|
|
* seg - pointer to the first byte in the segment
|
|
*
|
|
* Outputs:
|
|
* segLength - # of bytes of code in the segment
|
|
* segDisp - length of the new segment, in bytes
|
|
* sp - pointer to the first byte to process
|
|
* segSpace - reserved space at the end of the segment
|
|
* segType - segment type
|
|
* segName - pointer to the segment name
|
|
* segEntry - disp from start of segment for entry point
|
|
* segAlign - segment alignment factor
|
|
* segBanksize - segment bank size
|
|
* startpc - pc at the start of the segment
|
|
*
|
|
****************************************************************
|
|
*
|
|
ProcessHeader private
|
|
using Common
|
|
using OutCommon
|
|
resspc equ $04 disp to reserved space
|
|
length equ $08 disp to code length
|
|
lablen equ $0D disp to label length
|
|
numlen equ $0E disp to number length
|
|
version equ $0F disp to the segment version
|
|
banksize equ $10 disp to bank size
|
|
|
|
s0type equ $0C disp to segment type
|
|
s0org equ $14 disp to org
|
|
s0align equ $18 disp to alignment factor
|
|
s0numsex equ $1C disp to the number type
|
|
|
|
s1type equ $0C disp to segment type
|
|
s1org equ $18 disp to org
|
|
s1numsex equ $20 disp to the number type
|
|
s1entry equ $24 disp to segment entry
|
|
s1dispname equ $28 disp to the name displacement
|
|
s1dispdata equ $2A disp to the data displacement
|
|
s1align equ $1C disp to alignment factor
|
|
|
|
s2type equ $14 disp to segment type
|
|
s2org equ $18 disp to org
|
|
s2numsex equ $20 disp to the number type
|
|
s2entry equ $24 disp to segment entry
|
|
s2dispname equ $28 disp to the name displacement
|
|
s2dispdata equ $2A disp to the data displacement
|
|
s2temporg equ $2C disp to temporg
|
|
s2align equ $1C disp to alignment factor
|
|
;
|
|
; Do processing common to all segments
|
|
;
|
|
ldy #resspc get the reserved space
|
|
lda [seg],Y
|
|
sta segSpace
|
|
iny
|
|
iny
|
|
lda [seg],Y
|
|
sta segSpace+2
|
|
ldy #length get the length of the code
|
|
lda [seg],Y
|
|
sta segLength
|
|
iny
|
|
iny
|
|
lda [seg],Y
|
|
sta segLength+2
|
|
ldy #banksize get the bank size
|
|
lda [seg],Y
|
|
sta segBanksize
|
|
iny
|
|
iny
|
|
lda [seg],Y
|
|
sta segBanksize+2
|
|
ldy #lablen make sure names are pstrings
|
|
lda [seg],Y
|
|
and #$00FF
|
|
bne vc2
|
|
ldy #numlen make sure numbers are 4 bytes long
|
|
lda [seg],Y
|
|
and #$00FF
|
|
cmp #4
|
|
beq vt0
|
|
vc2 lda #4 flag an illegal header value error
|
|
jmp TermError
|
|
;
|
|
; Handle a version 2 header
|
|
;
|
|
vt0 ldy #version get the segment version number
|
|
lda [seg],Y
|
|
and #$00FF
|
|
sta segVersion
|
|
cmp #2 branch if not version 2
|
|
jne vo1
|
|
|
|
ldy #2 get the length of the segment
|
|
lda [seg]
|
|
sta segDisp
|
|
lda [seg],Y
|
|
sta segDisp+2
|
|
ldy #s2type get the segment type
|
|
lda [seg],Y
|
|
sta segType
|
|
ldy #s2org get the org
|
|
lda [seg],Y
|
|
sta segOrg
|
|
iny
|
|
iny
|
|
lda [seg],Y
|
|
sta segOrg+2
|
|
ldy #s2align get the alignment factor
|
|
lda [seg],Y
|
|
sta segAlign
|
|
iny
|
|
iny
|
|
lda [seg],Y
|
|
sta segAlign+2
|
|
ldy #s2entry get the entry disp
|
|
lda [seg],Y
|
|
sta segEntry
|
|
iny
|
|
iny
|
|
lda [seg],Y
|
|
sta segEntry+2
|
|
ldy #s2dispdata get the disp to the first op code byte
|
|
lda [seg],Y
|
|
clc
|
|
adc seg
|
|
sta sp
|
|
lda seg+2
|
|
adc #0
|
|
sta sp+2
|
|
ldy #s2dispname get a pointer to the segment name
|
|
lda [seg],Y and find the proper load segment
|
|
clc
|
|
adc seg
|
|
sta segName
|
|
lda seg+2
|
|
adc #0
|
|
sta segName+2
|
|
move4 segName,loadNamePtr
|
|
add4 segName,#10
|
|
jsr AutoSegment
|
|
jsr FindLoadSegment
|
|
ldy #s2numsex verify that numsex = 0
|
|
lda [seg],Y
|
|
and #$00FF
|
|
beq vt1
|
|
lda #4
|
|
jmp TermError
|
|
vt1 lda pass if this is pass 2 then
|
|
cmp #2
|
|
jne vf1
|
|
ldy #s2dispname skip check if disp to names < $30
|
|
lda [seg],Y
|
|
cmp #$30
|
|
jlt vf1
|
|
ldy #s2temporg flag temporg errors
|
|
lda [seg],Y
|
|
iny
|
|
iny
|
|
ora [seg],Y
|
|
jeq vf1
|
|
ph4 #0
|
|
ph2 #12
|
|
jsr Error
|
|
brl vf1
|
|
;
|
|
; Handle a version 1 header
|
|
;
|
|
vo1 cmp #1 branch if not version 1
|
|
jne vz1
|
|
|
|
ldy #2 get the length of the segment
|
|
lda [seg]
|
|
sta segDisp+1
|
|
lda [seg],Y
|
|
short M
|
|
stz segDisp
|
|
sta segDisp+3
|
|
long M
|
|
asl segDisp
|
|
rol segDisp+2
|
|
ldy #s1type get the segment type
|
|
lda [seg],Y
|
|
and #$00FF
|
|
pha
|
|
and #$001F
|
|
sta segType
|
|
pla
|
|
xba
|
|
and #$E000
|
|
ora segType
|
|
sta segType
|
|
ldy #s1org get the org
|
|
lda [seg],Y
|
|
sta segOrg
|
|
iny
|
|
iny
|
|
lda [seg],Y
|
|
sta segOrg+2
|
|
ldy #s1align get the alignment factor
|
|
lda [seg],Y
|
|
sta segAlign
|
|
iny
|
|
iny
|
|
lda [seg],Y
|
|
sta segAlign+2
|
|
ldy #s1entry get the entry disp
|
|
lda [seg],Y
|
|
sta segEntry
|
|
iny
|
|
iny
|
|
lda [seg],Y
|
|
sta segEntry+2
|
|
ldy #s1dispdata get the disp to the first op code byte
|
|
lda [seg],Y
|
|
clc
|
|
adc seg
|
|
sta sp
|
|
lda seg+2
|
|
adc #0
|
|
sta sp+2
|
|
ldy #s1dispname get a pointer to the segment name
|
|
lda [seg],Y and find the proper load segment
|
|
clc
|
|
adc seg
|
|
sta segName
|
|
lda seg+2
|
|
adc #0
|
|
sta segName+2
|
|
move4 segName,loadNamePtr
|
|
add4 segName,#10
|
|
jsr AutoSegment
|
|
jsr FindLoadSegment
|
|
ldy #s1numsex verify that numsex = 0
|
|
lda [seg],Y
|
|
and #$00FF
|
|
jeq vf1
|
|
lda #4
|
|
jmp TermError
|
|
brl vf1
|
|
;
|
|
; Handle a version 0 header
|
|
;
|
|
vz1 cmp #0 branch if not version 0
|
|
jne ve1
|
|
|
|
ldy #2 get the length of the segment
|
|
lda [seg]
|
|
sta segDisp+1
|
|
lda [seg],Y
|
|
short M
|
|
stz segDisp
|
|
sta segDisp+3
|
|
long M
|
|
asl segDisp
|
|
rol segDisp+2
|
|
ldy #s0type get the segment type
|
|
lda [seg],Y
|
|
and #$00FF
|
|
pha
|
|
and #$001F
|
|
sta segType
|
|
pla
|
|
xba
|
|
and #$E000
|
|
ora segType
|
|
sta segType
|
|
ldy #s0org get the org
|
|
lda [seg],Y
|
|
sta segOrg
|
|
iny
|
|
iny
|
|
lda [seg],Y
|
|
sta segOrg+2
|
|
ldy #s0align get the alignment factor
|
|
lda [seg],Y
|
|
sta segAlign
|
|
iny
|
|
iny
|
|
lda [seg],Y
|
|
sta segAlign+2
|
|
stz segEntry get the entry disp
|
|
stz segEntry+2
|
|
add4 seg,#$24,segName get a pointer to the segment name
|
|
move4 segName,r0 get the disp to the first op code byte
|
|
lda [r0]
|
|
and #$00FF
|
|
sec
|
|
adc segName
|
|
sta sp
|
|
lda segName+2
|
|
adc #0
|
|
sta sp+2
|
|
ldy #s0numsex verify that numsex = 0
|
|
lda [seg],Y
|
|
and #$00FF
|
|
beq vz2
|
|
lda #4
|
|
jmp TermError
|
|
|
|
vz2 lla loadNamePtr,blankSeg find the proper load segment
|
|
jsr FindLoadSegment
|
|
bra vf1
|
|
;
|
|
; Segment version error
|
|
;
|
|
ve1 lda #3
|
|
jmp TermError
|
|
;
|
|
; Do common end processing
|
|
;
|
|
vf1 stz dataNumber data area number is 0 for code files
|
|
lda segType if this is a data area then
|
|
and #$00FF
|
|
cmp #1
|
|
bne vf2
|
|
inc lastDataNumber assign a data area number
|
|
lda lastDataNumber
|
|
sta dataNumber
|
|
vf2 move4 pc,startpc record the pc
|
|
sec
|
|
rts
|
|
;
|
|
; Local data
|
|
;
|
|
blankSeg dc 10c' ' default load segment name
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* RootName - Append .root to file name
|
|
*
|
|
* inputs:
|
|
* basename - base file name
|
|
*
|
|
* outputs:
|
|
* ckname - current keep file name
|
|
* tkname - .root appended to contents of kname
|
|
* kltr - suffix letter for the main obj file
|
|
*
|
|
****************************************************************
|
|
*
|
|
RootName private
|
|
using SegCommon
|
|
|
|
ph4 fname free old buffer
|
|
jsr Free
|
|
lda [basename] get new buffer
|
|
clc
|
|
adc #2+l:root
|
|
pea 0
|
|
pha
|
|
jsr MLalloc
|
|
sta fname
|
|
stx fname+2
|
|
sta r4 copy basename to fname
|
|
stx r6
|
|
move4 basename,r0
|
|
jsr MoveName
|
|
|
|
lda [fname] append root to the name
|
|
tay
|
|
clc
|
|
adc #l:root
|
|
sta [fname]
|
|
iny
|
|
iny
|
|
ldx #0
|
|
phy
|
|
short M
|
|
rn1 lda root,X
|
|
sta [fname],Y
|
|
iny
|
|
inx
|
|
cpx #l:root
|
|
bne rn1
|
|
long M
|
|
ph4 fname if not exists(fname) then
|
|
jsr ExistsM
|
|
ply
|
|
tax
|
|
bne ret
|
|
short M
|
|
ldx #1
|
|
iny
|
|
rn2 lda root,X uppercase suffix
|
|
and #$DF
|
|
sta [fname],Y
|
|
iny
|
|
inx
|
|
cpx #l:root
|
|
bne rn2
|
|
long M
|
|
ret rts
|
|
|
|
root dc c'.root'
|
|
end
|