mirror of
https://github.com/byteworksinc/Linker.git
synced 2024-11-21 13:31:57 +00:00
8aa3c4e8c7
The error "Alignment factor must not exceed segment align factor" is now given when an ALIGN record with greater alignment than its segment is encountered. (This is the error that was given erroneously in other circumstances before the last commit.)
1671 lines
31 KiB
NASM
1671 lines
31 KiB
NASM
keep obj/pass2
|
|
mcopy pass2.mac
|
|
****************************************************************
|
|
*
|
|
* Pass 2
|
|
*
|
|
* This module contains the subroutines used to do pass 2
|
|
* processing of the input files and creation of the output
|
|
* files.
|
|
*
|
|
****************************************************************
|
|
copy directPage
|
|
|
|
****************************************************************
|
|
*
|
|
* Align - align the code to a byte boundary
|
|
*
|
|
* Inputs:
|
|
* sp - pointer to the opcode
|
|
* pc - current program counter
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the next opcode
|
|
* pc - new program counter
|
|
*
|
|
****************************************************************
|
|
*
|
|
Align private
|
|
using Common
|
|
|
|
ldy #1 get the alignment factor
|
|
lda [sp],Y
|
|
sta r0
|
|
iny
|
|
iny
|
|
lda [sp],Y
|
|
sta r2
|
|
cmpl segAlign,r0 if alignment factor > segAlign
|
|
bge lb1
|
|
ph4 #0 Error(NULL,22)
|
|
ph2 #22
|
|
jsr Error
|
|
lb1 add4 sp,#5 skip the alignment opcode and operand
|
|
jsr DefineAlign do the align
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* BExpr - evaluate a local bank expression
|
|
*
|
|
* Inputs:
|
|
* sp - pointer to the opcode
|
|
* pc - current program counter
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the next opcode
|
|
* pc - new program counter
|
|
*
|
|
****************************************************************
|
|
*
|
|
BExpr private
|
|
using ExpCommon
|
|
using OutCommon
|
|
using Common
|
|
|
|
stz saveSegment saveSegment := false
|
|
lda [sp] update the PC
|
|
xba
|
|
and #$00FF
|
|
sta expLength
|
|
lb1 add4 sp,#2 skip the op code and expression length
|
|
ph4 sp evaluate the expression
|
|
jsr Evaluate
|
|
sta expValue
|
|
stx expValue+2
|
|
add4 loadOrg,pc,val1 make sure bank bytes match
|
|
lda symbolRelocatable
|
|
beq lb2
|
|
add4 loadOrg,expValue,val2
|
|
bra lb2a
|
|
lb2 move4 expValue,val2
|
|
lb2a stz mask
|
|
stz mask+2
|
|
short M
|
|
ldx expLength
|
|
beq lb4
|
|
cpx #4
|
|
bge lb4
|
|
ldx #3
|
|
lda #$FF
|
|
lb3 sta mask,X
|
|
dex
|
|
cpx expLength
|
|
bge lb3
|
|
lb4 long M
|
|
lda mask
|
|
and val1
|
|
sta val1
|
|
lda mask+2
|
|
and val1+2
|
|
sta val1+2
|
|
lda mask
|
|
and val2
|
|
cmp val1
|
|
bne lb5
|
|
lda mask+2
|
|
and val2+2
|
|
cmp val1+2
|
|
beq lb6
|
|
lb5 ph4 #0
|
|
ph2 #10
|
|
jsr Error
|
|
bra lb10
|
|
lb6 lda expSegment if the expression uses values in another
|
|
beq lb10 segment then
|
|
cmp loadNumber
|
|
beq lb10
|
|
lda expLength if the expression is too short for
|
|
cmp #3 a legal interseg reference then
|
|
bge lb7
|
|
ph4 #0 flag the error
|
|
ph2 #10
|
|
jsr Error
|
|
bra lb10 skip to "normal" processing
|
|
lb7 lda symbolRelocatable if the expression is relocatable then
|
|
beq lb9
|
|
jsr DictInterseg create a dictionary entry
|
|
sta saveSegment save the save segment flag
|
|
lda shiftFlag if the value is shifted then
|
|
beq lb8
|
|
move4 shiftValue,expValue use the unshifted value
|
|
lb8 anop
|
|
lb9 lda expSegment if the segment is dynamic then
|
|
jsr IsDynamic
|
|
bcc lb11
|
|
ph4 #0 flag the error
|
|
ph2 #17
|
|
jsr Error
|
|
bra lb11 else
|
|
lb10 lda symbolRelocatable if the expression is relocatable then
|
|
beq lb11
|
|
jsr DictReloc create a dictionary entry
|
|
lb11 anop endif
|
|
|
|
jsr PutValue write an expression value
|
|
lda saveSegment if saveSegment then
|
|
beq lb12
|
|
sec save the segment number
|
|
lda op
|
|
sbc saveSegment
|
|
sta r0
|
|
lda op+2
|
|
sbc #0
|
|
sta r2
|
|
short M
|
|
clc
|
|
lda expSegment
|
|
sta [r0]
|
|
long M
|
|
lb12 brl SkipExpression skip the expression
|
|
;
|
|
; Local data
|
|
;
|
|
val1 ds 4 first address
|
|
val2 ds 4 second address
|
|
mask ds 4 bank mask
|
|
saveSegment ds 2 save segment number flag
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* Const - constant bytes
|
|
*
|
|
* Inputs:
|
|
* sp - pointer to the opcode
|
|
* pc - current program counter
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the next opcode
|
|
* pc - new program counter
|
|
*
|
|
****************************************************************
|
|
*
|
|
Const private
|
|
|
|
lda [sp] update the program counter
|
|
and #$00FF
|
|
tay
|
|
clc
|
|
adc pc
|
|
sta pc
|
|
bcc lb1
|
|
inc pc+2
|
|
lb1 inc4 sp skip the op code
|
|
tyx save the length
|
|
|
|
tya move the bytes
|
|
lsr A
|
|
bcc lb2
|
|
short M
|
|
dey
|
|
lda [sp],Y
|
|
sta [op],Y
|
|
long M
|
|
lb2 dey
|
|
dey
|
|
bmi lb3a
|
|
lb3 lda [sp],Y
|
|
sta [op],Y
|
|
dey
|
|
dey
|
|
bpl lb3
|
|
lb3a anop
|
|
txa update the output pointer
|
|
clc
|
|
adc op
|
|
sta op
|
|
bcc lb4
|
|
inc op+2
|
|
lb4 txa update sp
|
|
clc
|
|
adc sp
|
|
sta sp
|
|
bcc lb5
|
|
inc sp+2
|
|
lb5 rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* DefineAlign - align to a power of 2 boundary
|
|
*
|
|
* Inputs:
|
|
* r0 - alignment factor
|
|
* sp - pointer to the opcode
|
|
* pc - current program counter
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the next opcode
|
|
* pc - new program counter
|
|
*
|
|
****************************************************************
|
|
*
|
|
DefineAlign start
|
|
using Common
|
|
|
|
stz total total = 0
|
|
stz total+2
|
|
move4 pc,tpc save the pc
|
|
ph4 r0 check the alignment factor
|
|
jsr CheckAlign
|
|
dec4 r0 align the PC
|
|
|
|
lb1 lda r0 quit if we are aligned
|
|
and pc
|
|
bne lb2
|
|
lda r2
|
|
and pc+2
|
|
beq lb5
|
|
lb2 lda r0 form the remaining bit mask
|
|
and pc
|
|
sta r4
|
|
lda r2
|
|
and pc+2
|
|
sta r6
|
|
lda #1 find the least significant bit
|
|
sta r8
|
|
stz r10
|
|
lb3 lda r8
|
|
and r4
|
|
bne lb4
|
|
lda r10
|
|
and r6
|
|
bne lb4
|
|
asl r8
|
|
rol r10
|
|
bra lb3
|
|
lb4 add4 total,r8 update the total
|
|
add4 pc,r8
|
|
bra lb1 check the next bit
|
|
|
|
lb5 move4 tpc,pc reset pc
|
|
lda total if total <> 0 then
|
|
ora total+2
|
|
beq lb6
|
|
move4 total,r0 define an appropriate DS record
|
|
jsr DefineDS
|
|
lb6 rts
|
|
|
|
total ds 4 total DS space
|
|
tpc ds 4 temp pc
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* DefineDS - reserve space in a segment
|
|
*
|
|
* Inputs:
|
|
* r0 - # of bytes to reserve
|
|
* sp - pointer to the opcode
|
|
* pc - current program counter
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the next opcode
|
|
* pc - new program counter
|
|
*
|
|
****************************************************************
|
|
*
|
|
DefineDS start
|
|
using Common
|
|
|
|
add4 pc,r0 update the program count
|
|
lda express if express or (r0 < 10) then
|
|
bne lb0
|
|
lda r2
|
|
bne lb7
|
|
lda r0
|
|
cmp #10
|
|
bge lb7
|
|
lb0 ldx r2 fill 64K areas
|
|
beq lb2
|
|
ldy #0
|
|
tya
|
|
lb1 sta [op],Y
|
|
dey
|
|
dey
|
|
bne lb1
|
|
inc op+2
|
|
dex
|
|
bne lb1
|
|
lb2 short M fill in remaining bytes
|
|
lda #0
|
|
ldy r0
|
|
beq lb5
|
|
dey
|
|
beq lb4
|
|
lb3 sta [op],Y
|
|
dey
|
|
bne lb3
|
|
lb4 sta [op]
|
|
lb5 long M
|
|
clc update op
|
|
lda op
|
|
adc r0
|
|
sta op
|
|
bcc lb6
|
|
inc op+2
|
|
lb6 bra lb8 else {if not express then}
|
|
lb7 ph4 r0 finish off the current lConst
|
|
jsr FinishLConst
|
|
pl4 r0
|
|
lda #$F1 place a DS record in the segment
|
|
sta [op]
|
|
ldy #1
|
|
lda r0
|
|
sta [op],Y
|
|
iny
|
|
iny
|
|
lda r2
|
|
sta [op],Y
|
|
add4 op,#5,opst start a new lConst
|
|
add4 op,#10 update op
|
|
lb8 anop endif
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* DefineSegment - put the segment in the symbol table
|
|
*
|
|
* Inputs:
|
|
* segName - pointer to the segment name
|
|
* pc - current pc
|
|
* segEntry - disp to segment entry point
|
|
*
|
|
****************************************************************
|
|
*
|
|
DefineSegment private
|
|
using Common
|
|
|
|
ph4 segName push the symbol name ptr
|
|
ph2 #1 the symbol is global
|
|
clc push the location
|
|
lda pc
|
|
adc segEntry
|
|
tax
|
|
lda pc+2
|
|
adc segEntry+2
|
|
pha
|
|
phx
|
|
jsr Define2 define the symbol
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* DictReloc - Create a relocatable dictionary entry (current bank)
|
|
*
|
|
* Inputs:
|
|
* bankOrg - is the program bank relative?
|
|
* expLength - expression length
|
|
* expValue - expression value
|
|
* shiftFlag - is the value shifted?
|
|
* shiftValue - value before a shift
|
|
* shiftCount - shift counter
|
|
*
|
|
****************************************************************
|
|
*
|
|
DictReloc private
|
|
using Common
|
|
using ExpCommon
|
|
using OutCommon
|
|
|
|
lda bankOrg if the program is bank relative then
|
|
beq lb0
|
|
lda shiftFlag if the value is not shifted then
|
|
bne lb0
|
|
lda expLength if the expression is 1 or 2 bytes then
|
|
cmp #3
|
|
bge lb0
|
|
rts return
|
|
|
|
lb0 lda #11 make sure there is room in the dictionary
|
|
cmp loadDictSize
|
|
blt lb1
|
|
jsr ExpandDictBuffer
|
|
|
|
lb1 lda shiftFlag if the expression is shifted then
|
|
beq lb1a
|
|
move4 shiftValue,val use the unshifted value
|
|
bra lb1b else
|
|
lb1a move4 expValue,val use the returned value
|
|
lb1b anop endif
|
|
lda val+2 short = val and pc < 64K
|
|
ora pc+2
|
|
sta short
|
|
short M if short then
|
|
bne lb2
|
|
lda #$F5 write the cReloc opcode
|
|
sta [dp]
|
|
lda expLength write the expression length
|
|
cmp #4
|
|
bne lb1c
|
|
dec A
|
|
lb1c ldy #1
|
|
sta [dp],Y
|
|
bra lb3 else
|
|
lb2 lda #$E2 write the Reloc opcode
|
|
sta [dp]
|
|
lda expLength write the expression length
|
|
ldy #1
|
|
sta [dp],Y
|
|
lb3 iny write the shift count
|
|
lda shiftCount
|
|
sta [dp],Y
|
|
long M
|
|
lda short if short then
|
|
bne lb4
|
|
lda pc save the pc
|
|
iny
|
|
sta [dp],Y
|
|
iny save the value
|
|
iny
|
|
lda val
|
|
sta [dp],Y
|
|
add4 dp,#7 update dp
|
|
sub2 loadDictSize,#7 update loadDictSize
|
|
rts return
|
|
|
|
lb4 iny save the pc
|
|
lda pc
|
|
sta [dp],Y
|
|
iny
|
|
iny
|
|
lda pc+2
|
|
sta [dp],Y
|
|
iny save the value
|
|
iny
|
|
lda val
|
|
sta [dp],Y
|
|
iny
|
|
iny
|
|
lda val+2
|
|
sta [dp],Y
|
|
sub2 loadDictSize,#11 update loadDictSize
|
|
add4 dp,#11 update dp
|
|
rts
|
|
;
|
|
; Local data
|
|
;
|
|
short ds 2 is this a cReloc?
|
|
val ds 4 expression value
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* DictInterseg - Create an interseg dictionary entry (another bank)
|
|
*
|
|
* Inputs:
|
|
* expLength - expression length
|
|
* expValue - expression value
|
|
* expSegment - expression segment number
|
|
* shiftFlag - is the value shifted?
|
|
* shiftValue - value before a shift
|
|
* shiftCount - shift counter
|
|
*
|
|
* Outputs:
|
|
* A - 1 if the segment should be saved in the expression,
|
|
* else 0. (The segment is saved with the expression
|
|
* for 3-byte cInterseg expressions with 0 shift when
|
|
* files are being compacted.)
|
|
*
|
|
****************************************************************
|
|
*
|
|
DictInterseg private
|
|
using Common
|
|
using ExpCommon
|
|
using OutCommon
|
|
|
|
stz saveSegment don't save the segment number
|
|
lda #15 make sure there is room in the dictionary
|
|
cmp loadDictSize
|
|
blt lb1
|
|
jsr ExpandDictBuffer
|
|
|
|
lb1 lda shiftFlag if the expression is shifted then
|
|
beq lb1a
|
|
move4 shiftValue,val use the unshifted value
|
|
bra lb1b else
|
|
lb1a move4 expValue,val use the returned value
|
|
lb1b anop endif
|
|
lda expSegment short = (val < 64K) and (pc < 64K)
|
|
and #$FF00 and (expSegment < 256)
|
|
ora val+2
|
|
ora pc+2
|
|
sta short
|
|
short M if short then
|
|
bne lb2
|
|
lda #$F6 write the cInterseg opcode
|
|
sta [dp]
|
|
lda expLength write the expression length
|
|
cmp #4
|
|
bne lb1c
|
|
ldx compact if compact then
|
|
beq ss1
|
|
ldx shiftFlag if not shiftFlag then
|
|
bne ss1
|
|
ldx #2 set saveSegment
|
|
stx saveSegment
|
|
ss1 dec A convert length to 3
|
|
lb1c ldy #1
|
|
sta [dp],Y
|
|
bra lb3 else
|
|
lb2 lda #$E3 write the interseg opcode
|
|
sta [dp]
|
|
lda expLength write the expression length
|
|
ldy #1
|
|
sta [dp],Y
|
|
lb3 ldy #2 write the shift count
|
|
lda shiftCount
|
|
sta [dp],Y
|
|
long M
|
|
lda short if short then
|
|
bne lb4
|
|
lda pc save the pc
|
|
iny
|
|
sta [dp],Y
|
|
iny save the expression segment
|
|
iny
|
|
lda expSegment
|
|
sta [dp],Y
|
|
iny save the value
|
|
lda val
|
|
sta [dp],Y
|
|
sub2 loadDictSize,#8 update loadDictSize
|
|
add4 dp,#8 update dp
|
|
ldx compact if compact then
|
|
beq lb4a
|
|
ldx expLength if expLength = 3 then
|
|
cpx #3
|
|
bne lb4a
|
|
ldx shiftFlag if not shiftFlag then
|
|
bne lb4a
|
|
lda #1 we do need to save the segment
|
|
sta saveSegment
|
|
lb4a lda saveSegment return the save segment code
|
|
rts
|
|
|
|
lb4 iny save the pc
|
|
lda pc
|
|
sta [dp],Y
|
|
iny
|
|
iny
|
|
lda pc+2
|
|
sta [dp],Y
|
|
iny set the file number to 1
|
|
iny
|
|
lda #1
|
|
sta [dp],Y
|
|
iny save the segment number
|
|
iny
|
|
lda expSegment
|
|
sta [dp],Y
|
|
iny save the value
|
|
iny
|
|
lda val
|
|
sta [dp],Y
|
|
iny
|
|
iny
|
|
lda val+2
|
|
sta [dp],Y
|
|
sub2 loadDictSize,#15 update loadDictSize
|
|
add4 dp,#15 update dp
|
|
lda #0 don't save the segment number
|
|
rts
|
|
;
|
|
; Local data
|
|
;
|
|
saveSegment ds 2 save segment code:
|
|
! 0: don't save the segment #
|
|
! 1: save segment # in 3 byte field
|
|
! 2: save segment # in 4 byte field
|
|
short ds 2 is this a cReloc?
|
|
val ds 4 expression value
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* DoOrg - set the program counter
|
|
*
|
|
* Inputs:
|
|
* sp - pointer to the opcode
|
|
* pc - current program counter
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the next opcode
|
|
* pc - new program counter
|
|
*
|
|
****************************************************************
|
|
*
|
|
DoOrg private
|
|
|
|
ldy #1 get the value
|
|
lda [sp],Y
|
|
sta r4
|
|
ldy #3
|
|
lda [sp],Y
|
|
sta r6
|
|
add4 sp,#5 skip the op code & operand
|
|
sub4 pc,r4,r0 calculate the space to insert
|
|
lda r2 if space < 0 then
|
|
bpl lb1
|
|
ph4 #0 Error(NULL,3)
|
|
ph2 #3
|
|
jsr Error
|
|
rts return
|
|
|
|
lb1 jsr DefineDS handle the ORG
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* DoPass2 - Do pass 1 processing
|
|
*
|
|
* Outputs:
|
|
* C - set if an error occurred
|
|
*
|
|
****************************************************************
|
|
*
|
|
DoPass2 start
|
|
using Common
|
|
;
|
|
; Write the pass header
|
|
;
|
|
lda #2 pass = 2
|
|
sta pass
|
|
lda list if (not list) and progress then
|
|
bne wp1
|
|
lda progress
|
|
beq wp1
|
|
puts #'Pass 2: ' print the dot header
|
|
wp1 anop
|
|
;
|
|
; Initialize pass dependent variables
|
|
;
|
|
jsr InitPass
|
|
jsr DynamicCheck
|
|
;
|
|
; Process segments until there are no more
|
|
;
|
|
ps1 jsr NextSegment get the next segment
|
|
bcc rt1 branch if there are no more
|
|
move #0,dataAreas,#256 clear the data area flags
|
|
jsr DefineSegment put the segment in the symbol table
|
|
jsr ListSeg list the segname start info
|
|
jsr DoSegment process the segment
|
|
lda segSpace add in the reserved space (if any)
|
|
ora segSpace+2
|
|
beq ps1
|
|
move4 segSpace,r0
|
|
jsr DefineDS
|
|
bra ps1 next segment
|
|
;
|
|
; Return to main
|
|
;
|
|
rt1 lda list if list or progress then
|
|
bne rt2
|
|
lda progress
|
|
beq rt3
|
|
rt2 putcr write a cr
|
|
rt3 anop endif
|
|
clc
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* DoSegment - process the opcodes in this segment
|
|
*
|
|
* Inputs:
|
|
* sp - pointer to the first opcode to process
|
|
*
|
|
****************************************************************
|
|
*
|
|
DoSegment private
|
|
|
|
lb1 lda [sp]
|
|
and #$00FF
|
|
asl A
|
|
tax
|
|
jsr (addr,X)
|
|
bra lb1
|
|
|
|
addr dc a'End' $00 End
|
|
dc 15a'Const' $01..$0F Const
|
|
dc 16a'Const' $10..$1F Const
|
|
dc 16a'Const' $20..$2F Const
|
|
dc 16a'Const' $30..$3F Const
|
|
dc 16a'Const' $40..$4F Const
|
|
dc 16a'Const' $50..$5F Const
|
|
dc 16a'Const' $60..$6F Const
|
|
dc 16a'Const' $70..$7F Const
|
|
dc 16a'Const' $80..$8F Const
|
|
dc 16a'Const' $90..$9F Const
|
|
dc 16a'Const' $A0..$AF Const
|
|
dc 16a'Const' $B0..$BF Const
|
|
dc 16a'Const' $C0..$CF Const
|
|
dc 16a'Const' $D0..$DF Const
|
|
dc a'Align' $E0 Align
|
|
dc a'DoOrg' $E1 Org
|
|
dc a'Invalid' $E2 Reloc
|
|
dc a'Invalid' $E3 Interseg
|
|
dc a'Using' $E4 Using
|
|
dc a'Strong' $E5 Strong
|
|
dc a'Global' $E6 Global
|
|
dc a'Gequ' $E7 Gequ
|
|
dc a'Invalid' $E8 Mem
|
|
dc a'Invalid' $E9 unused
|
|
dc a'Invalid' $EA unused
|
|
dc a'Expr' $EB Expr
|
|
dc a'ZExpr' $EC ZExpr
|
|
dc a'BExpr' $ED BExpr
|
|
dc a'RelExpr' $EE RelExpr
|
|
dc a'Local' $EF Local
|
|
dc a'Equ' $F0 Equ
|
|
dc a'DS' $F1 DS
|
|
dc a'Lconst' $F2 LConst
|
|
dc a'LExpr' $F3 LExpr
|
|
dc a'Invalid' $F4 Entry
|
|
dc a'Invalid' $F5 cReloc
|
|
dc a'Invalid' $F6 cInterseg
|
|
dc a'Invalid' $F7 Super
|
|
dc a'Invalid' $F8 unused
|
|
dc a'Invalid' $F9 unused
|
|
dc a'Invalid' $FA unused
|
|
dc a'Invalid' $FB unused
|
|
dc a'Invalid' $FC unused
|
|
dc a'Invalid' $FD unused
|
|
dc a'Invalid' $FE unused
|
|
dc a'Invalid' $FF unused
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* DS - insert zeros at the PC
|
|
*
|
|
* Inputs:
|
|
* sp - pointer to the opcode
|
|
* pc - current program counter
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the next opcode
|
|
* pc - new program counter
|
|
*
|
|
****************************************************************
|
|
*
|
|
DS private
|
|
using Common
|
|
|
|
inc4 sp skip the opcode
|
|
ldy #2 get the DS length
|
|
lda [sp]
|
|
sta r0
|
|
lda [sp],Y
|
|
sta r2
|
|
jsr DefineDS handle the DS
|
|
add4 sp,#4 skip the length
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* End - end of the segment
|
|
*
|
|
****************************************************************
|
|
*
|
|
End private
|
|
|
|
pla
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* EndExp - end of the expression
|
|
*
|
|
* Inputs:
|
|
* sp - pointer to the opcode
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the next opcode
|
|
*
|
|
****************************************************************
|
|
*
|
|
EndExp private
|
|
|
|
inc4 sp
|
|
pla
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* Equ - define a local equate
|
|
*
|
|
* Inputs:
|
|
* sp - pointer to the opcode
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the next opcode
|
|
*
|
|
****************************************************************
|
|
*
|
|
Equ private
|
|
using Common
|
|
|
|
inc4 sp skip the op code
|
|
ph4 sp push the symbol name ptr
|
|
lda [sp] skip the symbol name
|
|
and #$00FF
|
|
sec
|
|
adc sp
|
|
sta sp
|
|
bcc lb1
|
|
inc sp+2
|
|
lb1 lda segVersion if the segment is version 0 ro 1 then
|
|
cmp #2
|
|
beq lb2
|
|
add4 sp,#3 skip the attributes (1 byte length)
|
|
bra lb3 else
|
|
lb2 add4 sp,#4 skip the attributes (2 byte length)
|
|
lb3 anop endif
|
|
ph2 #0 the symbol is local
|
|
ph4 #0 don't check for addressing errors
|
|
jsr Define2 define the symbol
|
|
jsr SkipExpression skip the expression
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* Expr - evaluate an expression
|
|
*
|
|
* Inputs:
|
|
* sp - pointer to the opcode
|
|
* pc - current program counter
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the next opcode
|
|
* pc - new program counter
|
|
*
|
|
****************************************************************
|
|
*
|
|
Expr private
|
|
using ExpCommon
|
|
using Common
|
|
using OutCommon
|
|
|
|
stz saveSegment saveSegment := false
|
|
lda [sp] update the PC
|
|
xba
|
|
and #$00FF
|
|
sta expLength
|
|
lb1 add4 sp,#2 skip the op code and expression length
|
|
ph4 sp evaluate the expression
|
|
jsr Evaluate
|
|
sta expValue
|
|
stx expValue+2
|
|
lda expSegment if the expression uses values in another
|
|
beq lb2 segment then
|
|
cmp loadNumber
|
|
beq lb2
|
|
lda symbolRelocatable if the expression is relocatable then
|
|
beq lb1a
|
|
jsr DictInterseg create a dictionary entry
|
|
sta saveSegment save the save segment flag
|
|
lda shiftFlag if the value is shifted then
|
|
beq sh1 use the unshifted value
|
|
move4 shiftValue,expValue
|
|
sh1 anop
|
|
lb1a lda expSegment if the segment is dynamic then
|
|
jsr IsDynamic
|
|
bcc lb3
|
|
ph4 #0 flag the error
|
|
ph2 #17
|
|
jsr Error
|
|
bra lb3 else
|
|
lb2 lda symbolRelocatable if the expression is relocatable then
|
|
beq lb3
|
|
jsr DictReloc create a dictionary entry
|
|
lb3 anop endif
|
|
jsr PutValue write an expression value
|
|
lda saveSegment if saveSegment then
|
|
beq lb4
|
|
sec save the segment number
|
|
lda op
|
|
sbc saveSegment
|
|
sta r0
|
|
lda op+2
|
|
sbc #0
|
|
sta r2
|
|
short M
|
|
clc
|
|
lda expSegment
|
|
sta [r0]
|
|
long M
|
|
lb4 brl SkipExpression skip the expression
|
|
|
|
saveSegment ds 2 save segment number flag
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* Gequ - define a global equate
|
|
*
|
|
* Inputs:
|
|
* sp - pointer to the opcode
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the next opcode
|
|
*
|
|
****************************************************************
|
|
*
|
|
Gequ private
|
|
using Common
|
|
|
|
inc4 sp skip the op code
|
|
ph4 sp push the symbol name ptr
|
|
lda [sp] skip the symbol name
|
|
and #$00FF
|
|
sec
|
|
adc sp
|
|
sta sp
|
|
bcc lb1
|
|
inc sp+2
|
|
lb1 lda segVersion if the segment is version 0 or 1 then
|
|
cmp #2
|
|
beq lb2
|
|
add4 sp,#3 skip the attributes (1 byte length)
|
|
bra lb3 else
|
|
lb2 add4 sp,#4 skip the attributes (2 byte length)
|
|
lb3 anop endif
|
|
ph2 #1 the symbol is global
|
|
ph4 #0 don't ceck for addressing errors
|
|
jsr Define2 define the symbol
|
|
jsr SkipExpression skip the expression
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* Global - define a global label at the PC
|
|
*
|
|
* Inputs:
|
|
* sp - pointer to the opcode
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the next opcode
|
|
*
|
|
****************************************************************
|
|
*
|
|
Global private
|
|
using Common
|
|
|
|
inc4 sp skip the op code
|
|
ph4 sp push the symbol name ptr
|
|
lda [sp] skip the symbol name
|
|
and #$00FF
|
|
sec
|
|
adc sp
|
|
sta sp
|
|
bcc lb1
|
|
inc sp+2
|
|
lb1 lda segVersion if the segment is version 0 ro 1 then
|
|
cmp #2
|
|
beq lb2
|
|
add4 sp,#3 skip the attributes (1 byte length)
|
|
bra lb3 else
|
|
lb2 add4 sp,#4 skip the attributes (2 byte length)
|
|
lb3 anop endif
|
|
ph2 #1 the symbol is global
|
|
ph4 pc push the pass 2 value
|
|
jsr Define2 define the symbol
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* Invalid - invalid op code
|
|
*
|
|
* Notes:
|
|
* An invalid opcode stops the link process with a
|
|
* terminal error.
|
|
*
|
|
****************************************************************
|
|
*
|
|
Invalid private
|
|
|
|
lda #8
|
|
jmp TermError
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* LConst - long constant bytes
|
|
*
|
|
* Inputs:
|
|
* sp - pointer to the opcode
|
|
* pc - current program counter
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the next opcode
|
|
* pc - new program counter
|
|
*
|
|
****************************************************************
|
|
*
|
|
LConst private
|
|
|
|
ldy #1 get the length
|
|
lda [sp],Y
|
|
sta r0
|
|
iny
|
|
iny
|
|
lda [sp],Y
|
|
sta r2
|
|
add4 sp,#5 skip the op code, length
|
|
|
|
ldx r2 move 64K chunks
|
|
beq lb3
|
|
ldy #0
|
|
lb2 lda [sp],Y
|
|
sta [op],Y
|
|
dey
|
|
dey
|
|
bne lb2
|
|
inc op+2
|
|
inc sp+2
|
|
inc pc+2
|
|
dec r2
|
|
bne lb2
|
|
lb3 ldy r0 move the remaining bytes
|
|
beq lb6
|
|
short M
|
|
dey
|
|
beq lb5
|
|
lb4 lda [sp],Y
|
|
sta [op],Y
|
|
dey
|
|
bne lb4
|
|
lb5 lda [sp]
|
|
sta [op]
|
|
long M
|
|
|
|
add4 op,r0 update op for the <64K part
|
|
add4 sp,r0 skip the rest of the record
|
|
add4 pc,r0 update the PC
|
|
lb6 rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* LExpr - evaluate an expression, allowing references to dynamic segs
|
|
*
|
|
* Inputs:
|
|
* sp - pointer to the opcode
|
|
* pc - current program counter
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the next opcode
|
|
* pc - new program counter
|
|
*
|
|
****************************************************************
|
|
*
|
|
LExpr private
|
|
using ExpCommon
|
|
using Common
|
|
using OutCommon
|
|
|
|
stz saveSegment saveSegment := false
|
|
lda [sp] update the PC
|
|
xba
|
|
and #$00FF
|
|
sta expLength
|
|
lb1 add4 sp,#2 skip the op code and expression length
|
|
ph4 sp evaluate the expression
|
|
jsr Evaluate
|
|
sta expValue
|
|
stx expValue+2
|
|
lda expSegment if the expression uses values in another
|
|
beq lb2 segment then
|
|
cmp loadNumber
|
|
beq lb2
|
|
lda expSegment if the segment is dynamic then
|
|
jsr IsDynamic
|
|
bcc lb1a
|
|
jsr JumpTable create a jump table entry
|
|
lb1a lda symbolRelocatable if the expression is relocatable then
|
|
beq lb3
|
|
jsr DictInterseg create a dictionary entry
|
|
sta saveSegment save the save segment flag
|
|
lda shiftFlag if the value is shifted then
|
|
beq lb3 use the unshifted value
|
|
move4 shiftValue,expValue
|
|
bra lb3 else
|
|
lb2 lda symbolRelocatable if the expression is relocatable then
|
|
beq lb3
|
|
jsr DictReloc create a dictionary entry
|
|
lb3 anop endif
|
|
jsr PutValue write an expression value
|
|
lda saveSegment if saveSegment then
|
|
beq lb4
|
|
sec save the segment number
|
|
lda op
|
|
sbc saveSegment
|
|
sta r0
|
|
lda op+2
|
|
sbc #0
|
|
sta r2
|
|
short M
|
|
clc
|
|
lda expSegment
|
|
sta [r0]
|
|
long M
|
|
lb4 brl SkipExpression skip the expression
|
|
|
|
saveSegment ds 2 save segment number flag
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* ListSeg - list the segment start info
|
|
*
|
|
* Inputs:
|
|
* segName - ptr to name of the segment
|
|
* segType - segment type
|
|
* pc - segment disp
|
|
* segLength - segment length
|
|
* list - list info flag
|
|
*
|
|
****************************************************************
|
|
*
|
|
ListSeg private
|
|
using Common
|
|
using OutCommon
|
|
|
|
lda list if list then
|
|
jeq lb3
|
|
ph4 pc print the program counter
|
|
ph2 #8
|
|
ph2 #0
|
|
jsr PrintHex
|
|
putc #' '
|
|
ph4 segLength print the segment length
|
|
ph2 #8
|
|
ph2 #0
|
|
jsr PrintHex
|
|
putc #' ' print the load segment number
|
|
lda loadNumber
|
|
ldx kflag
|
|
beq lb0
|
|
ldx express
|
|
beq lb0
|
|
inc A
|
|
lb0 pea 0
|
|
pha
|
|
ph2 #2
|
|
ph2 #0
|
|
jsr PrintHex
|
|
lda segType print the segment type
|
|
lsr A
|
|
bcc lb1
|
|
puts #' Data: '
|
|
bra lb2
|
|
lb1 puts #' Code: '
|
|
lb2 sub4 segName,#1,r0 print the segment name
|
|
puts [r0],cr=t
|
|
jsr CheckForPause check for early exit
|
|
rts
|
|
|
|
lb3 lda progress else if progres then
|
|
beq lb4
|
|
putc #'.' print a dot
|
|
lb4 jsr CheckForPause check for early exit
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* Local - define a local label at the PC
|
|
*
|
|
* Inputs:
|
|
* sp - pointer to the opcode
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the next opcode
|
|
*
|
|
****************************************************************
|
|
*
|
|
Local private
|
|
using Common
|
|
|
|
inc4 sp skip the op code
|
|
ph4 sp push the symbol name ptr
|
|
lda [sp] skip the symbol name
|
|
and #$00FF
|
|
sec
|
|
adc sp
|
|
sta sp
|
|
bcc lb1
|
|
inc sp+2
|
|
lb1 lda segVersion if the segment is version 0 ro 1 then
|
|
cmp #2
|
|
beq lb2
|
|
add4 sp,#3 skip the attributes (1 byte length)
|
|
bra lb3 else
|
|
lb2 add4 sp,#4 skip the attributes (2 byte length)
|
|
lb3 anop endif
|
|
ph2 #0 the symbol is local
|
|
ph4 pc push the pass 2 value
|
|
jsr Define2 define the symbol
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* Operation - handle an operation in an expression
|
|
*
|
|
* Inputs:
|
|
* sp - pointer to the operation
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the next expression term
|
|
*
|
|
****************************************************************
|
|
*
|
|
Operation private
|
|
|
|
inc4 sp
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* PutValue - write a value to the file
|
|
*
|
|
* Inputs:
|
|
* expValue - expression value
|
|
* expLength - expression length
|
|
*
|
|
****************************************************************
|
|
*
|
|
PutValue private
|
|
using ExpCommon
|
|
|
|
lda expLength write the value
|
|
cmp #2
|
|
bge lb4
|
|
short M write a 1 byte value
|
|
lda expValue
|
|
sta [op]
|
|
long M
|
|
bra lb7
|
|
lb4 bne lb5
|
|
lda expValue write a 2 byte value
|
|
sta [op]
|
|
bra lb7
|
|
lb5 cmp #4
|
|
beq lb6
|
|
lda expValue write a 3 byte value
|
|
sta [op]
|
|
ldy #1
|
|
lda expValue+1
|
|
sta [op],Y
|
|
bra lb7
|
|
lb6 lda expValue write a 4 byte value
|
|
sta [op]
|
|
ldy #2
|
|
lda expValue+2
|
|
sta [op],Y
|
|
lb7 clc update op
|
|
lda op
|
|
adc expLength
|
|
sta op
|
|
bcc lb8
|
|
inc op+2
|
|
lb8 clc update pc
|
|
lda pc
|
|
adc expLength
|
|
sta pc
|
|
bcc lb9
|
|
inc pc+2
|
|
lb9 rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* RelExpr - evaluate a relative expression
|
|
*
|
|
* Inputs:
|
|
* sp - pointer to the opcode
|
|
* pc - current program counter
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the next opcode
|
|
* pc - new program counter
|
|
*
|
|
****************************************************************
|
|
*
|
|
RelExpr private
|
|
using ExpCommon
|
|
using Common
|
|
using OutCommon
|
|
|
|
lda [sp] update the PC
|
|
xba
|
|
and #$00FF
|
|
sta expLength
|
|
lb1 ldy #2 add pc, org and value
|
|
clc
|
|
lda [sp],Y
|
|
adc pc
|
|
sta t1
|
|
iny
|
|
iny
|
|
lda [sp],Y
|
|
adc pc+2
|
|
sta t1+2
|
|
add4 t1,loadOrg
|
|
add4 sp,#6 skip the op code, length & value
|
|
ph4 sp evaluate the expression
|
|
jsr Evaluate
|
|
sta expValue
|
|
stx expValue+2
|
|
sub4 expValue,t1 compute rel displacement
|
|
|
|
add4 expValue,loadOrg,t1 t1 = expValue+loadOrg
|
|
short I,M check t1 for branch out of range
|
|
lda expLength
|
|
cmp #4
|
|
bge lb6
|
|
tay
|
|
tax
|
|
lda t1,X
|
|
bmi lb3
|
|
lb2 lda t1,X
|
|
bne lb5
|
|
inx
|
|
cpx #4
|
|
blt lb2
|
|
lda t1-1,Y
|
|
bpl lb6
|
|
bra lb4a
|
|
lb3 lda #$FF
|
|
lb4 cmp t1,X
|
|
bne lb5
|
|
inx
|
|
cpx #4
|
|
blt lb4
|
|
lda t1-1,Y
|
|
bmi lb6
|
|
lb4a lda expLength let BRL wrap around within program bank
|
|
cmp #2
|
|
bge lb6
|
|
lb5 long I,M
|
|
ph4 #0
|
|
ph2 #11
|
|
jsr Error
|
|
lb6 long I,M
|
|
|
|
lda expSegment if the expression uses values in another
|
|
beq lb7 segment then flag the error
|
|
cmp loadNumber
|
|
beq lb7
|
|
ph4 #0
|
|
ph2 #10
|
|
jsr Error
|
|
lb7 jsr PutValue write an expression value
|
|
brl SkipExpression skip the expression
|
|
|
|
t1 ds 4 temp value
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* SkipExpression - skip an expression, noting label uses
|
|
*
|
|
* Inputs:
|
|
* sp - pointer to the first opcode in the expression
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the first opcode past the expression
|
|
*
|
|
****************************************************************
|
|
*
|
|
SkipExpression private
|
|
|
|
lb1 lda [sp]
|
|
and #$00FF
|
|
asl A
|
|
tax
|
|
jsr (addr,X)
|
|
bra lb1
|
|
|
|
addr dc a'EndExp' $00 End
|
|
dc 15a'Operation' $01..$0F some form of operation
|
|
dc 6a'Operation' $10..$15 some form of operation
|
|
dc 10a'Invalid' $16..$1F unused
|
|
dc 16a'Invalid' $20..$2F unused
|
|
dc 16a'Invalid' $30..$3F unused
|
|
dc 16a'Invalid' $40..$4F unused
|
|
dc 16a'Invalid' $50..$5F unused
|
|
dc 16a'Invalid' $60..$6F unused
|
|
dc 16a'Invalid' $70..$7F unused
|
|
dc a'Operation' $80 program counter
|
|
dc a'Value' $81 absolute value
|
|
dc a'WeakReference' $82 weak label reference
|
|
dc a'StrongReference' $83 strong label reference
|
|
dc a'StrongReference' $84 length attribute
|
|
dc a'StrongReference' $85 type attribute
|
|
dc a'WeakReference' $86 count attribute
|
|
dc a'Value' $87 disp from start of segment
|
|
dc 8a'Invalid' $88-8F unused
|
|
dc 16a'Invalid' $90..$9F unused
|
|
dc 16a'Invalid' $A0..$AF unused
|
|
dc 16a'Invalid' $B0..$BF unused
|
|
dc 16a'Invalid' $C0..$CF unused
|
|
dc 16a'Invalid' $D0..$DF unused
|
|
dc 16a'Invalid' $E0..$EF unused
|
|
dc 16a'Invalid' $F0..$FF unused
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* Strong - Strong label reference
|
|
*
|
|
* Inputs:
|
|
* sp - pointer to the opcode
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the next opcode
|
|
*
|
|
****************************************************************
|
|
*
|
|
Strong private
|
|
using ExpCommon
|
|
|
|
inc4 sp skip the op code
|
|
jsr Reference2 make a reference to the name
|
|
stz expSegment find the symbol value (forces error)
|
|
ph4 sp
|
|
ph2 #1
|
|
jsr GetSymbolValue
|
|
lda [sp] skip the name in the obj segment
|
|
and #$00FF
|
|
sec
|
|
adc sp
|
|
sta sp
|
|
bcc lb1
|
|
inc sp+2
|
|
lb1 rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* StrongReference - handle a strong label reference in an expression
|
|
*
|
|
* Inputs:
|
|
* sp - pointer to the label name
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the next expression term
|
|
*
|
|
****************************************************************
|
|
*
|
|
StrongReference private
|
|
|
|
inc4 sp skip the op code
|
|
jsr Reference2 make a reference to the name
|
|
lda [sp] skip the name in the segment
|
|
and #$00FF
|
|
sec
|
|
adc sp
|
|
sta sp
|
|
bcc lb1
|
|
inc sp+2
|
|
lb1 rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* Using - Note that we are using a data area
|
|
*
|
|
* Inputs:
|
|
* sp - pointer to the opcode
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the next opcode
|
|
*
|
|
****************************************************************
|
|
*
|
|
Using private
|
|
using ExpCommon
|
|
using Common
|
|
|
|
inc4 sp skip the op code
|
|
jsr Reference2 make a reference to the name
|
|
stz expSegment find the symbol
|
|
ph4 sp
|
|
ph2 #1
|
|
jsr GetSymbolValue
|
|
lda symbolFlag if not a data area then
|
|
and #isDataArea
|
|
bne lb1
|
|
ph4 sp Error(sp,8)
|
|
ph2 #8
|
|
jsr Error
|
|
bra lb2 else
|
|
lb1 ldx symbolData set the data area flag
|
|
short M
|
|
lda #1
|
|
sta dataAreas,X
|
|
long M
|
|
lb2 anop endif
|
|
|
|
lda [sp] skip the name in the obj segment
|
|
and #$00FF
|
|
sec
|
|
adc sp
|
|
sta sp
|
|
bcc lb3
|
|
inc sp+2
|
|
lb3 rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* Value - handle a value in an expression
|
|
*
|
|
* Inputs:
|
|
* sp - pointer to the value
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the next expression term
|
|
*
|
|
****************************************************************
|
|
*
|
|
Value private
|
|
|
|
add4 sp,#5
|
|
rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* WeakReference - handle a weak label reference in an expression
|
|
*
|
|
* Inputs:
|
|
* sp - pointer to the label name
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the next expression term
|
|
*
|
|
****************************************************************
|
|
*
|
|
WeakReference private
|
|
|
|
lda [sp]
|
|
and #$FF00
|
|
xba
|
|
inc A
|
|
sec
|
|
adc sp
|
|
sta sp
|
|
bcc lb1
|
|
inc sp+2
|
|
lb1 rts
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* ZExpr - evaluate a zero page expression
|
|
*
|
|
* Inputs:
|
|
* sp - pointer to the opcode
|
|
* pc - current program counter
|
|
*
|
|
* Outputs:
|
|
* sp - pointer to the next opcode
|
|
* pc - new program counter
|
|
*
|
|
****************************************************************
|
|
*
|
|
ZExpr private
|
|
using ExpCommon
|
|
using Common
|
|
using OutCommon
|
|
|
|
lda [sp] update the PC
|
|
xba
|
|
and #$00FF
|
|
sta expLength
|
|
lb1 add4 sp,#2 skip the op code and expression length
|
|
ph4 sp evaluate the expression
|
|
jsr Evaluate
|
|
sta expValue
|
|
stx expValue+2
|
|
ldx expLength make sure truncated bytes are 0
|
|
cpx #4
|
|
bge lb2
|
|
lb1a lda expValue,X
|
|
and #$00FF
|
|
beq lb1b
|
|
ph4 #0
|
|
ph2 #9
|
|
jsr Error
|
|
bra lb2
|
|
lb1b inx
|
|
cpx #4
|
|
blt lb1a
|
|
|
|
lb2 lda symbolRelocatable if the expression is relocatable then
|
|
beq lb3
|
|
ph4 #0 flag an error
|
|
ph2 #9
|
|
jsr Error
|
|
lb3 jsr PutValue write an expression value
|
|
brl SkipExpression skip the expression
|
|
end
|