Linker/pass2.asm
Stephen Heumann 8aa3c4e8c7 Give error about excessive alignment at the right time.
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.)
2021-03-03 22:53:57 -06:00

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