mirror of
https://github.com/byteworksinc/Linker.git
synced 2024-11-21 13:31:57 +00:00
aa9a585d19
This would happen if a later object segment had a more restrictive alignment than previous object segments that contribute to the same load segment, as in the following example: s1 start jsl s2 rtl end align 256 s2 start rtl end These alignment requirements can be satisfied by just giving the load segment the most restrictive alignment of any object segment (since all alignments are powers of 2) and inserting space as necessary to align the code from each object segment.
3150 lines
59 KiB
NASM
3150 lines
59 KiB
NASM
keep obj/out
|
|
mcopy out.mac
|
|
****************************************************************
|
|
*
|
|
* Ouput Module
|
|
*
|
|
* This module handles writing the output file and locating the
|
|
* proper load segment for code segments.
|
|
*
|
|
****************************************************************
|
|
copy directPage
|
|
****************************************************************
|
|
*
|
|
* OutCommon - global data for the segment module
|
|
*
|
|
****************************************************************
|
|
*
|
|
OutCommon data
|
|
;
|
|
; Constants
|
|
;
|
|
nameSize equ 10 size of a load segment name
|
|
dictGrowSize equ 4096 grow size for the dictionary buffer
|
|
dynGrowSize equ 1024 grow size for synamic segment buffer
|
|
;
|
|
; global variables
|
|
;
|
|
expressSegment ds 2 express segment number
|
|
keepRefnum ds 2 keep file reference number
|
|
lastLoadNumber ds 4 last load number allocated
|
|
loadList ds 4 head of load segment list
|
|
loadNamePtr ds 4 pointer to the name of the load segment
|
|
;
|
|
; Dynamic segment information
|
|
;
|
|
dynHandle ds 4 handle of the dynamic segment buffer
|
|
dynSize ds 2 bytes left in the buffer
|
|
dynBuffSize ds 4 total memory in the segment buffer
|
|
dynStart ds 4 ptr to the start of the buffer
|
|
dynSegment ds 2 dynamic segment number
|
|
;
|
|
; Current load segment information
|
|
;
|
|
loadNext ds 4 pointer to the next load segment
|
|
loadLast ds 4 pointer to the last load segment
|
|
loadPtr ds 4 pointer to the storage location for this record
|
|
loadNumber ds 2 number of this load segment
|
|
loadType ds 2 load segment type
|
|
loadORG ds 4 load segment origin
|
|
loadAlign ds 4 load segment aligment
|
|
loadBankSize ds 4 load segment bank size
|
|
loadName ds nameSize name of the load segment
|
|
loadSeg ds 4 handle of the segment buffer
|
|
loadSegStart ds 4 start of the segment buffer
|
|
loadPC ds 4 size of the load segment
|
|
loadOp ds 4 op disp for the segment buffer
|
|
loadOpSt ds 4 op at start of current lConst
|
|
loadDict ds 4 handle of the dictionary buffer
|
|
loadDictStart ds 4 start of the dictionary buffer
|
|
loadDictSize ds 2 bytes left in the dictionary buffer
|
|
loadDp ds 4 dp disp for the dictionary buffer
|
|
loadPass2 ds 2 are we ready for pass 2?
|
|
|
|
loadEnd anop end of the record
|
|
|
|
loadSize equ loadEnd-loadNext size of a load module record (even!)
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* AddEnd - add an end record to the dictionary
|
|
*
|
|
* Inputs:
|
|
* loadNext... - load segment record
|
|
*
|
|
****************************************************************
|
|
*
|
|
AddEnd private
|
|
using OutCommon
|
|
|
|
lda loadDictSize make sure there is room in the dictionary
|
|
bne lb1
|
|
jsr ExpandDictBuffer
|
|
lb1 short M save the end marker
|
|
lda #0
|
|
sta [dp]
|
|
long M
|
|
inc4 dp update dp
|
|
dec loadDictSize update loadDictSize
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* AddSegment - add a segment to the expressload table
|
|
*
|
|
* Inputs:
|
|
* r8 - pointer to the segment to add
|
|
* r4,r8 - expressload list pointers
|
|
* expOffset - segment offset pointer
|
|
* expMap - segment map pointer
|
|
* expHeader - segment header map
|
|
* expressSegment - express segment number
|
|
*
|
|
****************************************************************
|
|
*
|
|
AddSegment private
|
|
using OutCommon
|
|
|
|
jsr MoveSegment move the segment ot the new list
|
|
|
|
sub4 expHeader,expOffset,r12 set the segment offset
|
|
lda r12
|
|
sta [expOffset]
|
|
ldy #6 zero the reserved words
|
|
lda #0
|
|
lb1 sta [expOffset],Y
|
|
dey
|
|
dey
|
|
bne lb1
|
|
add4 expOffset,#8 update the offset pointer
|
|
|
|
ldy #loadNumber-loadNext get the old segment number
|
|
lda [r4],Y
|
|
dec A set it's mapped segment
|
|
asl A
|
|
tay
|
|
lda expressSegment
|
|
sta [expMap],Y
|
|
ldy #loadNumber-loadNext set the new segment number
|
|
sta [r4],Y
|
|
inc expressSegment update segment number
|
|
|
|
add4 fMark,#69+5 allow for the segment header & lconst
|
|
move4 fMark,mark1 set the lconst mark
|
|
ldy #loadPC-loadNext find the segment size
|
|
lda [r4],Y
|
|
sta len1
|
|
iny
|
|
iny
|
|
lda [r4],Y
|
|
sta len1+2
|
|
add4 fMark,len1 allow for the segment body
|
|
move4 fMark,mark2 set the reloc mark
|
|
ldy #loadDp-loadNext find the reloc size
|
|
lda [r4],Y
|
|
sta len2
|
|
iny
|
|
iny
|
|
lda [r4],Y
|
|
sta len2+2
|
|
ora len2 if len2 = 0 then
|
|
bne lb1a
|
|
stz mark2 mark2 = 0
|
|
stz mark2+2
|
|
lb1a add4 fMark,len2 allow for the dictionary
|
|
inc4 fMark allow for the end mark
|
|
ldy #loadBankSize-loadNext set the bank size
|
|
lda [r4],Y
|
|
sta bankSize
|
|
iny
|
|
iny
|
|
lda [r4],Y
|
|
sta bankSize+2
|
|
ldy #loadType-loadNext set the segment type
|
|
lda [r4],Y
|
|
sta kind
|
|
ldy #loadOrg-loadNext set the origin
|
|
lda [r4],Y
|
|
sta org
|
|
iny
|
|
iny
|
|
lda [r4],Y
|
|
sta org+2
|
|
ldy #loadAlign-loadNext set the alignment factor
|
|
lda [r4],Y
|
|
sta align
|
|
iny
|
|
iny
|
|
lda [r4],Y
|
|
sta align+2
|
|
ldy #loadNumber-loadNext set the segment number
|
|
lda [r4],Y
|
|
sta segNum
|
|
ldx #nameSize-2 set the segment name
|
|
ldy #loadName-loadNext+nameSize-2
|
|
lb2 lda [r4],Y
|
|
sta name,X
|
|
dey
|
|
dey
|
|
dex
|
|
dex
|
|
bpl lb2
|
|
|
|
ldy #segEnd-mark1-1 move the header to the express segment
|
|
short M
|
|
lb3 lda mark1,Y
|
|
sta [expHeader],Y
|
|
dey
|
|
bpl lb3
|
|
long M
|
|
add4 expHeader,#69 update the segment header pointer
|
|
rts
|
|
|
|
mark1 ds 4 lConst file mark
|
|
len1 ds 4 lConst length
|
|
mark2 ds 4 reloc file mark
|
|
len2 ds 4 reloc length
|
|
dc i1'0' undefined
|
|
dc i1'0' label length
|
|
dc i1'4' number length
|
|
dc i1'2' version
|
|
bankSize ds 4 bank size
|
|
kind ds 2 segment type
|
|
dc i'0' undefined
|
|
org ds 4 origin
|
|
align ds 4 alignment
|
|
dc i1'0' numsex
|
|
dc i1'0' undefined
|
|
segNum ds 2 segment number
|
|
dc i4'0' segment entry
|
|
dc i'lname-len1' disp to name
|
|
dc i'segend-mark1' disp to body
|
|
lname dc 10c' ' load name
|
|
dc i1'10' segment name length
|
|
name ds 10 segment name
|
|
segend anop
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* CheckHeader - check the header parameters
|
|
*
|
|
* Inputs:
|
|
* segOrg - origin for this segment
|
|
* segAlign - alignment for this segment
|
|
* segType - type for this segment
|
|
* segBanksize - banksize for this segment
|
|
* loadType - load segment type
|
|
* loadORG - load segment origin
|
|
* loadAlign - load segment aligment
|
|
* loadBankSize - load segment bank size
|
|
*
|
|
* Outputs:
|
|
* loadType - load segment type
|
|
* loadORG - load segment origin
|
|
* loadAlign - load segment aligment
|
|
* loadBankSize - load segment bank size
|
|
*
|
|
****************************************************************
|
|
*
|
|
CheckHeader private
|
|
using OutCommon
|
|
using Common
|
|
;
|
|
; Set the load segment type
|
|
;
|
|
lda loadPC if at the start of the segment then
|
|
ora loadPC+2
|
|
bne st1
|
|
lda segType use segType
|
|
and #$FEFF
|
|
sta loadType
|
|
bra st4 else
|
|
st1 lda segType or in the or flags
|
|
and #$1D00
|
|
ora loadType
|
|
sta loadType
|
|
lda segType mask out missing and flags
|
|
and #$E200
|
|
ora #$3DFF
|
|
and loadType
|
|
sta loadType
|
|
lda loadType get the type without flags
|
|
and #$007F
|
|
sta r0
|
|
lda segType
|
|
and #$007F
|
|
cmp r0 if they do not match then
|
|
beq st4
|
|
cmp #1 if seg is data then
|
|
bne st2
|
|
lda r0 if not load in [code,init,dp] then
|
|
beq st4
|
|
cmp #$10
|
|
beq st4
|
|
cmp #$12
|
|
beq st4
|
|
err15 ph4 #0 flag segment conflict
|
|
ph2 #15
|
|
jsr Error
|
|
bra st4
|
|
st2 cmp #0 else if seg in [code,init,dp] then
|
|
beq st3
|
|
cmp #$10
|
|
beq st3
|
|
cmp #$12
|
|
bne err15
|
|
st3 lda r0 if load = data then
|
|
cmp #1
|
|
bne err15
|
|
lda loadType use seg type
|
|
and #$FF00
|
|
sta loadType
|
|
lda segType
|
|
and #$007F
|
|
ora loadType
|
|
sta loadType
|
|
! else flag the error
|
|
st4 anop endif
|
|
|
|
lda bankOrg if bankOrg then
|
|
beq st5
|
|
lda loadType bank org the program
|
|
ora #$0100
|
|
sta loadType
|
|
st5 anop endif
|
|
;
|
|
; Set the load segment origin (pass 1)
|
|
;
|
|
lda pass branch if pass 2
|
|
cmp #2
|
|
beq or0
|
|
lda segOrg skip if org is 0
|
|
ora segOrg+2
|
|
jeq or4
|
|
|
|
lda loadPC if at the start of the segment then
|
|
ora loadPC+2
|
|
ora loadOrg
|
|
ora loadOrg+2
|
|
bne po1
|
|
move4 segOrg,loadOrg loadOrg = segOrg
|
|
bra po3 else
|
|
po1 sub4 segOrg,loadOrg,r0 update the pc
|
|
lda r2
|
|
bmi po3
|
|
cmpl r0,pc
|
|
blt po3
|
|
move4 r0,pc
|
|
po3 anop endif
|
|
bra or4
|
|
;
|
|
; Set the load segment origin (pass 2)
|
|
;
|
|
or0 lda segOrg skip if org is 0
|
|
ora segOrg+2
|
|
beq or4
|
|
|
|
lda loadPC if at the start of the segment then
|
|
ora loadPC+2
|
|
ora loadOrg
|
|
ora loadOrg+2
|
|
bne or1
|
|
move4 segOrg,loadOrg loadOrg = segOrg
|
|
bra or3 else
|
|
or1 sub4 segOrg,loadOrg,r0 update the pc
|
|
sub4 r0,pc
|
|
lda r2
|
|
bpl or2 if disp is negative then
|
|
ph4 #0 Error(NULL,3)
|
|
ph2 #3
|
|
jsr Error
|
|
bra or3 else
|
|
or2 lda r0 define DS bytes to fill space
|
|
ora r2
|
|
beq or3
|
|
jsr DefineDS
|
|
or3 anop endif
|
|
jsr CheckAlignOrg check for conflicts between align,org
|
|
or4 anop
|
|
;
|
|
; Set the load segment alignment (pass 1)
|
|
;
|
|
lda pass branch if pass 2
|
|
cmp #2
|
|
beq sa0
|
|
lda segAlign skip if alignment is 0
|
|
ora segAlign+2
|
|
jeq sa4
|
|
|
|
lda loadPC if at the start of the segment then
|
|
ora loadPC+2
|
|
ora loadAlign
|
|
ora loadAlign+2
|
|
bne la1
|
|
move4 segAlign,loadAlign loadAlign = segAlign
|
|
bra la3 else
|
|
la1 cmpl loadAlign,segAlign if loadAlign < segAlign then
|
|
bge la2
|
|
move4 segAlign,loadAlign loadAlign = segAlign
|
|
la2 move4 segAlign,r0 PrepareAlign(segAlign)
|
|
jsr PrepareAlign
|
|
la3 anop endif
|
|
bra sa4
|
|
;
|
|
; Set the load segment alignment (pass 2)
|
|
;
|
|
sa0 lda segAlign skip if alignment is 0
|
|
ora segAlign+2
|
|
beq sa4
|
|
|
|
ph4 segAlign make sure the align is a power of 2
|
|
jsr CheckAlign
|
|
lda loadPC if at the start of the segment then
|
|
ora loadPC+2
|
|
ora loadAlign
|
|
ora loadAlign+2
|
|
bne sa1
|
|
move4 segAlign,loadAlign loadAlign = segAlign
|
|
bra sa3 else
|
|
sa1 cmpl loadAlign,segAlign if loadAlign < segAlign then
|
|
bge sa2
|
|
move4 segAlign,loadAlign loadAlign = segAlign
|
|
sa2 move4 segAlign,r0 DefineAlign(segAlign)
|
|
jsr DefineAlign
|
|
sa3 anop endif
|
|
jsr CheckAlignOrg check for conflicts between align,org
|
|
sa4 anop
|
|
;
|
|
; Set the load segment bank size
|
|
;
|
|
lda pass branch if pass 2
|
|
cmp #2
|
|
beq rt1
|
|
lda loadBankSize if loadBanksize = 0
|
|
ora loadBanksize+2
|
|
beq bs1
|
|
cmpl segBanksize,loadBanksize or ((segBanksize < loadBanksize)
|
|
bge bs2 and (segBanksize <> 0)) then
|
|
lda segBanksize
|
|
ora segBanksize+2
|
|
beq bs2
|
|
bs1 move4 segBankSize,loadBankSize loadBankSize = segBankSize
|
|
bs2 anop
|
|
|
|
rt1 rts
|
|
;
|
|
; CheckAlignOrg - make sure the align and org do not conflict
|
|
;
|
|
CheckAlignOrg anop
|
|
|
|
lda loadAlign if loadAlign <> 0 then
|
|
ora loadAlign+2
|
|
beq ca2
|
|
sub4 loadAlign,#1,r0 if loadOrg & (loadAlign-1) then
|
|
lda r0
|
|
and loadOrg
|
|
bne ca1
|
|
lda r2
|
|
and loadOrg+2
|
|
beq ca2
|
|
ca1 ph4 #0 Error(NULL,21)
|
|
ph2 #21
|
|
jsr Error
|
|
ca2 rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* CompactCInterseg - compact a cInterseg record
|
|
*
|
|
* Inputs:
|
|
* r0 - ptr to the cInterseg record
|
|
* r4 - ptr to the end of the dictionary
|
|
* dp - ptr to the next free byte in the dictionary
|
|
*
|
|
****************************************************************
|
|
*
|
|
CompactCInterseg private
|
|
using Common
|
|
using OutCommon
|
|
;
|
|
; See if the record can be compacted
|
|
;
|
|
lda [r0] length must be 2 or 3
|
|
xba
|
|
and #$00FF
|
|
cmp #2
|
|
beq ck1
|
|
cmp #3
|
|
jne nc1
|
|
ck1 sta length
|
|
cmp #3 if length = 3 then
|
|
bne ck2
|
|
ldy #2 shift count must be 0
|
|
lda [r0],Y
|
|
and #$00FF
|
|
jne nc1
|
|
stz shift
|
|
lda #2 set the record type
|
|
sta recordType
|
|
ldy #5 set the segment number
|
|
lda [r0],Y
|
|
and #$00FF
|
|
sta segment
|
|
bra ck3 else {if length = 2 then}
|
|
ck2 ldy #5 segment number must be <= 12
|
|
lda [r0],Y
|
|
and #$00FF
|
|
sta segment
|
|
cmp #13
|
|
jge nc1
|
|
ldx express if express then
|
|
beq ck2a
|
|
cmp #12 don't use 12, either
|
|
jeq nc1
|
|
ck2a clc set the record type for shift 0
|
|
lda segment
|
|
adc #13
|
|
sta recordType
|
|
ldy #2 shift must be 0 or -16
|
|
lda [r0],Y
|
|
and #$00FF
|
|
sta shift
|
|
beq ck3
|
|
cmp #$00F0
|
|
jne nc1
|
|
add2 recordType,#12 set the record type for shift -16
|
|
ck3 anop
|
|
;
|
|
; Create a Super record
|
|
;
|
|
lda #13 create the record header
|
|
cmp loadDictSize make sure there is room in the
|
|
blt sp1 dictionary
|
|
jsr ExpandDictBuffer
|
|
sp1 add4 dp,#1,recordLengthPtr save a pointer to the length field
|
|
sub4 recordLengthPtr,loadDictStart
|
|
short M set the op code
|
|
lda #$F7
|
|
sta [dp]
|
|
ldy #5 set the super record type
|
|
lda recordType
|
|
sta [dp],Y
|
|
long M
|
|
add4 dp,#6 skip the super record header
|
|
sub2 loadDictSize,#6
|
|
|
|
ldy #4 set the segment offset page
|
|
lda [r0],Y
|
|
and #$00FF
|
|
sta page
|
|
beq pg3 if page <> 0 then
|
|
sta r12 while (r12 := page) > $7F do
|
|
pg1 lda r12
|
|
cmp #$80
|
|
blt pg2
|
|
short M write a skip page for $7F pages
|
|
lda #$FF
|
|
sta [dp]
|
|
long M
|
|
inc4 dp
|
|
dec loadDictSize
|
|
sub2 r12,#$7F r12 -= $7F
|
|
bra pg1 endwhile
|
|
pg2 lda r12 if r12 <> 0 then
|
|
beq pg3
|
|
short M write a skip page for r12 pages
|
|
ora #$80
|
|
sta [dp]
|
|
long M
|
|
inc4 dp
|
|
dec loadDictSize
|
|
pg3 anop
|
|
move4 dp,r12 initialize the page counter
|
|
short M
|
|
lda #$FF
|
|
sta [r12]
|
|
long M
|
|
inc4 dp skip the page counter
|
|
dec loadDictSize
|
|
|
|
move4 r0,r8 for each dictionary record do
|
|
sp2 cmpl r8,r4
|
|
jeq sp14
|
|
lda [r8] if it is a Reloc then
|
|
and #$00FF
|
|
cmp #$E2
|
|
bne sp3
|
|
add4 r8,#11 skip the record
|
|
bra sp2 loop
|
|
sp3 cmp #$75 if it is a skipped cReloc or
|
|
beq sp4 cReloc then
|
|
cmp #$F5
|
|
bne sp5
|
|
sp4 add4 r8,#7 skip the record
|
|
bra sp2 loop
|
|
sp5 cmp #$76 if it is a skipped cInterseg then
|
|
bne sp6
|
|
add4 r8,#8 skip the record
|
|
bra sp2 loop
|
|
sp6 cmp #$E3 if it is an Interseg then
|
|
bne sp7
|
|
add4 r8,#15 skip the record
|
|
bra sp2 loop
|
|
sp7 ldy #2 if the cInterseg is a different type
|
|
short M then
|
|
lda [r8],Y
|
|
cmp shift
|
|
bne sp7a
|
|
dey
|
|
lda [r8],Y
|
|
cmp length
|
|
bne sp7a
|
|
cmp #3
|
|
beq sp8
|
|
ldy #5
|
|
lda [r8],Y
|
|
cmp segment
|
|
beq sp8
|
|
sp7a long M skip the record
|
|
add4 r8,#8
|
|
brl sp2 loop
|
|
|
|
sp8 long M make sure there is room in the
|
|
lda #5 dictionary
|
|
cmp loadDictSize
|
|
blt sp9
|
|
sub4 r12,loadDictStart
|
|
jsr ExpandDictBuffer
|
|
add4 r12,loadDictStart
|
|
sp9 short M if r8^.page <> page then
|
|
sec
|
|
ldy #4
|
|
lda [r8],Y
|
|
sbc page
|
|
beq sp13
|
|
dec A if r8^.page - page > 1 then
|
|
beq sp12
|
|
sp10 cmp #$80 record a page skip
|
|
blt sp11
|
|
tax
|
|
lda #$FF
|
|
sta [dp]
|
|
long M
|
|
inc4 dp
|
|
dec loadDictSize
|
|
short M
|
|
txa
|
|
sec
|
|
sbc #$7F
|
|
bra sp10
|
|
sp11 cmp #0
|
|
beq sp12
|
|
ora #$80
|
|
sta [dp]
|
|
long M
|
|
inc4 dp
|
|
dec loadDictSize
|
|
short M
|
|
sp12 ldy #4 record the new page
|
|
lda [r8],Y
|
|
sta page
|
|
lda #$FF set up a record count
|
|
sta [dp]
|
|
long M
|
|
move4 dp,r12
|
|
inc4 dp
|
|
dec loadDictSize
|
|
short M
|
|
sp13 lda [r12] increment the record count
|
|
inc A
|
|
sta [r12]
|
|
ldy #3 set the offset
|
|
lda [r8],Y
|
|
sta [dp]
|
|
long M
|
|
inc4 dp
|
|
dec loadDictSize
|
|
short M mark the record
|
|
lda [r8]
|
|
and #$7F
|
|
sta [r8]
|
|
long M
|
|
add4 r8,#8 skip the record
|
|
brl sp2 loop
|
|
|
|
sp14 anop set the super record length
|
|
add4 recordLengthPtr,loadDictStart,r12
|
|
sub4 dp,r12,recordLengthPtr
|
|
sub4 recordLengthPtr,#4
|
|
ldy #2
|
|
lda recordLengthPtr
|
|
sta [r12]
|
|
lda recordLengthPtr+2
|
|
sta [r12],Y
|
|
rts
|
|
;
|
|
; Cannot compact - put the unchanged record in the dictionary
|
|
;
|
|
nc1 lda #8 make sure there is room in the
|
|
cmp loadDictSize dictionary
|
|
blt nc2
|
|
jsr ExpandDictBuffer
|
|
nc2 ldy #6 move the record
|
|
nc3 lda [r0],Y
|
|
sta [dp],Y
|
|
dey
|
|
dey
|
|
bpl nc3
|
|
add4 dp,#8 skip the record
|
|
sub2 loadDictSize,#8
|
|
add4 r0,#8
|
|
rts
|
|
;
|
|
; Local data
|
|
;
|
|
recordLengthPtr ds 4 pointer to the super record length field
|
|
page ds 2 current cReloc page number
|
|
length ds 2 length of the cReloc fields
|
|
shift ds 2 shift count
|
|
segment ds 2 segment number
|
|
recordType ds 2 type of the Super record
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* CompactCReloc - compact a cReloc record
|
|
*
|
|
* Inputs:
|
|
* r0 - ptr to the cReloc record
|
|
* r4 - ptr to the end of the dictionary
|
|
* dp - ptr to the next free byte in the dictionary
|
|
*
|
|
****************************************************************
|
|
*
|
|
CompactCReloc private
|
|
using OutCommon
|
|
;
|
|
; See if the record can be compacted
|
|
;
|
|
lda [r0] length must be 2 or 3
|
|
xba
|
|
and #$00FF
|
|
cmp #2
|
|
beq ck1
|
|
cmp #3
|
|
jne nc1
|
|
ck1 sta length
|
|
ldy #2 shift count must be 0
|
|
lda [r0],Y
|
|
and #$00FF
|
|
jne nc1
|
|
;
|
|
; Create a Super record
|
|
;
|
|
lda #13 create the record header
|
|
cmp loadDictSize make sure there is room in the
|
|
blt sp1 dictionary
|
|
jsr ExpandDictBuffer
|
|
sp1 add4 dp,#1,recordLengthPtr save a pointer to the length field
|
|
sub4 recordLengthPtr,loadDictStart
|
|
short M set the op code
|
|
lda #$F7
|
|
sta [dp]
|
|
ldy #5 set the super record type
|
|
lda length
|
|
and #$01
|
|
sta [dp],Y
|
|
long M
|
|
add4 dp,#6 skip the super record header
|
|
sub2 loadDictSize,#6
|
|
|
|
ldy #4 set the segment offset page
|
|
lda [r0],Y
|
|
and #$00FF
|
|
sta page
|
|
beq pg3 if page <> 0 then
|
|
sta r12 while (r12 := page) > $7F do
|
|
pg1 lda r12
|
|
cmp #$80
|
|
blt pg2
|
|
short M write a skip page for $7F pages
|
|
lda #$FF
|
|
sta [dp]
|
|
long M
|
|
inc4 dp
|
|
dec loadDictSize
|
|
sub2 r12,#$7F r12 -= $7F
|
|
bra pg1 endwhile
|
|
pg2 lda r12 if r12 <> 0 then
|
|
beq pg3
|
|
short M write a skip page for r12 pages
|
|
ora #$80
|
|
sta [dp]
|
|
long M
|
|
inc4 dp
|
|
dec loadDictSize
|
|
pg3 anop
|
|
move4 dp,r12 initialize the page counter
|
|
short M
|
|
lda #$FF
|
|
sta [r12]
|
|
long M
|
|
inc4 dp skip the page counter
|
|
dec loadDictSize
|
|
|
|
move4 r0,r8 for each dictionary record do
|
|
sp2 cmpl r8,r4
|
|
jeq sp14
|
|
lda [r8] if it is a Reloc then
|
|
and #$00FF
|
|
cmp #$E2
|
|
bne sp3
|
|
add4 r8,#11 skip the record
|
|
bra sp2 loop
|
|
sp3 cmp #$75 if it is a skipped cReloc then
|
|
bne sp4
|
|
add4 r8,#7 skip the record
|
|
bra sp2 loop
|
|
sp4 cmp #$F6 if it is a cInterseg or skipped
|
|
beq sp5 cInterseg then
|
|
cmp #$76
|
|
bne sp6
|
|
sp5 add4 r8,#8 skip the record
|
|
bra sp2 loop
|
|
sp6 cmp #$E3 if it is an Interseg then
|
|
bne sp7
|
|
add4 r8,#15 skip the record
|
|
bra sp2 loop
|
|
sp7 ldy #1 if the cReloc is a different type then
|
|
lda [r8],Y
|
|
cmp length (checks length and shift=0)
|
|
beq sp8
|
|
add4 r8,#7 skip the record
|
|
bra sp2 loop
|
|
|
|
sp8 lda #5 make sure there is room in the
|
|
cmp loadDictSize dictionary
|
|
blt sp9
|
|
sub4 r12,loadDictStart
|
|
jsr ExpandDictBuffer
|
|
add4 r12,loadDictStart
|
|
sp9 short M if r8^.page <> page then
|
|
sec
|
|
ldy #4
|
|
lda [r8],Y
|
|
sbc page
|
|
beq sp13
|
|
dec A if r8^.page - page > 1 then
|
|
beq sp12
|
|
sp10 cmp #$80 record a page skip
|
|
blt sp11
|
|
tax
|
|
lda #$FF
|
|
sta [dp]
|
|
long M
|
|
inc4 dp
|
|
dec loadDictSize
|
|
short M
|
|
txa
|
|
sec
|
|
sbc #$7F
|
|
bra sp10
|
|
sp11 cmp #0
|
|
beq sp12
|
|
ora #$80
|
|
sta [dp]
|
|
long M
|
|
inc4 dp
|
|
dec loadDictSize
|
|
short M
|
|
sp12 ldy #4 record the new page
|
|
lda [r8],Y
|
|
sta page
|
|
lda #$FF set up a record count
|
|
sta [dp]
|
|
long M
|
|
move4 dp,r12
|
|
inc4 dp
|
|
dec loadDictSize
|
|
short M
|
|
sp13 lda [r12] increment the record count
|
|
inc A
|
|
sta [r12]
|
|
ldy #3 set the offset
|
|
lda [r8],Y
|
|
sta [dp]
|
|
long M
|
|
inc4 dp
|
|
dec loadDictSize
|
|
short M mark the record
|
|
lda [r8]
|
|
and #$7F
|
|
sta [r8]
|
|
long M
|
|
add4 r8,#7 skip the record
|
|
brl sp2 loop
|
|
|
|
sp14 anop set the super record length
|
|
add4 recordLengthPtr,loadDictStart,r12
|
|
sub4 dp,r12,recordLengthPtr
|
|
sub4 recordLengthPtr,#4
|
|
ldy #2
|
|
lda recordLengthPtr
|
|
sta [r12]
|
|
lda recordLengthPtr+2
|
|
sta [r12],Y
|
|
rts
|
|
;
|
|
; Cannot compact - put the unchanged record in the dictionary
|
|
;
|
|
nc1 lda #8 make sure there is room in the
|
|
cmp loadDictSize dictionary
|
|
blt nc2
|
|
jsr ExpandDictBuffer
|
|
nc2 ldy #6 move the record
|
|
nc3 lda [r0],Y
|
|
sta [dp],Y
|
|
dey
|
|
dey
|
|
bpl nc3
|
|
add4 dp,#7 skip the record
|
|
sub2 loadDictSize,#7
|
|
add4 r0,#7
|
|
rts
|
|
;
|
|
; Local data
|
|
;
|
|
recordLengthPtr ds 4 pointer to the super record length field
|
|
page ds 2 current cReloc page number
|
|
length ds 2 length of the cReloc fields
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* CompactSegment - compact a single segment
|
|
*
|
|
* Inputs:
|
|
* LoadNext... - segment record
|
|
*
|
|
****************************************************************
|
|
*
|
|
CompactSegment private
|
|
using OutCommon
|
|
using Common
|
|
|
|
lda loadDict if there is no dictionary then
|
|
ora loadDict+2
|
|
bne lb1
|
|
rts return
|
|
|
|
lb1 move4 loadDict,dictHandle save the dictionary handle
|
|
move4 loadDictStart,r0 get a pointer to the dictionary
|
|
move4 dp,r4 get a pointer to the dictionary end
|
|
stz loadDictStart zero the current load dictionary
|
|
stz loadDictStart+2
|
|
stz loadDict
|
|
stz loadDict+2
|
|
stz loadDp
|
|
stz loadDp+2
|
|
stz dp
|
|
stz dp+2
|
|
stz loadDictSize
|
|
stz loadDictSize+2
|
|
lb2 cmpl r0,r4 for each dictionary entry do
|
|
jeq lb12
|
|
lda [r0] if r0^ = cReloc then
|
|
and #$00FF
|
|
cmp #$00F5
|
|
bne lb3
|
|
jsr CompactCReloc compact the record
|
|
bra lb2 loop
|
|
lb3 cmp #$75 if r0^ = skipped cReloc then
|
|
bne lb4
|
|
add4 r0,#7 skip the record
|
|
bra lb2 loop
|
|
lb4 cmp #$E2 if r0^ = Reloc then
|
|
bne lb7
|
|
lda #12 make sure there is room in the
|
|
cmp loadDictSize dictionary
|
|
blt lb5
|
|
jsr ExpandDictBuffer
|
|
lb5 ldy #10 move the record
|
|
lb6 lda [r0],Y
|
|
sta [dp],Y
|
|
dey
|
|
dey
|
|
bpl lb6
|
|
add4 dp,#11 skip the record
|
|
sub2 loadDictSize,#11
|
|
add4 r0,#11
|
|
bra lb2 loop
|
|
lb7 cmp #$F6 if r0^ = cInterseg then
|
|
bne lb8
|
|
jsr CompactCInterseg compact the record
|
|
bra lb2 loop
|
|
lb8 cmp #$76 if r0^ = skipped cInterseg then
|
|
bne lb9
|
|
add4 r0,#8 skip the record
|
|
brl lb2 loop
|
|
! (condition must be true) if r0^ = Interseg then
|
|
lb9 lda #16 make sure there is room in the
|
|
cmp loadDictSize dictionary
|
|
blt lb10
|
|
jsr ExpandDictBuffer
|
|
lb10 ldy #14 move the record
|
|
lb11 lda [r0],Y
|
|
sta [dp],Y
|
|
dey
|
|
dey
|
|
bpl lb11
|
|
add4 dp,#15 skip the record
|
|
sub2 loadDictSize,#15
|
|
add4 r0,#15
|
|
brl lb2 loop
|
|
|
|
lb12 ph4 dictHandle free the old dictionary buffer
|
|
_DisposeHandle
|
|
rts
|
|
|
|
dictHandle ds 4 old dictionary handle
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* CreateDynamicSegment - create the dynamic segment (if any)
|
|
*
|
|
* Inputs:
|
|
* dynSegment - dynmaic segment number; 0 if none
|
|
* dynStart - start of the dynamic segment
|
|
* dy - next byte in the buffer
|
|
*
|
|
****************************************************************
|
|
*
|
|
CreateDynamicSegment private
|
|
using OutCommon
|
|
|
|
lda dynSegment quit if there is no segment
|
|
bne lb0
|
|
rts
|
|
lb0 lda dynSize write the trailing 4 bytes
|
|
cmp #4
|
|
bge lb1
|
|
jsr ExpandDynamicBuffer
|
|
lb1 ldy #2
|
|
lda #0
|
|
sta [dy]
|
|
sta [dy],Y
|
|
add4 dy,#4
|
|
sub4 dy,dynStart,r0 set the size of the lConst
|
|
sub4 r0,#5
|
|
move4 dynStart,r4
|
|
lda #$F2
|
|
sta [r4]
|
|
ldy #1
|
|
lda r0
|
|
sta [r4],Y
|
|
iny
|
|
iny
|
|
lda r2
|
|
sta [r4],Y
|
|
|
|
move #0,loadNext,#loadSize clear all entries
|
|
lda dynSegment set the segment number
|
|
sta loadNumber
|
|
lda #2 set the segment type
|
|
sta loadType
|
|
lla loadBankSize,$10000 set the load segment bank size
|
|
move jumpName,loadName,#nameSize set the segment name
|
|
move4 dynHandle,loadSeg set the segment buffer handle
|
|
move4 dynStart,loadSegStart set the load segment start
|
|
sub4 dy,dynStart,loadPc set the segment size
|
|
sub4 loadPc,#5
|
|
move4 loadPc,pc
|
|
move4 dy,op set the segment pointer
|
|
sub4 dy,dynStart,loadOp set the segment displacement
|
|
inc loadPass2 ready for pass 2
|
|
stz dp no dictionary pointer
|
|
stz dp+2
|
|
jsr SaveSegment
|
|
rts
|
|
|
|
jumpName dc c'~JumpTable'
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* CreateFile - make sure an output file exists
|
|
*
|
|
* Inputs:
|
|
* kname - keep file name
|
|
*
|
|
****************************************************************
|
|
*
|
|
CreateFile private
|
|
using OutCommon
|
|
|
|
move4 kname,giPathname see if a file exists
|
|
OSGet_File_Info giRec
|
|
bcs lb1
|
|
lda giFiletype yes -> make sure it is an OBJ file
|
|
cmp #$B3
|
|
blt err7
|
|
cmp #$BF+1
|
|
bge err7
|
|
rts
|
|
|
|
lb1 move4 kname,crPathname no file exists, so create one
|
|
OSCreate crRec
|
|
bcs err12
|
|
rts
|
|
|
|
err12 lda #12 file write error
|
|
jmp TermError
|
|
|
|
err7 lda #7 Could not overwrite existing file
|
|
jmp TermError
|
|
;
|
|
; Local data
|
|
;
|
|
giRec dc i'3' GetFileInfo record
|
|
giPathname ds 4
|
|
ds 2
|
|
giFiletype ds 2
|
|
|
|
crRec dc i'4'
|
|
crPathname ds 4
|
|
dc i'$C3'
|
|
dc i'EXE'
|
|
dc i4'$0100'
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* DecimalVariable - convert an OS string to a decimal value
|
|
*
|
|
* Inputs:
|
|
* r0 - pointer to the shell variable value
|
|
*
|
|
* Outputs:
|
|
* C - set if all characters are digits, else clear
|
|
* X-A - value (if C set); least sig. 32 bits only
|
|
*
|
|
****************************************************************
|
|
*
|
|
DecimalVariable private
|
|
|
|
lda [r0] get a loop counter
|
|
sta r12
|
|
stz r8 set the initial value
|
|
stz r10
|
|
add4 r0,#2,r4 get a character pointer
|
|
|
|
lb1 lda [r4] if the character is not a digit then
|
|
and #$00FF return false
|
|
cmp #'0'
|
|
blt lb3
|
|
cmp #'9'+1
|
|
bge lb3
|
|
mul4 r8,#10 r8 = r8*10 + value(r4^)
|
|
lda [r4]
|
|
and #$000F
|
|
clc
|
|
adc r8
|
|
sta r8
|
|
bcc lb2
|
|
inc r10
|
|
lb2 inc4 r4 loop
|
|
dec r12
|
|
bne lb1
|
|
|
|
lda r8 return value
|
|
ldx r10
|
|
sec
|
|
rts
|
|
|
|
lb3 clc return false
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* DoCompact - compact the dictionaries
|
|
*
|
|
****************************************************************
|
|
*
|
|
DoCompact private
|
|
using OutCommon
|
|
using Common
|
|
|
|
jsr SaveSegment save the current segment
|
|
lda #1 set the segment number
|
|
sta segment
|
|
lb1 move4 loadList,r0 find the proper segment
|
|
lb2 ldy #loadNumber-loadNext
|
|
lda [r0],Y
|
|
cmp segment
|
|
bne lb3
|
|
jsr GetSegment get the segment
|
|
jsr CompactSegment compact the segment
|
|
jsr SaveSegment save the segment
|
|
inc segment next segment
|
|
bra lb1 start the search over
|
|
|
|
lb3 ldy #2 next segment pointer
|
|
lda [r0],Y
|
|
tax
|
|
lda [r0]
|
|
sta r0
|
|
stx r2
|
|
ora r2
|
|
bne lb2
|
|
|
|
move4 loadList,r0 done - get a segment back
|
|
jsr GetSegment
|
|
rts return
|
|
|
|
segment ds 2 segment number
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* DynamicCheck - if any segment is dynamic, set up a jump table
|
|
*
|
|
* Inputs:
|
|
* loadList - list of current load segments
|
|
* loadNext... - active load segment
|
|
* lastLoadNumber - last load number allocated
|
|
*
|
|
* Outputs: (if there is a dynamic segment)
|
|
* dynHandle - handle of the synamic segment
|
|
* dynStart - start of the dynamic segment
|
|
* dynSize - size of the dynamic segment
|
|
* dy - pointer to the next spot in the dynamic segment
|
|
* dynSegment - dynamic segment number
|
|
*
|
|
****************************************************************
|
|
*
|
|
DynamicCheck start
|
|
using OutCommon
|
|
;
|
|
; See if any segment is dynamic
|
|
;
|
|
lda loadType check the current segment
|
|
bmi pr1
|
|
move4 loadList,r0 check the segments in the segment list
|
|
cs1 lda r0
|
|
ora r2
|
|
beq cs2
|
|
ldy #loadType-loadNext
|
|
lda [r0],Y
|
|
bmi pr1
|
|
ldy #2
|
|
lda [r0],Y
|
|
tax
|
|
lda [r0]
|
|
sta r0
|
|
stx r2
|
|
bra cs1
|
|
|
|
cs2 rts
|
|
;
|
|
; Prepare for dynamic segment output
|
|
;
|
|
pr1 stz dy zero the pointer
|
|
stz dy+2
|
|
stz dynSize zero the size
|
|
stz dynBuffSize no memory in the buffer
|
|
stz dynBuffSize+2
|
|
stz dynHandle no handle, yet
|
|
stz dynHandle+2
|
|
stz dynStart initialize the field
|
|
stz dynStart+2
|
|
jsr ExpandDynamicBuffer get an initial buffer
|
|
add4 dy,#5 create space for the lConst opcode
|
|
ldy #6 insert the 8 leading zeros
|
|
lda #0
|
|
pr2 sta [dy],Y
|
|
dey
|
|
dey
|
|
bpl pr2
|
|
sub2 dynSize,#13
|
|
add4 dy,#8
|
|
lda lastLoadNumber get a segment number
|
|
inc A
|
|
sta lastLoadNumber
|
|
sta dynSegment
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* ExpandDictBuffer - expand the dictionary buffer
|
|
*
|
|
* Inputs:
|
|
* loadDict - handle of the dictionary buffer, nil for none
|
|
* loadDictSize - size of the dictionary buffer
|
|
*
|
|
* Outputs:
|
|
* loadDict - handle of the dictionary buffer
|
|
* loadDictStart - start of the dictionary buffer
|
|
* loadDictSize - size of the dictionary buffer
|
|
* dp - start of the dictionary buffer
|
|
*
|
|
* Notes:
|
|
* Other than dp, direct page is not disturbed.
|
|
*
|
|
****************************************************************
|
|
*
|
|
ExpandDictBuffer start
|
|
using Common
|
|
using OutCommon
|
|
|
|
lda loadDict if there is no buffer then
|
|
ora loadDict+2
|
|
bne lb1
|
|
la loadDictSize,dictGrowSize set the dictionary size
|
|
pha get a new buffer
|
|
pha
|
|
ph4 #dictGrowSize
|
|
ph2 userID
|
|
ph2 #$8000
|
|
ph4 #0
|
|
_NewHandle
|
|
jcs oom
|
|
pl4 loadDict
|
|
stz loadDP loadDP = 0
|
|
stz loadDP+2
|
|
brl lb2 else
|
|
lb1 sub4 dp,loadDictStart,loadDP get the displacement
|
|
ph4 loadDict unlock the handle
|
|
_HUnlock
|
|
pha get the current handle size
|
|
pha
|
|
ph4 loadDict
|
|
_GetHandleSize
|
|
clc set the new size
|
|
lda 1,S
|
|
adc #dictGrowSize
|
|
sta 1,S
|
|
lda 3,S
|
|
adc #^dictGrowSize
|
|
sta 3,S
|
|
ph4 loadDict expand the buffer
|
|
_SetHandleSize
|
|
bcs oom
|
|
ph4 loadDict lock the handle
|
|
_HLock
|
|
add2 loadDictSize,#dictGrowSize update the free space
|
|
lb2 anop endif
|
|
|
|
move4 loadDict,dp dereference the handle
|
|
ldy #2
|
|
lda [dp]
|
|
sta loadDictStart
|
|
lda [dp],Y
|
|
sta loadDictStart+2
|
|
add4 loadDictStart,loadDP,dp set dp
|
|
rts
|
|
|
|
oom lda #5
|
|
jmp TermError
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* ExpandDynamicBuffer - expand the dynamic segment buffer
|
|
*
|
|
* Inputs:
|
|
* dynHandle - handle of the buffer, nil for none
|
|
* dynBuffSize - size of the buffer
|
|
* synSize - bytes left in the current buffer
|
|
* dy - pointer to the current buffer
|
|
* dynStart - start of the buffer
|
|
*
|
|
* Outputs:
|
|
* dynHandle - handle of the buffer, nil for none
|
|
* dynBuffSize - size of the buffer
|
|
* synSize - bytes left in the current buffer
|
|
* dy - pointer to the current buffer
|
|
* dynStart - start of the buffer
|
|
*
|
|
****************************************************************
|
|
*
|
|
ExpandDynamicBuffer private
|
|
using Common
|
|
using OutCommon
|
|
|
|
lda dynHandle if there is no buffer then
|
|
ora dynHandle+2
|
|
bne lb1
|
|
pha get a new buffer
|
|
pha
|
|
ph4 #dynGrowSize
|
|
ph2 userID
|
|
ph2 #$8000
|
|
ph4 #0
|
|
_NewHandle
|
|
jcs oom
|
|
pl4 dynHandle
|
|
lla dynBuffSize,dynGrowSize set the size
|
|
bra lb2 else
|
|
lb1 ph4 loadDict unlock the handle
|
|
_HUnlock
|
|
add4 dynBuffSize,#dynGrowSize get the new size
|
|
ph4 dynBuffSize set the new size
|
|
ph4 dynHandle expand the buffer
|
|
_SetHandleSize
|
|
bcs oom
|
|
ph4 dynHandle lock the handle
|
|
_HLock
|
|
lb2 anop endif
|
|
|
|
add2 dynSize,#dynGrowSize update the free space
|
|
sub4 dy,dynStart convert dy to a displacement
|
|
move4 dynHandle,r0 dereference the handle
|
|
ldy #2
|
|
lda [r0]
|
|
sta dynStart
|
|
lda [r0],Y
|
|
sta dynStart+2
|
|
add4 dy,dynStart set dy
|
|
rts
|
|
|
|
oom lda #5
|
|
jmp TermError
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* ExpressLoad - Handle express loading
|
|
*
|
|
* Inputs:
|
|
* express - is the program express loaded?
|
|
*
|
|
****************************************************************
|
|
*
|
|
ExpressLoad private
|
|
using OutCommon
|
|
using Common
|
|
;
|
|
; Sort the segments by number
|
|
;
|
|
lda #1 set the initial segment number
|
|
sta expressSegment
|
|
stz r0 nothing in the output list
|
|
stz r2
|
|
sn1 move4 loadList,r8 for each segment number
|
|
sn2 lda r8 for each segment
|
|
ora r10
|
|
beq sn4
|
|
ldy #loadNumber-loadNext if this is the right segment then
|
|
lda [r8],Y
|
|
cmp expressSegment
|
|
bne sn3
|
|
jsr MoveSegment move the segment to the new list
|
|
bra sn4
|
|
sn3 ldy #2 next segment
|
|
lda [r8],Y
|
|
tax
|
|
lda [r8]
|
|
sta r8
|
|
stx r10
|
|
bra sn2
|
|
sn4 inc expressSegment next segment number
|
|
lda loadList
|
|
ora loadList+2
|
|
bne sn1
|
|
move4 r0,loadList replace the list
|
|
;
|
|
; Build the expressload segment
|
|
;
|
|
pha get memory for the lConst record
|
|
pha
|
|
mul4 lastLoadNumber,#79,r0
|
|
add4 r0,#7
|
|
ph4 r0
|
|
ph2 userID
|
|
ph2 #$8000
|
|
ph4 #0
|
|
_NewHandle
|
|
bcc ex1
|
|
lda #5
|
|
jmp TermError
|
|
ex1 pl4 r0 recover the handle
|
|
ldy #2 recover the start pointer
|
|
lda [r0]
|
|
sta expStart
|
|
lda [r0],Y
|
|
sta expStart+2
|
|
add4 expStart,#6,expOffset set the initial offset pointer
|
|
mul4 lastLoadNumber,#8,r0 set the initial map pointer
|
|
add4 r0,expOffset,expMap
|
|
mul4 lastLoadNumber,#2,r0 set the initial header pointer
|
|
add4 r0,expMap,expHeader
|
|
lda #2 start with segment 2
|
|
sta expressSegment
|
|
mul4 lastLoadNumber,#79,fMark set the initial file mark
|
|
add4 fMark,#67+5+4+2+1
|
|
;
|
|
; Add all static segments to the expressload segment
|
|
;
|
|
stz r0 nothing in the output list
|
|
stz r2
|
|
st1 move4 loadList,r8 for each segment do
|
|
st2 lda r8
|
|
ora r10
|
|
beq dy1
|
|
ldy #loadType-loadNext if it is a static segment then
|
|
lda [r8],Y
|
|
bmi st3
|
|
jsr AddSegment add the segment to the express list
|
|
bra st1 loop
|
|
st3 ldy #2 next segment
|
|
lda [r8],Y
|
|
tax
|
|
lda [r8]
|
|
sta r8
|
|
stx r10
|
|
bra st2
|
|
;
|
|
; Add all remaining segments to the expressload segment
|
|
;
|
|
dy1 lda loadList for each segment do
|
|
ora loadList+2
|
|
beq dn1
|
|
move4 loadList,r8 add the segment to the express list
|
|
jsr AddSegment
|
|
bra dy1
|
|
;
|
|
; Adjust the dynamic segment number
|
|
;
|
|
dn1 anop
|
|
lda dynSegment get the old segment number
|
|
beq fe1 skip if there isn't one
|
|
dec A set its mapped segment
|
|
asl A
|
|
tay
|
|
lda [expMap],Y
|
|
sta dynSegment set the new segment number
|
|
;
|
|
; Finish off the express record
|
|
;
|
|
fe1 move4 r0,loadList replace the load list pointer
|
|
lda #0 put and end mark after the record
|
|
short M
|
|
sta [expHeader]
|
|
long M
|
|
ldy #2 zero the reserved space for the link
|
|
sta [expStart]
|
|
sta [expStart],Y
|
|
ldy #4 set the number of segments
|
|
lda lastLoadNumber
|
|
dec A
|
|
sta [expStart],Y
|
|
;
|
|
; Write the expressload segment
|
|
;
|
|
! set the size of the segment
|
|
sub4 expHeader,expStart,length
|
|
add4 length,#headerEnd-header+1,byteCnt
|
|
move4 length,length2 set the length of the lCost record
|
|
|
|
lda keepRefnum write the header
|
|
sta wrRefnum
|
|
sta wsRefnum
|
|
OSWrite wrRec
|
|
bcs lb1
|
|
move4 expStart,wsBuff write the body
|
|
add4 length,#1,wsLen
|
|
OSWrite wsRec
|
|
bcs lb1
|
|
rts
|
|
|
|
lb1 lda #12
|
|
jmp TermError
|
|
;
|
|
; Local data
|
|
;
|
|
wsRec dc i'4' write the body
|
|
wsRefnum ds 2
|
|
wsBuff ds 4
|
|
wsLen ds 4
|
|
ds 4
|
|
|
|
wrRec dc i'4' write the segment header
|
|
wrRefnum ds 2
|
|
da 'header'
|
|
dc i4'headerEnd-header'
|
|
ds 4
|
|
|
|
header anop segment header model
|
|
byteCnt ds 4 length of the segment, in bytes
|
|
dc i4'0' reserved space at the end of the segment
|
|
length ds 4 length of the segment
|
|
dc i1'0' undefined
|
|
dc i1'0' label length
|
|
dc i1'4' number length
|
|
dc i1'2' OMF version
|
|
dc i4'$10000' bank size
|
|
dc i'$8001' segment kind
|
|
dc i'0' undefined
|
|
dc i4'0' origin
|
|
dc i4'0' alignment factor
|
|
dc i1'0' numSex; set to LSB first
|
|
dc i1'0' undefined
|
|
dc i'1' segment number
|
|
dc i4'0' entry point
|
|
dc i'ldName-header' disp to the segment name
|
|
dc i'data-header' disp to the segment image
|
|
ldName dc 10c' ' load segment name; unused in load segs
|
|
dc i1'12' length of the segment name
|
|
dc c'~ExpressLoad' segment name
|
|
data dc i1'$F2' lConst header
|
|
length2 ds 4
|
|
headerEnd anop
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* FindLoadSegment - find the proper load segment for a file
|
|
*
|
|
* Inputs:
|
|
* loadNamePtr - pointer to the load segment name
|
|
* segOrg - origin for this segment
|
|
* segAlign - alignment for this segment
|
|
* segType - type for this segment
|
|
* segBanksize - banksize for this segment
|
|
*
|
|
* Outputs:
|
|
* loadNumber - load segment number
|
|
*
|
|
* Additional outputs if pass = 2:
|
|
* op - pointer to the next output segment byte
|
|
* dp - pointer to the next dictionary segment byte
|
|
* dictSize - remaining bytes in the dictionary segment
|
|
* dictStart - pointer to the first byte in the dictionary
|
|
*
|
|
****************************************************************
|
|
*
|
|
FindLoadSegment start
|
|
using Common
|
|
using OutCommon
|
|
|
|
lda loadNumber if there is an existing segment then
|
|
bmi lb3
|
|
move4 loadNamePtr,r0 if we need this segment then
|
|
ldy #nameSize-2
|
|
lb1 lda [r0],Y
|
|
cmp loadName,Y
|
|
bne lb2
|
|
dey
|
|
dey
|
|
bpl lb1
|
|
move4 pc,loadPC save the program counter
|
|
jsr Pass2Prep make sure we are "pass 2 ready"
|
|
jsr CheckHeader check header parameters
|
|
rts return
|
|
lb2 jsr SaveSegment save the current segment info
|
|
|
|
lb3 move4 loadList,r0 find the correct segment
|
|
move4 loadNamePtr,r8
|
|
lb4 lda r0
|
|
ora r2
|
|
beq lb6
|
|
add4 r0,#loadName-loadNext,r4
|
|
ldy #nameSize-2
|
|
lb5 lda [r4],Y
|
|
cmp [r8],Y
|
|
bne lb5a
|
|
dey
|
|
dey
|
|
bpl lb5
|
|
jsr GetSegment recover the segment
|
|
jsr CheckHeader check header parameters
|
|
rts
|
|
|
|
lb5a ldy #2 next segment
|
|
lda [r0],Y
|
|
tax
|
|
lda [r0]
|
|
sta r0
|
|
stx r2
|
|
bra lb4
|
|
|
|
lb6 jsr NewSegment create a new segment
|
|
jsr CheckHeader
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* FinishLconst - finish the current lconst record
|
|
*
|
|
* Inputs:
|
|
* op - current ptr in buffer
|
|
* opst - op at the start of this record
|
|
*
|
|
* Outputs:
|
|
* opst - set to op
|
|
*
|
|
****************************************************************
|
|
*
|
|
FinishLConst start
|
|
|
|
sub4 op,opSt,r0
|
|
sub4 r0,#5
|
|
lda #$F2
|
|
sta [opSt]
|
|
ldy #1
|
|
lda r0
|
|
sta [opSt],Y
|
|
lda r2
|
|
iny
|
|
iny
|
|
sta [opSt],Y
|
|
move4 op,opSt
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* GetSegment - get a segment from storage
|
|
*
|
|
* Inputs:
|
|
* r0 - pointer to the segment to get
|
|
* pass - current pass number
|
|
*
|
|
* Outputs:
|
|
* loadNext... - filled in
|
|
* pc - set to last value
|
|
* op,opst,dp,dpSize - set as appropriate
|
|
*
|
|
****************************************************************
|
|
*
|
|
GetSegment private
|
|
using Common
|
|
using OutCommon
|
|
|
|
ldy #loadSize-2 recover the segment
|
|
lb0 lda [r0],Y
|
|
sta loadNext,Y
|
|
dey
|
|
dey
|
|
bpl lb0
|
|
lda loadSeg if there is a segment buffer then
|
|
ora loadSeg+2
|
|
beq lb1
|
|
ph4 loadSeg lock the buffer
|
|
_HLock
|
|
move4 loadSeg,r0 dereference the segment
|
|
ldy #2
|
|
lda [r0]
|
|
sta loadSegStart
|
|
lda [r0],Y
|
|
sta loadSegStart+2
|
|
add4 loadOp,loadSegStart,op set the segment pointer
|
|
add4 loadOpSt,loadSegStart,opst set the lConst pointer
|
|
bra lb3 else if pass = 2 then
|
|
lb1 lda pass
|
|
cmp #2
|
|
bne lb3
|
|
move4 loadPC,pc save the program counter
|
|
jsr Pass2Prep prepare for pass2
|
|
lb3 anop endif
|
|
move4 loadPC,pc reset the program counter
|
|
lda loadDict if there is a dictionary then
|
|
ora loadDict+2
|
|
beq lb4
|
|
ph4 loadDict lock the buffer
|
|
_HLock
|
|
move4 loadDict,r0 dereference the segment
|
|
ldy #2
|
|
lda [r0]
|
|
sta loadDictStart
|
|
lda [r0],Y
|
|
sta loadDictStart+2
|
|
add4 loadDp,loadDictStart,dp set the segment pointer
|
|
|
|
lb4 lda loadLast break the back link
|
|
ora loadLast+2
|
|
beq lb5
|
|
move4 loadLast,r0
|
|
ldy #2
|
|
lda loadNext
|
|
sta [r0]
|
|
lda loadNext+2
|
|
sta [r0],Y
|
|
bra lb6
|
|
lb5 move4 loadNext,loadList
|
|
lb6 lda loadNext break the forward link
|
|
ora loadNext+2
|
|
beq lb7
|
|
move4 loadNext,r0
|
|
ldy #loadLast-loadNext
|
|
lda loadLast
|
|
sta [r0],Y
|
|
iny
|
|
iny
|
|
lda loadLast+2
|
|
sta [r0],Y
|
|
lb7 rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* HexVariable - convert an OS string to a value
|
|
*
|
|
* Inputs:
|
|
* r0 - pointer to the shell variable value
|
|
*
|
|
* Outputs:
|
|
* C - set if all characters are hex digits, else clear
|
|
* X-A - value (if C set); least sig. 32 bits only
|
|
*
|
|
****************************************************************
|
|
*
|
|
HexVariable private
|
|
|
|
lda [r0] get a loop counter
|
|
sta r12
|
|
stz r8 set the initial value
|
|
stz r10
|
|
add4 r0,#2,r4 get a character pointer
|
|
|
|
lda [r4] the first char must be '$'
|
|
and #$00FF
|
|
cmp #'$'
|
|
bne lb3
|
|
inc4 r4
|
|
dec r12
|
|
beq lb2a
|
|
lb1 lda [r4] if the character is not a digit then
|
|
and #$00FF return false
|
|
cmp #'0'
|
|
blt lb3
|
|
cmp #'9'+1
|
|
blt lb1a
|
|
and #$005F
|
|
cmp #'F'+1
|
|
bge lb3
|
|
cmp #'A'
|
|
blt lb3
|
|
lb1a pha r8 = r8*16 + value(r4^)
|
|
mul4 r8,#16
|
|
pla
|
|
and #$007F
|
|
cmp #'9'+1
|
|
blt lb1b
|
|
sbc #7
|
|
lb1b and #$000F
|
|
clc
|
|
adc r8
|
|
sta r8
|
|
bcc lb2
|
|
inc r10
|
|
lb2 inc4 r4 loop
|
|
dec r12
|
|
bne lb1
|
|
|
|
lb2a lda r8 return value
|
|
ldx r10
|
|
sec
|
|
rts
|
|
|
|
lb3 clc return false
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* InitOut - initialize the output buffer variables
|
|
*
|
|
****************************************************************
|
|
*
|
|
InitOut start
|
|
using Common
|
|
using OutCommon
|
|
|
|
lda #-1 no load segment is active
|
|
sta loadNumber
|
|
stz lastLoadNumber no load segments created
|
|
stz loadList no load segments in the list
|
|
stz loadList+2
|
|
stz dynSegment no dynamic segment
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* IsDynamic - is the segment dynamic?
|
|
*
|
|
* Inputs:
|
|
* A - segment to check
|
|
*
|
|
* Outputs:
|
|
* C - set if the segment is dynamic, else clear
|
|
*
|
|
****************************************************************
|
|
*
|
|
IsDynamic start
|
|
using OutCommon
|
|
|
|
cmp loadNumber if A = current segment then
|
|
bne lb2
|
|
lda loadType return dynamic(loadType)
|
|
lb0 bpl lb1
|
|
sec
|
|
rts
|
|
lb1 clc
|
|
rts
|
|
|
|
lb2 sta r4 save the segment number
|
|
move4 loadList,r0 for each segment in the list do
|
|
lb3 lda r0
|
|
ora r2
|
|
beq lb1
|
|
ldy #loadNumber-loadNext if this is the correct segment then
|
|
lda [r0],Y
|
|
cmp r4
|
|
bne lb4
|
|
ldy #loadType-loadNext return dynamic(r0^.loadType)
|
|
lda [r0],Y
|
|
bra lb0
|
|
lb4 ldy #2 next segment
|
|
lda [r0],Y
|
|
tax
|
|
lda [r0]
|
|
sta r0
|
|
stx r2
|
|
bra lb3
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* JumpTable - create/reuse a jump table entry
|
|
*
|
|
* Inputs:
|
|
* expValue - disp into the dynamic segment
|
|
* expSegment - dynamic segment number
|
|
* shiftFlag - shift flag for the expression
|
|
*
|
|
* Outputs:
|
|
* expValue - disp into the segment buffer
|
|
* expSegment - dynamic segment number
|
|
*
|
|
****************************************************************
|
|
*
|
|
JumpTable start
|
|
using OutCommon
|
|
using ExpCommon
|
|
userID equ 0 disp to the user ID field
|
|
file equ 2 disp to the file number
|
|
seg equ 4 disp to the segment number
|
|
offset equ 6 disp to the offset (expr value)
|
|
jsl equ 10 disp to the jsl to the loader
|
|
|
|
length equ 14 length of a record
|
|
|
|
header equ 8+5 bytes in the buffer header
|
|
|
|
add4 dynStart,#header,r0 check for an existing entry
|
|
lb1 cmpl r0,dy
|
|
bge lb3
|
|
ldy #seg
|
|
lda [r0],Y
|
|
cmp expSegment
|
|
bne lb2
|
|
ldy #offset
|
|
lda [r0],Y
|
|
cmp expValue
|
|
bne lb2
|
|
iny
|
|
iny
|
|
lda [r0],Y
|
|
cmp expValue+2
|
|
beq lb5
|
|
lb2 add4 r0,#length
|
|
bra lb1
|
|
|
|
lb3 lda dynSize no existing entry; create a new one
|
|
cmp #length
|
|
bge lb4
|
|
jsr ExpandDynamicBuffer
|
|
lb4 move4 dy,r0
|
|
add4 dy,#length
|
|
lda #0
|
|
sta [r0]
|
|
ldy #file
|
|
lda #1
|
|
sta [r0],Y
|
|
ldy #seg
|
|
lda expSegment
|
|
sta [r0],Y
|
|
ldy #offset
|
|
lda expValue
|
|
sta [r0],Y
|
|
iny
|
|
iny
|
|
lda expValue+2
|
|
sta [r0],Y
|
|
ldy #jsl
|
|
lda #$0022
|
|
sta [r0],Y
|
|
iny
|
|
iny
|
|
lda #0
|
|
sta [r0],Y
|
|
|
|
lb5 sub4 r0,dynStart,expValue set the new expValue
|
|
add4 expValue,#jsl-5
|
|
lda dynSegment set the new segment value
|
|
sta expSegment
|
|
lda shiftFlag check for an illegal shift
|
|
beq lb6
|
|
ph4 #0
|
|
ph2 #20
|
|
jsr Error
|
|
lb6 rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* KeepFile - write the segments to the file
|
|
*
|
|
* Inputs:
|
|
* loadList - head of the load list
|
|
* kname - pointer to the output name
|
|
*
|
|
****************************************************************
|
|
*
|
|
KeepFile start
|
|
using Common
|
|
using OutCommon
|
|
|
|
lda #1 set the segment number
|
|
sta segment
|
|
jsr CreateFile create/check the file
|
|
move4 kname,opPathname open the file
|
|
OSOpen opRec
|
|
bcc lb0
|
|
err12 lda #12
|
|
jmp TermError
|
|
|
|
lb0 lda opRefnum save the keep refnum
|
|
sta keepRefnum
|
|
sta clRefnum
|
|
sta mkRefnum
|
|
OSSet_EOF mkRec erase the old file contents
|
|
bcs err12
|
|
lda compact if compact then
|
|
beq lb0a
|
|
jsr DoCompact compact the dictionaries
|
|
lb0a jsr SaveSegment save the current segment
|
|
jsr CreateDynamicSegment create the dynamic segment
|
|
lda express if express then
|
|
beq lb1
|
|
jsr ExpressLoad write the expressload segment (if any)
|
|
inc segment first segment to process is 2
|
|
|
|
lb1 move4 loadList,r0 find the proper segment
|
|
lb2 ldy #loadNumber-loadNext
|
|
lda [r0],Y
|
|
cmp segment
|
|
beq lb3
|
|
ldy #2
|
|
lda [r0],Y
|
|
tax
|
|
lda [r0]
|
|
sta r0
|
|
stx r2
|
|
ora r2
|
|
bne lb2
|
|
OSClose clRec none left -- close the file
|
|
move4 loadList,r0 get a segment back
|
|
jsr GetSegment
|
|
jsr SetFileType
|
|
rts
|
|
|
|
lb3 jsr GetSegment get and lock the segment
|
|
jsr AddEnd add an end record to the dictionary
|
|
jsr FinishLConst finish the current lconst record
|
|
lda express if express then
|
|
beq lb4
|
|
jsr Remap remap the segment numbers
|
|
bra lb5 else
|
|
lb4 jsr OptimizeDS optimize the DS, LConst records
|
|
lb5 jsr WriteHeader write the header
|
|
jsr WriteBody write the segment image
|
|
jsr WriteDictionary write the dictionary
|
|
jsr SaveSegment save the segment
|
|
inc segment next segment
|
|
bra lb1
|
|
;
|
|
; Local data
|
|
;
|
|
clRec dc i'1' close record
|
|
clRefnum ds 2
|
|
|
|
opRec dc i'2' open record
|
|
opRefnum ds 2
|
|
opPathname ds 4
|
|
|
|
mkRec dc i'3' set mark record
|
|
mkRefnum ds 2
|
|
dc i'0'
|
|
dc i4'0'
|
|
|
|
segment ds 2 segment number
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* MoveSegment - move a segment record
|
|
*
|
|
* Inputs:
|
|
* r0 - pointer to the head of the new list
|
|
* r4 - pointer to the last record in the new list (if r0 <> nil)
|
|
* r8 - pointer to the record to move
|
|
* loadList - pointer to the first record in the old list
|
|
*
|
|
* Outputs:
|
|
* input pointers are modified
|
|
*
|
|
****************************************************************
|
|
*
|
|
MoveSegment private
|
|
using OutCommon
|
|
;
|
|
; Break the back link
|
|
;
|
|
ldy #loadLast-loadNext if r8^.last = nil then
|
|
lda [r8],Y
|
|
iny
|
|
iny
|
|
ora [r8],Y
|
|
bne lb1
|
|
ldy #2 loadList := r8^.next
|
|
lda [r8]
|
|
sta loadList
|
|
lda [r8],Y
|
|
sta loadList+2
|
|
bra lb2 else
|
|
lb1 ldy #loadLast-loadNext r12 := r8^.last
|
|
lda [r8],Y
|
|
sta r12
|
|
iny
|
|
iny
|
|
lda [r8],Y
|
|
sta r14
|
|
ldy #2 r12^.next := r8^.next
|
|
lda [r8]
|
|
sta [r12]
|
|
lda [r8],Y
|
|
sta [r12],Y
|
|
lb2 anop endif
|
|
;
|
|
; Break the forward link
|
|
;
|
|
ldy #2 if r8^.next <> nil then
|
|
lda [r8]
|
|
ora [r8],Y
|
|
beq lb3
|
|
lda [r8] r12 := r8^.next
|
|
sta r12
|
|
lda [r8],Y
|
|
sta r14
|
|
ldy #loadLast-loadNext r12^.last := r8^.last
|
|
lda [r8],Y
|
|
sta [r12],Y
|
|
iny
|
|
iny
|
|
lda [r8],Y
|
|
sta [r12],Y
|
|
lb3 anop endif
|
|
;
|
|
; Add the record to the new list
|
|
;
|
|
ldy #2 r8^.next := nil
|
|
lda #0
|
|
sta [r8]
|
|
sta [r8],Y
|
|
lda r0 if r0 = nil then
|
|
ora r2
|
|
bne lb4
|
|
ldy #loadLast-loadNext r8^.last := nil
|
|
lda #0
|
|
sta [r8],Y
|
|
iny
|
|
iny
|
|
sta [r8],Y
|
|
move4 r8,r0 r0 := r8
|
|
bra lb5 else
|
|
lb4 ldy #2 r4^.next := r8
|
|
lda r8
|
|
sta [r4]
|
|
lda r10
|
|
sta [r4],Y
|
|
ldy #loadLast-loadNext r8^.last := r4
|
|
lda r4
|
|
sta [r8],Y
|
|
iny
|
|
iny
|
|
lda r6
|
|
sta [r8],Y
|
|
lb5 anop endif
|
|
move4 r8,r4 r4 := r8
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* NamedVariable - see if the variable is a file type
|
|
*
|
|
* Inputs:
|
|
* r0 - pointer to the shell variable value
|
|
*
|
|
* Outputs:
|
|
* C - set if we have a match, else clear
|
|
* X-A - variable value (if C is set)
|
|
*
|
|
****************************************************************
|
|
*
|
|
NamedVariable private
|
|
|
|
lda [r0] if length <> 3 then
|
|
cmp #3
|
|
bne lb3 return false
|
|
lda #nameEnd-name-3 index into the name array
|
|
sta r4
|
|
lda #$BD initial file number
|
|
sta r6
|
|
lb1 ldx r4 check for match
|
|
ldy #2
|
|
short M
|
|
lb1a lda [r0],Y
|
|
cmp name,X
|
|
beq lb1b
|
|
and #$5F
|
|
cmp name,X
|
|
bne lb2
|
|
lb1b inx
|
|
iny
|
|
cpy #5
|
|
bne lb1a
|
|
long M
|
|
lda r6 return the file type
|
|
ldx #0
|
|
sec
|
|
rts
|
|
|
|
lb2 long M no match - loop
|
|
dec r6
|
|
sec
|
|
lda r4
|
|
sbc #3
|
|
sta r4
|
|
bpl lb1
|
|
|
|
lb3 clc return false
|
|
rts
|
|
;
|
|
; Local data
|
|
;
|
|
name dc c'S16' file type mnemonics
|
|
dc c'RTL'
|
|
dc c'EXE'
|
|
dc c'PIF'
|
|
dc c'TIF'
|
|
dc c'NDA'
|
|
dc c'CDA'
|
|
dc c'TOL'
|
|
dc c'DVR'
|
|
dc c'LDF'
|
|
dc c'FST'
|
|
nameEnd anop
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* NewSegment - create a new segment record
|
|
*
|
|
* Inputs:
|
|
* loadNamePtr - pointer to the load name
|
|
* lastLoadNumber - load number for the last segment created
|
|
*
|
|
* Outputs:
|
|
* loadNumber - number of this load segment
|
|
* loadName - name of the load segment
|
|
* pc - 0
|
|
* * - all other load record variables are set to 0
|
|
*
|
|
****************************************************************
|
|
*
|
|
NewSegment private
|
|
using Common
|
|
using OutCommon
|
|
|
|
move #0,loadNext,#loadSize
|
|
move4 loadNamePtr,r0
|
|
ldy #nameSize-2
|
|
lb1 lda [r0],Y
|
|
sta loadName,Y
|
|
dey
|
|
dey
|
|
bpl lb1
|
|
inc lastLoadNumber
|
|
lda lastLoadNumber
|
|
sta loadNumber
|
|
stz pc
|
|
stz pc+2
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* OptimizeDS - optimize DS and LConst records
|
|
*
|
|
* This subroutine removes LConst records that have a length
|
|
* of zero, and combines adjacent DS records.
|
|
*
|
|
* Inputs:
|
|
* op - ptr to the end of the load segment body
|
|
* opst - copy of op
|
|
* loadSegStart - start of the load segment body
|
|
*
|
|
* Outputs:
|
|
* op - ptr to the end of the load segment body
|
|
* opst - copy of op
|
|
*
|
|
****************************************************************
|
|
*
|
|
OptimizeDS private
|
|
using Common
|
|
using OutCommon
|
|
LConst equ $F2 long contanst op-code
|
|
DS equ $F0 DS op-code
|
|
|
|
lda loadSegStart r0 = to address
|
|
ldx loadSegStart+2 r4 = from address
|
|
sta r0
|
|
stx r2
|
|
sta r4
|
|
stx r6
|
|
stz r8 r8 = false {r0, r4 are the same}
|
|
lb2 cmpl r4,op while r4 <> op do
|
|
jge lb12
|
|
lda [r4] if r4^ = LConst then
|
|
and #$00FF
|
|
cmp #LConst
|
|
bne lb3
|
|
ldy #1 if length = 0 then
|
|
lda [r4],Y
|
|
ldy #3
|
|
ora [r4],Y
|
|
bne lb4
|
|
add4 r4,#5 skip the record
|
|
lda #1 r8 := true
|
|
sta r8
|
|
bra lb2
|
|
lb3 add4 r4,#5,r10 else {if r4^ = DS then}
|
|
lb3a cmpl r10,op if (r10 = r4+5) < op then
|
|
bge lb4
|
|
lda [r10] if r10^ = LConst then
|
|
and #$00FF
|
|
cmp #LConst
|
|
bne lb3b
|
|
ldy #1 if r10^.length = 0 then
|
|
lda [r10],Y
|
|
ldy #3
|
|
ora [r10],Y
|
|
bne lb4
|
|
add4 r10,#5 skip the lconst
|
|
lda #1 r8 := true
|
|
sta r8
|
|
bra lb3a try again
|
|
lb3b ldy #1 else if r10^ = DS then
|
|
clc r10^.length += r4^.length
|
|
lda [r10],Y
|
|
adc [r4],Y
|
|
sta [r10],Y
|
|
ldy #3
|
|
lda [r10],Y
|
|
adc [r4],Y
|
|
sta [r10],Y
|
|
move4 r10,r4 r4 := r10
|
|
lda #1 r8 := true
|
|
sta r8
|
|
bra lb3 try again
|
|
lb4 lda r8 {move the record to the new spot}
|
|
beq lb10 if the record needs to be moved then
|
|
lda [r4] if r4^ = LConst then
|
|
and #$00FF
|
|
cmp #Lconst
|
|
bne lb9
|
|
ldy #1
|
|
lda [r4],Y
|
|
sta r10
|
|
ldy #3
|
|
lda [r4],Y
|
|
sta r12
|
|
add4 r10,#5
|
|
ldx r12
|
|
beq lb6
|
|
ldy #0
|
|
lb5 lda [r4],Y
|
|
sta [r0],Y
|
|
iny
|
|
iny
|
|
bne lb5
|
|
inc r2
|
|
inc r6
|
|
dex
|
|
bne lb5
|
|
lb6 lda r10
|
|
beq lb10
|
|
ldy #0
|
|
lsr A
|
|
tax
|
|
bcc lb7
|
|
short M
|
|
lda [r4]
|
|
sta [r0]
|
|
long M
|
|
iny
|
|
lb7 txa
|
|
beq lb10
|
|
lb8 lda [r4],Y
|
|
sta [r0],Y
|
|
iny
|
|
iny
|
|
dex
|
|
bne lb8
|
|
bra lb10 else {if r4^ = DS then}
|
|
lb9 lda [r4]
|
|
sta [r0]
|
|
ldy #2
|
|
lda [r4],Y
|
|
sta [r0],Y
|
|
iny
|
|
lda [r4],Y
|
|
sta [r0],Y
|
|
lb10 lda [r0] {next record}
|
|
and #$00FF
|
|
cmp #LConst
|
|
bne lb11
|
|
clc
|
|
ldy #1
|
|
lda [r0],Y
|
|
adc r4
|
|
tax
|
|
ldy #3
|
|
lda [r0],Y
|
|
adc r6
|
|
sta r6
|
|
stx r4
|
|
clc
|
|
ldy #1
|
|
lda [r0],Y
|
|
adc r0
|
|
tax
|
|
ldy #3
|
|
lda [r0],Y
|
|
adc r2
|
|
sta r2
|
|
stx r0
|
|
lb11 add4 r0,#5
|
|
add4 r4,#5
|
|
brl lb2 endwhile
|
|
|
|
lb12 lda r0 op = opst = r0
|
|
ldx r2
|
|
sta op
|
|
stx op+2
|
|
sta opst
|
|
stx opst+2
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* Pass2Prep - prepare a buffer for the first call to pass2
|
|
*
|
|
* Inputs:
|
|
* loadPass2 - has the buffer been prepared for pass 2?
|
|
*
|
|
****************************************************************
|
|
*
|
|
Pass2Prep private
|
|
using Common
|
|
using OutCommon
|
|
|
|
lda pass if this is not pass 2
|
|
cmp #2
|
|
bne lb1
|
|
lda loadPass2 or the buffer has already been prepared
|
|
beq lb2
|
|
lb1 rts return
|
|
|
|
lb2 add4 length,loadPC update the length of the program
|
|
lda loadBanksize check for a bank overflow
|
|
ora loadBanksize+2
|
|
beq lb2a
|
|
cmpl loadPC,loadBanksize
|
|
blt lb2a
|
|
ph4 #0
|
|
ph2 #18
|
|
jsr Error
|
|
lb2a pha get memory for the output buffer
|
|
pha
|
|
clc
|
|
lda loadPC
|
|
adc #5
|
|
tax
|
|
lda loadPC+2
|
|
adc #0
|
|
pha
|
|
phx
|
|
ph2 userID
|
|
ph2 #$8000
|
|
ph4 #0
|
|
_NewHandle
|
|
bcc lb3
|
|
lda #5
|
|
jmp TermError
|
|
lb3 pl4 loadSeg
|
|
move4 loadSeg,r0 dereference the segment
|
|
ldy #2
|
|
lda [r0]
|
|
sta loadSegStart
|
|
sta op
|
|
sta opst
|
|
lda [r0],Y
|
|
sta loadSegStart+2
|
|
sta op+2
|
|
sta opst+2
|
|
add4 op,#5 skip the space for the lConst header
|
|
stz loadPC loadPC = 0
|
|
stz loadPC+2
|
|
stz loadOrg loadOrg = 0
|
|
stz loadOrg+2
|
|
stz loadAlign loadAlign = 0
|
|
stz loadAlign+2
|
|
stz pc pc = 0
|
|
stz pc+2
|
|
inc loadPass2 loadPass2 = true
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* PrintSegmentInfo - print the segment statistics
|
|
*
|
|
* Inputs:
|
|
* loadList - head of the load list
|
|
*
|
|
****************************************************************
|
|
*
|
|
PrintSegmentInfo start
|
|
using Common
|
|
using OutCommon
|
|
|
|
puts #'Segment Information:',cr=t write segment header
|
|
putcr
|
|
puts #' Number Name Type Length Org',cr=t
|
|
putcr
|
|
jsr SaveSegment save the current segment
|
|
lda #1 set the segment number
|
|
sta segment
|
|
lda kflag
|
|
beq lb1
|
|
lda express
|
|
beq lb1
|
|
inc segment
|
|
|
|
lb1 move4 loadList,r0 find the proper segment
|
|
lb2 ldy #loadNumber-loadNext
|
|
lda [r0],Y
|
|
cmp segment
|
|
beq lb3
|
|
ldy #2
|
|
lda [r0],Y
|
|
tax
|
|
lda [r0]
|
|
sta r0
|
|
stx r2
|
|
ora r2
|
|
bne lb2
|
|
|
|
move4 loadList,r0 done - get a segment back
|
|
jsr GetSegment
|
|
rts
|
|
|
|
lb3 put2 segment,#6 print the segment number
|
|
putc #' ',#6
|
|
inc segment
|
|
ldy #loadName-loadNext print the segment name
|
|
short I,M
|
|
ldx #0
|
|
lb3a lda [r0],Y
|
|
beq lb3b
|
|
sta name+1,X
|
|
iny
|
|
inx
|
|
cpx #10
|
|
bne lb3a
|
|
lb3b stx name
|
|
sec
|
|
lda #13
|
|
sbc name
|
|
sta fw
|
|
long I,M
|
|
puts name-1
|
|
putc #'$',fw print the type
|
|
pea 0
|
|
ldy #loadType-loadNext
|
|
lda [r0],Y
|
|
pha
|
|
ph2 #2
|
|
ph2 #0
|
|
jsr PrintHex
|
|
puts #' $' print the length
|
|
ldy #loadPC-loadNext+2
|
|
lda [r0],Y
|
|
pha
|
|
dey
|
|
dey
|
|
lda [r0],Y
|
|
pha
|
|
ph2 #8
|
|
ph2 #0
|
|
jsr PrintHex
|
|
puts #' '
|
|
ldy #loadORG-loadNext+2 print the org
|
|
lda [r0],Y
|
|
sta r6
|
|
dey
|
|
dey
|
|
lda [r0],Y
|
|
sta r4
|
|
ora r6
|
|
beq lb4
|
|
putc #'$'
|
|
ph4 r4
|
|
ph2 #8
|
|
ph2 #0
|
|
jsr PrintHex
|
|
putcr
|
|
brl lb1
|
|
lb4 puts #'Relocatable',cr=t
|
|
brl lb1
|
|
|
|
segment ds 2 segment number
|
|
name dc i1'10',10c' ' segment name
|
|
fw dc i'0' field width for spaces after name
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* Remap - remap the segment numbers in interseg references
|
|
*
|
|
* Inputs:
|
|
* loadDictStart - start of the dictionary
|
|
*
|
|
* Notes:
|
|
* This remapping is needed when express loading a segment
|
|
* changes the segment numbers.
|
|
*
|
|
****************************************************************
|
|
*
|
|
Remap private
|
|
using OutCommon
|
|
|
|
move4 loadDictStart,r0
|
|
|
|
lb1 lda [r0] get an op code
|
|
and #$00FF
|
|
jeq lb5 quit if it is the end
|
|
|
|
cmp #$E2 skip reloc
|
|
bne lb2
|
|
add4 r0,#11
|
|
bra lb1
|
|
|
|
lb2 cmp #$E3 remap interseg
|
|
bne lb3
|
|
ldy #9
|
|
lda [r0],Y
|
|
dec A
|
|
asl A
|
|
tay
|
|
lda [expMap],Y
|
|
ldy #9
|
|
sta [r0],Y
|
|
add4 r0,#15
|
|
bra lb1
|
|
|
|
lb3 cmp #$F5 skip cReloc
|
|
bne lb4
|
|
add4 r0,#7
|
|
bra lb1
|
|
|
|
lb4 cmp #$F7 remap Super
|
|
jne lb4a
|
|
ldy #5 if r0^.type = 2 {interseg1} then
|
|
lda [r0],Y
|
|
and #$00FF
|
|
cmp #2
|
|
jne sp7
|
|
add4 r0,#6,r4 r4 = disp to 1st subrecord
|
|
sec r8 = page offset
|
|
lda loadSegStart
|
|
sbc #$0100-7
|
|
sta r8
|
|
lda loadSegStart+2
|
|
sbc #0
|
|
sta r10
|
|
ldy #1 r12 = # bytes to process
|
|
lda [r0],Y
|
|
dec A
|
|
sta r12
|
|
sp1 lda [r4] repeat
|
|
and #$00FF if r4^ & $80 <> 0 then
|
|
bit #$0080
|
|
beq sp4
|
|
and #$007F add in the page displacement
|
|
bne sp2
|
|
lda #$0080
|
|
sp2 xba
|
|
clc
|
|
adc r8
|
|
sta r8
|
|
bcc sp3
|
|
inc r10
|
|
sp3 inc4 r4 ++r4
|
|
dec r12 --r12
|
|
bra sp6 next entry
|
|
sp4 sta r14 else r14 = #bytes + 1
|
|
inc4 r4 skip the count byte
|
|
dec r12
|
|
lda r8 new page
|
|
clc
|
|
adc #$100
|
|
sta r8
|
|
bcc sp5
|
|
inc r10
|
|
sp5 short I,M repeat
|
|
lda [r4] remap one segment
|
|
tay
|
|
tax
|
|
lda [r8],Y
|
|
dec A
|
|
asl A
|
|
tay
|
|
lda [expMap],Y
|
|
txy
|
|
sta [r8],Y
|
|
long I,M
|
|
inc4 r4 ++r4
|
|
dec r12 --r12
|
|
dec r14 --r14
|
|
bpl sp5 until r14 < 0
|
|
sp6 lda r12 until r12 = 0
|
|
bne sp1
|
|
bra sp9
|
|
sp7 cmp #14 else if r0^.type in [14..25] then
|
|
blt sp9
|
|
cmp #26
|
|
bge sp8
|
|
short I,M remap the segment number
|
|
sec
|
|
sbc #14
|
|
asl A
|
|
tay
|
|
lda [expMap],Y
|
|
clc
|
|
adc #13
|
|
ldy #5
|
|
sta [r0],Y
|
|
long I,M
|
|
bra sp9 else if r0^.type in [26..37] then
|
|
sp8 short I,M remap the segment number
|
|
sec
|
|
sbc #26
|
|
asl A
|
|
tay
|
|
lda [expMap],Y
|
|
clc
|
|
adc #25
|
|
ldy #5
|
|
sta [r0],Y
|
|
long I,M
|
|
sp9 anop endif
|
|
ldy #1 skip the record
|
|
clc
|
|
lda [r0],Y
|
|
adc r0
|
|
tax
|
|
iny
|
|
iny
|
|
lda [r0],Y
|
|
adc r2
|
|
sta r2
|
|
stx r0
|
|
add4 r0,#5
|
|
brl lb1
|
|
|
|
lb4a short I,M remap cInterseg
|
|
ldy #5
|
|
lda [r0],Y
|
|
dec A
|
|
asl A
|
|
tay
|
|
lda [expMap],Y
|
|
ldy #5
|
|
sta [r0],Y
|
|
long I,M
|
|
add4 r0,#8
|
|
brl lb1
|
|
|
|
lb5 rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* RemapJumpTable - remap the segment numbers in the jump table
|
|
*
|
|
* Inputs:
|
|
* loadSegStart - start of the jump table buffer
|
|
*
|
|
* Notes:
|
|
* This remapping is needed when express loading a segment
|
|
* changes the segment numbers.
|
|
*
|
|
****************************************************************
|
|
*
|
|
RemapJumpTable private
|
|
using OutCommon
|
|
|
|
add4 loadSegStart,#8+5,r0
|
|
|
|
lb1 ldy #2 quit if file = 0
|
|
lda [r0],Y
|
|
beq lb2
|
|
|
|
ldy #4 remap a segment
|
|
lda [r0],Y
|
|
dec A
|
|
asl A
|
|
tay
|
|
lda [expMap],Y
|
|
ldy #4
|
|
sta [r0],Y
|
|
add4 r0,#14
|
|
bra lb1
|
|
|
|
lb2 rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* SaveSegment - save the current load segment record
|
|
*
|
|
****************************************************************
|
|
*
|
|
SaveSegment private
|
|
using OutCommon
|
|
|
|
move4 loadList,loadNext insert the record in the linked list
|
|
stz loadLast
|
|
stz loadLast+2
|
|
move4 pc,loadPC save the current pc
|
|
lda loadSeg if there is a segment buffer then
|
|
ora loadSeg+2
|
|
beq lb1
|
|
sub4 op,loadSegStart,loadOp save the op displacement
|
|
sub4 opst,loadSegStart,loadOpSt save the opst displacement
|
|
ph4 loadSeg unlock the segment buffer
|
|
_HUnlock
|
|
lb1 lda loadDict if there is a dictionary buffer then
|
|
ora loadDict+2
|
|
beq lb2
|
|
sub4 dp,loadDictStart,loadDP save the dp displacement
|
|
ph4 loadDict unlock the dictionary buffer
|
|
_HUnlock
|
|
lb2 lda loadPtr if there is no spot reserved then
|
|
ora loadPtr+2
|
|
bne lb3
|
|
ph2 #loadSize get some space
|
|
jsr GetSymbolMemory
|
|
sta loadPtr
|
|
stx loadPtr+2
|
|
lb3 move4 loadPtr,r0 save the record
|
|
ldy #loadSize-2
|
|
lb4 lda loadNext,Y
|
|
sta [r0],Y
|
|
dey
|
|
dey
|
|
bpl lb4
|
|
lda loadList if loadList <> nil then
|
|
ora loadList+2
|
|
beq lb5
|
|
move4 loadList,r0 loadList^.loadLast = loadPtr
|
|
ldy #loadLast-loadNext
|
|
lda loadPtr
|
|
sta [r0],Y
|
|
iny
|
|
iny
|
|
lda loadPtr+2
|
|
sta [r0],Y
|
|
lb5 move4 loadPtr,loadList point the head to this segment
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* SetFileType - set the file type and aux type
|
|
*
|
|
* Inputs:
|
|
* kname - keep name pointer
|
|
*
|
|
****************************************************************
|
|
*
|
|
SetFileType private
|
|
;
|
|
; Get the current file info
|
|
;
|
|
move4 kname,giPathName
|
|
OSGet_File_Info giRec
|
|
;
|
|
; Set the file type
|
|
;
|
|
ph4 #FileType read the file type variable
|
|
jsr ReadVariable
|
|
sta r0
|
|
stx r2
|
|
lda [r0] if the variable exists then
|
|
beq lb2
|
|
jsr NamedVariable handle a named variable
|
|
bcs lb1
|
|
jsr DecimalVariable handle a decimal variable
|
|
bcs lb1
|
|
jsr HexVariable handle a hex variable
|
|
bcs lb1
|
|
err13 ph4 #0 flag a bad file name error
|
|
ph2 #13
|
|
jsr Error
|
|
bra lb2
|
|
lb1 txy check for a file type out of range
|
|
bne err13
|
|
cmp #$B3
|
|
blt err13
|
|
cmp #$BF+1
|
|
bge err13
|
|
sta giFileType set the file type
|
|
bra lb3 else
|
|
lb2 lda #EXE use the default file type
|
|
sta giFileType
|
|
lb3 anop endif
|
|
ph4 r0 Free(r0)
|
|
jsr Free
|
|
;
|
|
; Set the aux type
|
|
;
|
|
ph4 #AuxType read the file type variable
|
|
jsr ReadVariable
|
|
sta r0
|
|
stx r2
|
|
lda [r0] if the variable exists then
|
|
beq ax2
|
|
jsr DecimalVariable handle a decimal variable
|
|
bcs ax1
|
|
jsr HexVariable handle a hex variable
|
|
bcs ax1
|
|
ph4 #0 flag a bad file name error
|
|
ph2 #19
|
|
jsr Error
|
|
bra ax2
|
|
ax1 stx giAuxType+2 save the aux type
|
|
sta giAuxType
|
|
bra ax3 else
|
|
ax2 lla giAuxType,$100 use the default aux type
|
|
ax3 anop endif
|
|
ph4 r0 Free(r0)
|
|
jsr Free
|
|
;
|
|
; Update the file info
|
|
;
|
|
OSSet_File_Info giRec
|
|
bcs fi1
|
|
rts
|
|
|
|
fi1 lda #12
|
|
jmp TermError
|
|
;
|
|
; Local data
|
|
;
|
|
giRec dc i'4' get/set file info record
|
|
giPathname ds 4
|
|
ds 2
|
|
giFileType ds 2
|
|
giAuxType ds 4
|
|
|
|
FileType dos KeepType filetype shell variable name
|
|
AuxType dos AuxType auxtype shell variable name
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* WriteBody - write the body of a load segment
|
|
*
|
|
* Inputs:
|
|
* loadNext... - load segment record
|
|
* keepRefnum - keep file reference number
|
|
*
|
|
****************************************************************
|
|
*
|
|
WriteBody private
|
|
using Common
|
|
using OutCommon
|
|
|
|
lda express if express then
|
|
beq lb0
|
|
lda loadNumber if loadNumber = dynSegment then
|
|
cmp dynSegment
|
|
bne lb0
|
|
jsr RemapJumpTable remap the dynamic jump table
|
|
lb0 move4 loadSegStart,wrBuff set the buffer address
|
|
sub4 op,loadSegStart,wrLength set the length
|
|
lda keepRefnum set the refnum
|
|
sta wrRefnum
|
|
OSWrite wrRec write the segment
|
|
bcs lb1
|
|
rts
|
|
|
|
lb1 lda #12
|
|
jmp TermError
|
|
;
|
|
; Local data
|
|
;
|
|
wrRec dc i'4' write the segment
|
|
wrRefnum ds 2
|
|
wrBuff ds 4
|
|
wrLength ds 4
|
|
ds 4
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* WriteDictionary - write the dictionary for a load segment
|
|
*
|
|
* Inputs:
|
|
* loadNext... - load segment record
|
|
* keepRefnum - keep file reference number
|
|
*
|
|
****************************************************************
|
|
*
|
|
WriteDictionary private
|
|
using Common
|
|
using OutCommon
|
|
|
|
sub4 dp,loadDictStart,wrLength set the length
|
|
move4 loadDictStart,wrBuff set the buffer address
|
|
lda keepRefnum set the refnum
|
|
sta wrRefnum
|
|
OSWrite wrRec write the segment
|
|
bcs lb1
|
|
rts
|
|
|
|
lb1 lda #12
|
|
jmp TermError
|
|
;
|
|
; Local data
|
|
;
|
|
wrRec dc i'4' write the segment
|
|
wrRefnum ds 2
|
|
wrBuff ds 4
|
|
wrLength ds 4
|
|
ds 4
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* WriteHeader - write the segment header for a load segment
|
|
*
|
|
* Inputs:
|
|
* loadNext... - load segment record
|
|
* keepRefnum - keep file reference number
|
|
*
|
|
* Notes:
|
|
* This subroutine also writes the lConst opcode and
|
|
* length field for the code image that will be written
|
|
* by WriteBody.
|
|
*
|
|
****************************************************************
|
|
*
|
|
WriteHeader private
|
|
using OutCommon
|
|
|
|
! set the size of the segment
|
|
sub4 opst,loadSegStart,byteCnt
|
|
add4 byteCnt,#headerEnd-header
|
|
sub4 dp,loadDictStart,r0
|
|
add4 byteCnt,r0
|
|
move4 loadPC,length set the length of the segment
|
|
move4 loadBankSize,bankSize set the bankSize of the segment
|
|
lda loadType set the kind of the segment
|
|
sta kind
|
|
move4 loadORG,org set the org of the segment
|
|
move4 loadAlign,align set the alignment factor of the segment
|
|
lda loadNumber set the segment number
|
|
sta segNum
|
|
move loadName,segName,#nameSize set the segment name
|
|
|
|
lda keepRefnum write the header
|
|
sta wrRefnum
|
|
OSWrite wrRec
|
|
bcs lb1
|
|
rts
|
|
|
|
lb1 lda #12
|
|
jmp TermError
|
|
;
|
|
; Local data
|
|
;
|
|
wrRec dc i'4' write the segment
|
|
wrRefnum ds 2
|
|
da 'header'
|
|
dc i4'headerEnd-header'
|
|
ds 4
|
|
|
|
header anop segment header model
|
|
byteCnt ds 4 length of the segment, in bytes
|
|
dc i4'0' reserved space at the end of the segment
|
|
length ds 4 length of the segment
|
|
dc i1'0' undefined
|
|
dc i1'0' label length
|
|
dc i1'4' number length
|
|
dc i1'2' OMF version
|
|
bankSize ds 4 bank size
|
|
kind ds 2 segment kind
|
|
dc i'0' undefined
|
|
org ds 4 origin
|
|
align ds 4 alignment factor
|
|
dc i1'0' numSex; set to LSB first
|
|
dc i1'0' undefined
|
|
segnum ds 2 segment number
|
|
ds 4 entry point
|
|
dc i'ldName-header' disp to the segment name
|
|
dc i'headerEnd-header' disp to the segment image
|
|
dc i4'0' temp ORG
|
|
ldName dc 10c' ' load segment name; unused in load segs
|
|
dc i1'10' length of the segment name
|
|
segName ds 10 segment name
|
|
headerEnd anop
|
|
end
|
|
|