Linker/pass1.asm
2017-10-02 09:35:05 -04:00

874 lines
16 KiB
NASM

keep obj/pass1
mcopy pass1.mac
****************************************************************
*
* Pass 1
*
* This module contains the subroutines used to do pass 1
* processing of the input 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
ldy #1 get the alignment factor
lda [sp],Y
sta r0
iny
iny
lda [sp],Y
sta r2
add4 sp,#5
jsr PrepareAlign do pass 1 prep for the align
rts
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]
and #$00FF
tax
clc
adc pc
sta pc
bcc lb1
inc pc+2
lb1 txa
sec
adc sp
sta sp
bcc lb2
inc sp+2
lb2 rts
end
****************************************************************
*
* DefineSegment - put the segment in the symbol table
*
* Inputs:
* segName - pointer to the segment name
* segType - segment type
* pc - current pc
* segEntry - disp to segment entry point
*
****************************************************************
*
DefineSegment private
using Common
ph4 segName push the symbol name ptr
ph2 #0 length attribute is 0
ph2 #'N' push the type attribute
lda segType push the private flag
and #$4000
beq lb1
lda #1
lb1 pha
ph2 #1 the symbol is global
ph2 #0 the symbol is not an expression
clc push the location
lda pc
adc segEntry
tax
lda pc+2
adc segEntry+2
pha
phx
lda segType push the data area flag
and #$007F
cmp #1
beq lb2
ph2 #0
bra lb3
lb2 ph2 #1
lb3 ph2 #1 push the segment flag
jsr Define define the symbol
rts
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
using OutCommon
ldy #1 get the value and skip the record
lda [sp],Y
sta r0
ldy #3
lda [sp],Y
sta r2+2
add4 sp,#5
sub4 r0,loadOrg get the disp from the segment start
cmpl pc,r0
bge lb1 if the disp is greater than the pc then
move4 r0,pc update the pc
lb1 anop
rts
end
****************************************************************
*
* DoPass1 - Do pass 1 processing
*
* Outputs:
* C - set if an error occurred
*
****************************************************************
*
DoPass1 start
using Common
;
; Write the pass header
;
lda #1 pass = 1
sta pass
lda list if list then
beq wp1
puts #'Segment:',cr=t print the general header
putcr
bra wp2 else if progress then
wp1 lda progress
beq wp2
puts #'Pass 1: ' print the dot header
wp2 anop
;
; Initialize pass dependent variables
;
jsr InitPass
;
; Process segments until there are no more
;
ps1 jsr NextSegment get the next segment
bcc rt1 branch if there are no more
jsr DefineSegment put the segment in the symbol table
jsr ListSeg list the segname start info
jsr DoSegment process this segment
add4 pc,segSpace add in the reserved space (if any)
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'Strong' $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'Expr' $EC ZExpr
dc a'Expr' $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'Expr' $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
inc4 sp
ldy #2
clc
lda [sp]
adc pc
sta pc
lda [sp],Y
adc pc+2
sta pc+2
add4 sp,#4
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 or 1 then
cmp #2
beq lb2
lda [sp] push the length byte
and #$00FF
pha
inc4 sp ++sp
bra lb3 else
lb2 lda [sp] push the length word
pha
add4 sp,#2 sp += 2
lb3 anop endif
lda [sp] push the type attribute
and #$00FF
pha
lda [sp] push the private flag
and #$FF00
xba
pha
add4 sp,#2 sp += 2 {skip the attributes}
ph2 #0 the symbol is local
ph2 #1 the symbol is an expression
ph4 sp push the address of the expression
ph2 #0 push the data area flag
ph2 #0 push the segment flag
jsr Define 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
lda [sp] update the PC
xba
and #$00FF
clc
adc pc
sta pc
bcc lb1
inc pc+2
lb1 add4 sp,#2 skip the op code and expression length
brl SkipExpression skip the expression
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 ro 1 then
cmp #2
beq lb2
lda [sp] push the length byte
and #$00FF
pha
inc4 sp ++sp
bra lb3 else
lb2 lda [sp] push the length word
pha
add4 sp,#2 sp += 2
lb3 anop endif
lda [sp] push the type attribute
and #$00FF
pha
lda [sp] push the private flag
and #$FF00
xba
pha
add4 sp,#2 sp += 2 {skip the attributes}
ph2 #1 the symbol is global
ph2 #1 the symbol is an expression
ph4 sp push the address of the expression
ph2 #0 push the data area flag
ph2 #0 push the segment flag
jsr Define 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
lda [sp] push the length byte
and #$00FF
pha
inc4 sp ++sp
bra lb3 else
lb2 lda [sp] push the length word
pha
add4 sp,#2 sp += 2
lb3 anop endif
lda [sp] push the type attribute
and #$00FF
pha
lda [sp] push the private flag
and #$FF00
xba
pha
add4 sp,#2 sp += 2 {skip the attributes}
ph2 #1 the symbol is global
ph2 #0 the symbol is not an expression
ph4 pc push the current pc
ph2 #0 push the data area flag
ph2 #0 push the segment flag
jsr Define 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
inc4 sp
ldy #2
lda [sp]
sta r0
lda [sp],Y
sta r0+2
add4 sp,r0
add4 sp,#4
add4 pc,r0
rts
end
****************************************************************
*
* ListSeg - list the segment start info
*
* Inputs:
* list - list info flag
*
****************************************************************
*
ListSeg private
using Common
lda list
bne lb1
lda progress
beq lb1
putc #'.'
lb1 jsr CheckForPause
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
lda [sp] push the length byte
and #$00FF
pha
inc4 sp ++sp
bra lb3 else
lb2 lda [sp] push the length word
pha
add4 sp,#2 sp += 2
lb3 anop endif
lda [sp] push the type attribute
and #$00FF
pha
lda [sp] push the private flag
and #$FF00
xba
pha
add4 sp,#2 sp += 2 {skip the attributes}
ph2 #0 the symbol is local
ph2 #0 the symbol is not an expression
ph4 pc push the current pc
ph2 #0 push the data area flag
ph2 #0 push the segment flag
jsr Define 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
****************************************************************
*
* PrepareAlign - do pass 1 prep for an align on pass 2
*
* Inputs:
* r0 - alignmanr factor
* pc - program counter
*
* Outputs:
* pc - program counter
*
****************************************************************
*
PrepareAlign start
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 pc,r8 add this to the pc
bra lb1 check the next bit
lb5 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
lda [sp] update the PC
xba
and #$00FF
clc
adc pc
sta pc
bcc lb1
inc pc+2
lb1 add4 sp,#6 skip the op code, length and offset
brl SkipExpression skip the expression
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 - Note that we are using a data area
*
* Inputs:
* sp - pointer to the opcode
*
* Outputs:
* sp - pointer to the next opcode
*
****************************************************************
*
Strong private
inc4 sp skip the op code
jsr Reference make a reference to the name
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 Reference 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
****************************************************************
*
* 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