mirror of
https://github.com/byteworksinc/Linker.git
synced 2024-08-31 23:30:38 +00:00
1662 lines
27 KiB
NASM
1662 lines
27 KiB
NASM
keep obj/exp
|
|
mcopy exp.mac
|
|
****************************************************************
|
|
*
|
|
* Expression evaluation
|
|
*
|
|
* This module handles evaluation of expressions during pass
|
|
* 2.
|
|
*
|
|
****************************************************************
|
|
copy directPage
|
|
****************************************************************
|
|
*
|
|
* ExpCommon - global data for the expression module
|
|
*
|
|
****************************************************************
|
|
*
|
|
;
|
|
; Constants
|
|
;
|
|
maxTerm gequ 16 max # of STACKED terms in an expression
|
|
maxDepth gequ 8 max # of NESTED unresolved labels
|
|
|
|
ExpCommon data
|
|
;
|
|
; External value returned by CopyExpression
|
|
;
|
|
copiedExpression ds 2 was the expression resolved to a constant?
|
|
shiftCount ds 4 shift count (# bits to shift)
|
|
shiftFlag ds 2 is the expression shifted?
|
|
shiftValue ds 4 expression value before shift
|
|
symbolCount ds 2 count attribute
|
|
symbolLength ds 2 length attribute
|
|
symbolRelocatable ds 2 symbol relocatable flag
|
|
symbolType ds 2 type attribute
|
|
symbolValue ds 4 symbol value
|
|
symbolData ds 2 symbol data area number
|
|
symbolFlag ds 2 symbol flags
|
|
symbolFile ds 2 symbol file
|
|
expSegment ds 2 segment number for the expression
|
|
;
|
|
; Current expression information
|
|
;
|
|
expValue ds 4 expression value
|
|
expLength ds 2 expression length
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* CopyExpression - resolve or copy an expression
|
|
*
|
|
* Inputs:
|
|
* ep - pointer to the first opcode in the expression
|
|
*
|
|
* Outputs:
|
|
* X-A constant value or ptr to a safe copy of the expression
|
|
* copiedExpression -
|
|
* 1 -> the value returned is a copy of the expression
|
|
* 0 -> the value returned is a constant
|
|
*
|
|
****************************************************************
|
|
*
|
|
CopyExpression start
|
|
using ExpCommon
|
|
val equ 1 value of the expression
|
|
oep equ 5 original copy of ep
|
|
length equ 9 length of the expression, in bytes
|
|
done equ 13 done processing flag
|
|
sp equ 15 expression stack pointer
|
|
stack equ 17 expression stack
|
|
|
|
sub (4:ep),16+maxTerm*4
|
|
|
|
stz copiedExpression assume we can resolve to a constant
|
|
move4 ep,oep save a copy of the start of the expression
|
|
stz done not done, yet
|
|
stz sp nothing on the operand stack
|
|
|
|
lb1 lda [ep] loop over the expression, processing it
|
|
and #$00FF
|
|
asl A
|
|
tax
|
|
jsr (addr,X)
|
|
lda done
|
|
beq lb1
|
|
|
|
lda #9 if sp <> 4 then
|
|
ldx sp
|
|
cpx #4
|
|
jne TermError flag an expression syntax error
|
|
move4 stack,val set the value
|
|
lda copiedExpression if the expression is not constant then
|
|
beq lb4
|
|
sub2 ep,oep,length get some memory from the symbol table
|
|
ph2 length
|
|
jsr GetSymbolMemory
|
|
sta val
|
|
stx val+2
|
|
sta ep
|
|
stx ep+2
|
|
lda length X = # of words to copy
|
|
lsr A
|
|
tax
|
|
bcc lb2 if there are an odd # of bytes then
|
|
short M
|
|
lda [oep]
|
|
sta [ep]
|
|
long M
|
|
inc4 oep
|
|
inc4 ep
|
|
tax
|
|
beq lb4
|
|
lb2 ldy #0
|
|
lb3 lda [oep],Y
|
|
sta [ep],Y
|
|
iny
|
|
iny
|
|
dex
|
|
bne lb3
|
|
|
|
lb4 ret 4:val return the expression value
|
|
;
|
|
; Add:
|
|
;
|
|
Add anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
clc do the operation
|
|
lda stack-4,X
|
|
adc stack,X
|
|
sta stack-4,X
|
|
lda stack-2,X
|
|
adc stack+2,X
|
|
sta stack-2,X
|
|
rts
|
|
;
|
|
; And:
|
|
;
|
|
And anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-4,X do the operation
|
|
ora stack-2,X
|
|
beq and1
|
|
lda stack,X
|
|
ora stack+2,X
|
|
beq and1
|
|
|
|
lda #1 result is true
|
|
bra and2
|
|
|
|
and1 lda #0 result is false
|
|
and2 sta stack-4,X
|
|
lda #0
|
|
sta stack-2,X
|
|
rts
|
|
;
|
|
; BAnd:
|
|
;
|
|
BAnd anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-4,X do the operation
|
|
and stack,X
|
|
sta stack-4,X
|
|
lda stack-2,X
|
|
and stack+2,X
|
|
sta stack-2,X
|
|
rts
|
|
;
|
|
; BEor:
|
|
;
|
|
BEor anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-4,X do the operation
|
|
eor stack,X
|
|
sta stack-4,X
|
|
lda stack-2,X
|
|
eor stack+2,X
|
|
sta stack-2,X
|
|
rts
|
|
;
|
|
; BNot:
|
|
;
|
|
BNot anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check1 make sure there is at least 1 operand
|
|
lda stack-4,X do the operation
|
|
eor #$FFFF
|
|
sta stack-4,X
|
|
lda stack-2,X
|
|
eor #$FFFF
|
|
sta stack-2,X
|
|
rts
|
|
;
|
|
; BOr:
|
|
;
|
|
BOr anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-4,X do the operation
|
|
ora stack,X
|
|
sta stack-4,X
|
|
lda stack-2,X
|
|
ora stack+2,X
|
|
sta stack-2,X
|
|
rts
|
|
;
|
|
; Check1 - Makes sure there is at least 1 operand. Returns sp in X.
|
|
;
|
|
Check1 anop
|
|
|
|
ldx sp
|
|
beq check2a
|
|
rts
|
|
;
|
|
; Check2 - Makes sure there are at least 2 operands. Removes 1, returns
|
|
; new sp in X.
|
|
;
|
|
Check2 anop
|
|
|
|
lda sp
|
|
cmp #8
|
|
bge check21
|
|
check2a lda #9
|
|
jmp TermError
|
|
|
|
check21 sec
|
|
sbc #4
|
|
sta sp
|
|
tax
|
|
rts
|
|
;
|
|
; CheckStack - check for stack overflows
|
|
;
|
|
CheckStack anop
|
|
|
|
lda #9
|
|
ldx sp
|
|
cpx #maxTerm*4
|
|
jeq TermError
|
|
rts
|
|
;
|
|
; Div:
|
|
;
|
|
Div anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-2,X do the operation
|
|
pha
|
|
lda stack-4,X
|
|
pha
|
|
lda stack+2,X
|
|
pha
|
|
lda stack,X
|
|
pha
|
|
jsl ~Div4
|
|
ldx sp
|
|
pla
|
|
sta stack-4,X
|
|
pla
|
|
sta stack-2,X
|
|
pla
|
|
pla
|
|
rts
|
|
;
|
|
; Eor:
|
|
;
|
|
Eor anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-4,X do the operation
|
|
ora stack-2,X
|
|
bne eor1
|
|
lda stack,X
|
|
ora stack+2,X
|
|
bne eor2
|
|
bra eor3
|
|
|
|
eor1 lda stack,X
|
|
ora stack+2,X
|
|
bne eor3
|
|
|
|
eor2 lda #1 result is true
|
|
bra eor4
|
|
|
|
eor3 lda #0 result is false
|
|
eor4 sta stack-4,X
|
|
lda #0
|
|
sta stack-2,X
|
|
rts
|
|
;
|
|
; EndExp - end of the expression
|
|
;
|
|
EndExp anop
|
|
|
|
inc4 ep
|
|
inc done
|
|
rts
|
|
;
|
|
; EQ:
|
|
;
|
|
EQ anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-4,X do the operation
|
|
cmp stack,X
|
|
bne eq1
|
|
lda stack-2,X
|
|
cmp stack+2,X
|
|
bne eq1
|
|
|
|
lda #1 result is true
|
|
bra eq2
|
|
|
|
eq1 lda #0 result is false
|
|
eq2 ldx sp
|
|
sta stack-4,X
|
|
lda #0
|
|
sta stack-2,X
|
|
rts
|
|
;
|
|
; Invalid - illegal byte in the expression
|
|
;
|
|
Invalid anop
|
|
|
|
lda #8
|
|
jmp TermError
|
|
;
|
|
; LE:
|
|
;
|
|
LE anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-2,X do the operation
|
|
pha
|
|
lda stack-4,X
|
|
pha
|
|
lda stack+2,X
|
|
pha
|
|
lda stack,X
|
|
pha
|
|
jsl SCmp4
|
|
ble le1
|
|
|
|
lda #0 result is false
|
|
bra le2
|
|
|
|
le1 lda #1 result is true
|
|
le2 ldx sp
|
|
sta stack-4,X
|
|
lda #0
|
|
sta stack-2,X
|
|
rts
|
|
;
|
|
; LT:
|
|
;
|
|
LT anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-2,X do the operation
|
|
pha
|
|
lda stack-4,X
|
|
pha
|
|
lda stack+2,X
|
|
pha
|
|
lda stack,X
|
|
pha
|
|
jsl SCmp4
|
|
blt lt1
|
|
|
|
lda #0 result is false
|
|
bra lt2
|
|
|
|
lt1 lda #1 result is true
|
|
lt2 ldx sp
|
|
sta stack-4,X
|
|
lda #0
|
|
sta stack-2,X
|
|
rts
|
|
;
|
|
; GE:
|
|
;
|
|
GE anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-2,X do the operation
|
|
pha
|
|
lda stack-4,X
|
|
pha
|
|
lda stack+2,X
|
|
pha
|
|
lda stack,X
|
|
pha
|
|
jsl SCmp4
|
|
bge ge1
|
|
|
|
lda #0 result is false
|
|
bra ge2
|
|
|
|
ge1 lda #1 result is true
|
|
ge2 ldx sp
|
|
sta stack-4,X
|
|
lda #0
|
|
sta stack-2,X
|
|
rts
|
|
;
|
|
; GT:
|
|
;
|
|
GT anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-2,X do the operation
|
|
pha
|
|
lda stack-4,X
|
|
pha
|
|
lda stack+2,X
|
|
pha
|
|
lda stack,X
|
|
pha
|
|
jsl SCmp4
|
|
bgt gt1
|
|
|
|
lda #0 result is false
|
|
bra gt2
|
|
|
|
gt1 lda #1 result is true
|
|
gt2 ldx sp
|
|
sta stack-4,X
|
|
lda #0
|
|
sta stack-2,X
|
|
rts
|
|
;
|
|
; Mod:
|
|
;
|
|
Mod anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-2,X do the operation
|
|
pha
|
|
lda stack-4,X
|
|
pha
|
|
lda stack+2,X
|
|
pha
|
|
lda stack,X
|
|
pha
|
|
jsl ~Div4
|
|
pla
|
|
pla
|
|
ldx sp
|
|
pla
|
|
sta stack-4,X
|
|
pla
|
|
sta stack-2,X
|
|
rts
|
|
;
|
|
; Mul:
|
|
;
|
|
Mul anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-2,X do the operation
|
|
pha
|
|
lda stack-4,X
|
|
pha
|
|
lda stack+2,X
|
|
pha
|
|
lda stack,X
|
|
pha
|
|
jsl ~Mul4
|
|
ldx sp
|
|
pla
|
|
sta stack-4,X
|
|
pla
|
|
sta stack-2,X
|
|
rts
|
|
;
|
|
; NE:
|
|
;
|
|
NE anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-4,X do the operation
|
|
cmp stack,X
|
|
bne ne1
|
|
lda stack-2,X
|
|
cmp stack+2,X
|
|
bne ne1
|
|
|
|
lda #0 result is false
|
|
bra ne2
|
|
|
|
ne1 lda #1 result is true
|
|
ne2 ldx sp
|
|
sta stack-4,X
|
|
lda #0
|
|
sta stack-2,X
|
|
rts
|
|
;
|
|
; Not:
|
|
;
|
|
Not anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check1 make sure there are at least 2 operands
|
|
lda stack-4,X do the operation
|
|
ora stack-2,X
|
|
bne not1
|
|
|
|
lda #1 result is true
|
|
bra not2
|
|
|
|
not1 lda #0 result is false
|
|
not2 sta stack-4,X
|
|
lda #0
|
|
sta stack-2,X
|
|
rts
|
|
;
|
|
; Or:
|
|
;
|
|
Or anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-4,X do the operation
|
|
ora stack-2,X
|
|
bne or1
|
|
lda stack,X
|
|
ora stack+2,X
|
|
bne or1
|
|
|
|
lda #0 result is false
|
|
bra or2
|
|
|
|
or1 lda #1 result is true
|
|
or2 sta stack-4,X
|
|
lda #0
|
|
sta stack-2,X
|
|
rts
|
|
;
|
|
; PCounter - program counter
|
|
;
|
|
PCounter anop
|
|
|
|
lda #1 copiedExpression = true
|
|
sta copiedExpression
|
|
inc4 ep skip the op code
|
|
jsr CheckStack make sure there is room on the stack
|
|
add2 sp,#4 reserve space on the operand stack
|
|
rts
|
|
;
|
|
; Reference - a reference to a label
|
|
;
|
|
Reference anop
|
|
|
|
lda #1 copiedExpression = true
|
|
sta copiedExpression
|
|
jsr CheckStack make sure there is room on the stack
|
|
add2 sp,#4 reserve space on the operand stack
|
|
inc4 ep skip the op code
|
|
lda [ep] skip the name in the segment
|
|
and #$00FF
|
|
sec
|
|
adc ep
|
|
sta ep
|
|
bcc rf1
|
|
inc ep+2
|
|
rf1 rts
|
|
;
|
|
; SegDisp - disp from the start of the segment
|
|
;
|
|
SegDisp anop
|
|
|
|
lda #1 copiedExpression = true
|
|
sta copiedExpression
|
|
jsr CheckStack make sure there is room on the stack
|
|
add4 ep,#5 skip the op code and operand
|
|
add2 sp,#4 reserve space on the operand stack
|
|
rts
|
|
;
|
|
; Shift:
|
|
;
|
|
Shift anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
|
|
lda stack+2,X if shift is to the right then
|
|
bpl shift2
|
|
lda stack,X shift to the right
|
|
tay
|
|
shift1 lsr stack-2,X
|
|
ror stack-4,X
|
|
iny
|
|
bne shift1
|
|
rts return
|
|
|
|
shift2 lda stack,X shift to the left
|
|
tay
|
|
beq shift4
|
|
shift3 asl stack-4,X
|
|
rol stack-2,X
|
|
dey
|
|
bne shift3
|
|
shift4 rts
|
|
;
|
|
; Sub:
|
|
;
|
|
Sub anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
sec do the operation
|
|
lda stack-4,X
|
|
sbc stack,X
|
|
sta stack-4,X
|
|
lda stack-2,X
|
|
sbc stack+2,X
|
|
sta stack-2,X
|
|
rts
|
|
;
|
|
; UMinus:
|
|
;
|
|
UMinus anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check1 make sure there is at least 1 operand
|
|
sec do the operation
|
|
lda #0
|
|
sbc stack-4,X
|
|
sta stack-4,X
|
|
lda #0
|
|
sbc stack-2,X
|
|
sta stack-2,X
|
|
rts
|
|
;
|
|
; Value - constant value
|
|
;
|
|
Value anop
|
|
|
|
jsr CheckStack make sure there is room on the stack
|
|
ldy #1 place the value on the stack
|
|
ldx sp
|
|
lda [ep],Y
|
|
sta stack,X
|
|
ldy #3
|
|
lda [ep],Y
|
|
sta stack+2,X
|
|
add4 ep,#5 skip the op code and operand
|
|
add2 sp,#4 reserve space on the operand stack
|
|
rts
|
|
;
|
|
; Table of expression handling subroutines
|
|
;
|
|
addr dc a'EndExp' $00 End
|
|
dc a'Add' $01 +
|
|
dc a'Sub' $02 -
|
|
dc a'Mul' $03 *
|
|
dc a'Div' $04 div
|
|
dc a'Mod' $05 mod
|
|
dc a'UMinus' $06 unary -
|
|
dc a'Shift' $07 << or >>
|
|
dc a'And' $08 and
|
|
dc a'Or' $09 or
|
|
dc a'Eor' $0A eor
|
|
dc a'Not' $0B not
|
|
dc a'LE' $0C <=
|
|
dc a'GE' $0D >=
|
|
dc a'NE' $0E <>
|
|
dc a'LT' $0F <
|
|
dc a'GT' $10 >
|
|
dc a'EQ' $11 =
|
|
dc a'BAnd' $12 &
|
|
dc a'BOr' $13 |
|
|
dc a'BEor' $14 bitwise eor
|
|
dc a'BNot' $15 bitwise not
|
|
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'PCounter' $80 program counter
|
|
dc a'Value' $81 absolute value
|
|
dc a'Reference' $82 weak label reference
|
|
dc a'Reference' $83 strong label reference
|
|
dc a'Reference' $84 length attribute
|
|
dc a'Reference' $85 type attribute
|
|
dc a'Reference' $86 count attribute
|
|
dc a'SegDisp' $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
|
|
|
|
****************************************************************
|
|
*
|
|
* Evaluate - evaluate an expression
|
|
*
|
|
* Inputs:
|
|
* ep - pointer to the expression
|
|
*
|
|
* Outputs:
|
|
* shiftFlag - 1 if the value is shifted, else 0
|
|
* shiftValue - expression result before shifting
|
|
* shiftCount - shift counter
|
|
* returns the value of the expression
|
|
*
|
|
****************************************************************
|
|
*
|
|
Evaluate start
|
|
using Common
|
|
using ExpCommon
|
|
done equ 1 done processing flag
|
|
sp equ 3 expression stack pointer
|
|
stack equ 7 expression stack
|
|
|
|
sub (4:ep),6+maxTerm*5
|
|
|
|
tsc check for a stack overflow
|
|
sec
|
|
sbc #$0100
|
|
cmp dpReg
|
|
bge lb0
|
|
lda #9
|
|
jmp TermError
|
|
|
|
lb0 stz shiftFlag no shift has occurred
|
|
stz shiftCount
|
|
stz shiftCount+2
|
|
stz done not done, yet
|
|
stz sp nothing on the operand stack
|
|
stz expSegment no segment-dependent variables, yet
|
|
|
|
lb1 lda [ep] loop over the expression, processing it
|
|
and #$00FF
|
|
asl A
|
|
tax
|
|
jsr (addr,X)
|
|
lda done
|
|
beq lb1
|
|
|
|
lda #9 if sp <> 4 then
|
|
ldx sp
|
|
cpx #5
|
|
jne TermError flag an expression syntax error
|
|
lda stack+4 set the relocatable flag
|
|
and #$00FF
|
|
sta symbolRelocatable
|
|
|
|
ret 4:stack return the expression value
|
|
;
|
|
; Add:
|
|
;
|
|
Add anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
clc do the operation
|
|
lda stack-5,X
|
|
adc stack,X
|
|
sta stack-5,X
|
|
lda stack-3,X
|
|
adc stack+2,X
|
|
sta stack-3,X
|
|
|
|
lda stack-1,X if both operands are relative then
|
|
and stack+4,X
|
|
and #$00FF
|
|
beq ad1
|
|
ph4 #0 Error(NULL,16)
|
|
ph2 #16
|
|
jsr Error
|
|
rts
|
|
|
|
ad1 lda stack-1,X if either operand is relative and a
|
|
ora stack+4,X shift has occurred then
|
|
and #$00FF
|
|
beq ad3
|
|
lda shiftFlag
|
|
beq ad2
|
|
ph4 #0 Error(NULL,16)
|
|
ph2 #16
|
|
jsr Error
|
|
rts
|
|
|
|
ad2 lda #1 one operand is relative, so the result
|
|
sta stack-1,X is also relative
|
|
ad3 rts
|
|
;
|
|
; And:
|
|
;
|
|
And anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-5,X do the operation
|
|
ora stack-3,X
|
|
beq and1
|
|
lda stack,X
|
|
ora stack+2,X
|
|
beq and1
|
|
|
|
lda #1 result is true
|
|
bra and2
|
|
|
|
and1 lda #0 result is false
|
|
and2 sta stack-5,X
|
|
lda #0
|
|
sta stack-3,X
|
|
jsr NoRelocate2 make sure the operands are not relocatable
|
|
rts
|
|
;
|
|
; AttrCount - get the count attribute of a label
|
|
;
|
|
AttrCount anop
|
|
|
|
inc4 ep skip the op code
|
|
ph4 ep find the symbol value
|
|
ph2 #0
|
|
jsr GetSymbolValue
|
|
jsr CheckStack make sure there is room on the stack
|
|
lda symbolCount save the value
|
|
sta stack,X
|
|
lda #0
|
|
sta stack+2,X
|
|
short M set the relocation flag
|
|
lda #0
|
|
sta stack+4,X
|
|
long M
|
|
add2 sp,#5 reserve space on the operand stack
|
|
lda [ep] skip the name in the segment
|
|
and #$00FF
|
|
sec
|
|
adc ep
|
|
sta ep
|
|
bcc ac1
|
|
inc ep+2
|
|
ac1 rts
|
|
;
|
|
; AttrLength - get the length attribute of a label
|
|
;
|
|
AttrLength anop
|
|
|
|
inc4 ep skip the op code
|
|
ph4 ep find the symbol value
|
|
ph2 #1
|
|
jsr GetSymbolValue
|
|
jsr CheckStack make sure there is room on the stack
|
|
lda symbolLength save the value
|
|
sta stack,X
|
|
lda #0
|
|
sta stack+2,X
|
|
short M set the relocation flag
|
|
lda #0
|
|
sta stack+4,X
|
|
long M
|
|
add2 sp,#5 reserve space on the operand stack
|
|
lda [ep] skip the name in the segment
|
|
and #$00FF
|
|
sec
|
|
adc ep
|
|
sta ep
|
|
bcc al1
|
|
inc ep+2
|
|
al1 rts
|
|
;
|
|
; AttrType - get the type attribute of a label
|
|
;
|
|
AttrType anop
|
|
|
|
inc4 ep skip the op code
|
|
ph4 ep find the symbol value
|
|
ph2 #1
|
|
jsr GetSymbolValue
|
|
jsr CheckStack make sure there is room on the stack
|
|
lda symbolType save the value
|
|
sta stack,X
|
|
lda #0
|
|
sta stack+2,X
|
|
short M set the relocation flag
|
|
lda #0
|
|
sta stack+4,X
|
|
long M
|
|
add2 sp,#5 reserve space on the operand stack
|
|
lda [ep] skip the name in the segment
|
|
and #$00FF
|
|
sec
|
|
adc ep
|
|
sta ep
|
|
bcc at1
|
|
inc ep+2
|
|
at1 rts
|
|
;
|
|
; BAnd:
|
|
;
|
|
BAnd anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-5,X do the operation
|
|
and stack,X
|
|
sta stack-5,X
|
|
lda stack-3,X
|
|
and stack+2,X
|
|
sta stack-3,X
|
|
jsr NoRelocate2 make sure the operands are not relocatable
|
|
rts
|
|
;
|
|
; BEor:
|
|
;
|
|
BEor anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-5,X do the operation
|
|
eor stack,X
|
|
sta stack-5,X
|
|
lda stack-3,X
|
|
eor stack+2,X
|
|
sta stack-3,X
|
|
jsr NoRelocate2 make sure the operands are not relocatable
|
|
rts
|
|
;
|
|
; BNot:
|
|
;
|
|
BNot anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check1 make sure there is at least 1 operand
|
|
lda stack-5,X do the operation
|
|
eor #$FFFF
|
|
sta stack-5,X
|
|
lda stack-3,X
|
|
eor #$FFFF
|
|
sta stack-3,X
|
|
jsr NoRelocate1 make sure the operand is not relocatable
|
|
rts
|
|
;
|
|
; BOr:
|
|
;
|
|
BOr anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-5,X do the operation
|
|
ora stack,X
|
|
sta stack-5,X
|
|
lda stack-3,X
|
|
ora stack+2,X
|
|
sta stack-3,X
|
|
jsr NoRelocate2 make sure the operands are not relocatable
|
|
rts
|
|
;
|
|
; Check1 - Makes sure there is at least 1 operand. Returns sp in X.
|
|
;
|
|
Check1 anop
|
|
|
|
ldx sp
|
|
beq check2a
|
|
rts
|
|
;
|
|
; Check2 - Makes sure there are at least 2 operands. Removes 1, returns
|
|
; new sp in X.
|
|
;
|
|
Check2 anop
|
|
|
|
lda sp
|
|
cmp #10
|
|
bge check21
|
|
check2a lda #9
|
|
jmp TermError
|
|
|
|
check21 sec
|
|
sbc #5
|
|
sta sp
|
|
tax
|
|
rts
|
|
;
|
|
; CheckStack - check for stack overflows
|
|
;
|
|
CheckStack anop
|
|
|
|
lda #9
|
|
ldx sp
|
|
cpx #maxTerm*5
|
|
jeq TermError
|
|
rts
|
|
;
|
|
; Div:
|
|
;
|
|
Div anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-3,X do the operation
|
|
pha
|
|
lda stack-5,X
|
|
pha
|
|
lda stack+2,X
|
|
pha
|
|
lda stack,X
|
|
pha
|
|
jsl ~Div4
|
|
ldx sp
|
|
pla
|
|
sta stack-5,X
|
|
pla
|
|
sta stack-3,X
|
|
pla
|
|
pla
|
|
jsr NoRelocate2 make sure the operands are not relocatable
|
|
rts
|
|
;
|
|
; Eor:
|
|
;
|
|
Eor anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-5,X do the operation
|
|
ora stack-3,X
|
|
bne eor1
|
|
lda stack,X
|
|
ora stack+2,X
|
|
bne eor2
|
|
bra eor3
|
|
|
|
eor1 lda stack,X
|
|
ora stack+2,X
|
|
bne eor3
|
|
|
|
eor2 lda #1 result is true
|
|
bra eor4
|
|
|
|
eor3 lda #0 result is false
|
|
eor4 sta stack-5,X
|
|
lda #0
|
|
sta stack-3,X
|
|
jsr NoRelocate2 make sure the operands are not relocatable
|
|
rts
|
|
;
|
|
; EndExp - end of the expression
|
|
;
|
|
EndExp anop
|
|
|
|
inc4 ep
|
|
inc done
|
|
rts
|
|
;
|
|
; EQ:
|
|
;
|
|
EQ anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-5,X do the operation
|
|
cmp stack,X
|
|
bne eq1
|
|
lda stack-3,X
|
|
cmp stack+2,X
|
|
bne eq1
|
|
|
|
lda #1 result is true
|
|
bra eq2
|
|
|
|
eq1 lda #0 result is false
|
|
eq2 ldx sp
|
|
sta stack-5,X
|
|
lda #0
|
|
sta stack-3,X
|
|
jsr NoRelocate2 make sure the operands are not relocatable
|
|
rts
|
|
;
|
|
; Invalid - illegal byte in the expression
|
|
;
|
|
Invalid anop
|
|
lda #8
|
|
jmp TermError
|
|
;
|
|
; LE:
|
|
;
|
|
LE anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-3,X do the operation
|
|
pha
|
|
lda stack-5,X
|
|
pha
|
|
lda stack+2,X
|
|
pha
|
|
lda stack,X
|
|
pha
|
|
jsl SCmp4
|
|
ble le1
|
|
|
|
lda #0 result is false
|
|
bra le2
|
|
|
|
le1 lda #1 result is true
|
|
le2 ldx sp
|
|
sta stack-5,X
|
|
lda #0
|
|
sta stack-3,X
|
|
jsr NoRelocate2 make sure the operands are not relocatable
|
|
rts
|
|
;
|
|
; LT:
|
|
;
|
|
LT anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-3,X do the operation
|
|
pha
|
|
lda stack-5,X
|
|
pha
|
|
lda stack+2,X
|
|
pha
|
|
lda stack,X
|
|
pha
|
|
jsl SCmp4
|
|
blt lt1
|
|
|
|
lda #0 result is false
|
|
bra lt2
|
|
|
|
lt1 lda #1 result is true
|
|
lt2 ldx sp
|
|
sta stack-5,X
|
|
lda #0
|
|
sta stack-3,X
|
|
jsr NoRelocate2 make sure the operands are not relocatable
|
|
rts
|
|
;
|
|
; GE:
|
|
;
|
|
GE anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-3,X do the operation
|
|
pha
|
|
lda stack-5,X
|
|
pha
|
|
lda stack+2,X
|
|
pha
|
|
lda stack,X
|
|
pha
|
|
jsl SCmp4
|
|
bge ge1
|
|
|
|
lda #0 result is false
|
|
bra ge2
|
|
|
|
ge1 lda #1 result is true
|
|
ge2 ldx sp
|
|
sta stack-5,X
|
|
lda #0
|
|
sta stack-3,X
|
|
jsr NoRelocate2 make sure the operands are not relocatable
|
|
rts
|
|
;
|
|
; GT:
|
|
;
|
|
GT anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-3,X do the operation
|
|
pha
|
|
lda stack-5,X
|
|
pha
|
|
lda stack+2,X
|
|
pha
|
|
lda stack,X
|
|
pha
|
|
jsl SCmp4
|
|
bgt gt1
|
|
|
|
lda #0 result is false
|
|
bra gt2
|
|
|
|
gt1 lda #1 result is true
|
|
gt2 ldx sp
|
|
sta stack-5,X
|
|
lda #0
|
|
sta stack-3,X
|
|
jsr NoRelocate2 make sure the operands are not relocatable
|
|
rts
|
|
;
|
|
; Mod:
|
|
;
|
|
Mod anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-3,X do the operation
|
|
pha
|
|
lda stack-5,X
|
|
pha
|
|
lda stack+2,X
|
|
pha
|
|
lda stack,X
|
|
pha
|
|
jsl ~Div4
|
|
pla
|
|
pla
|
|
ldx sp
|
|
pla
|
|
sta stack-5,X
|
|
pla
|
|
sta stack-3,X
|
|
jsr NoRelocate2 make sure the operands are not relocatable
|
|
rts
|
|
;
|
|
; Mul:
|
|
;
|
|
Mul anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-3,X do the operation
|
|
pha
|
|
lda stack-5,X
|
|
pha
|
|
lda stack+2,X
|
|
pha
|
|
lda stack,X
|
|
pha
|
|
jsl ~Mul4
|
|
ldx sp
|
|
pla
|
|
sta stack-5,X
|
|
pla
|
|
sta stack-3,X
|
|
jsr NoRelocate2 make sure the operands are not relocatable
|
|
rts
|
|
;
|
|
; NE:
|
|
;
|
|
NE anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-5,X do the operation
|
|
cmp stack,X
|
|
bne ne1
|
|
lda stack-3,X
|
|
cmp stack+2,X
|
|
bne ne1
|
|
|
|
lda #0 result is false
|
|
bra ne2
|
|
|
|
ne1 lda #1 result is true
|
|
ne2 ldx sp
|
|
sta stack-5,X
|
|
lda #0
|
|
sta stack-3,X
|
|
jsr NoRelocate2 make sure the operands are not relocatable
|
|
rts
|
|
;
|
|
; NoRelocate1 - make sure the top operand is not relocatable
|
|
;
|
|
NoRelocate1 anop
|
|
|
|
lda stack-1,X
|
|
bra nr0
|
|
;
|
|
; NoRelocate2 - make sure the top two operands are not relocatable
|
|
;
|
|
NoRelocate2 anop
|
|
|
|
lda stack-1,X
|
|
ora stack+4,X
|
|
nr0 and #$00FF
|
|
beq nr1
|
|
ph4 #0
|
|
ph2 #16
|
|
jsr Error
|
|
nr1 rts
|
|
;
|
|
; Not:
|
|
;
|
|
Not anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check1 make sure there are at least 2 operands
|
|
lda stack-5,X do the operation
|
|
ora stack-3,X
|
|
bne not1
|
|
|
|
lda #1 result is true
|
|
bra not2
|
|
|
|
not1 lda #0 result is false
|
|
not2 sta stack-5,X
|
|
lda #0
|
|
sta stack-3,X
|
|
jsr NoRelocate1 make sure the operand is not relocatable
|
|
rts
|
|
;
|
|
; Or:
|
|
;
|
|
Or anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
lda stack-5,X do the operation
|
|
ora stack-3,X
|
|
bne or1
|
|
lda stack,X
|
|
ora stack+2,X
|
|
bne or1
|
|
|
|
lda #0 result is false
|
|
bra or2
|
|
|
|
or1 lda #1 result is true
|
|
or2 sta stack-5,X
|
|
lda #0
|
|
sta stack-3,X
|
|
jsr NoRelocate2 make sure the operands are not relocatable
|
|
rts
|
|
;
|
|
; PCounter - program counter
|
|
;
|
|
PCounter anop
|
|
|
|
inc4 ep skip the op code
|
|
ldx dpReg get the program counter
|
|
lda >pc+2,X
|
|
pha
|
|
lda >pc,X
|
|
pha
|
|
jsr CheckStack make sure there is room on the stack
|
|
pla save the program counter
|
|
sta stack,X
|
|
pla
|
|
sta stack+2,X
|
|
short M value is relocatable
|
|
lda #1
|
|
sta stack+4,X
|
|
long M
|
|
add2 sp,#5 reserve space on the operand stack
|
|
rts
|
|
;
|
|
; Reference - a reference to a label
|
|
;
|
|
Reference anop
|
|
|
|
inc4 ep skip the op code
|
|
ph4 ep find the symbol value
|
|
ph2 #1
|
|
jsr GetSymbolValue
|
|
jsr CheckStack make sure there is room on the stack
|
|
lda symbolValue save the value
|
|
sta stack,X
|
|
lda symbolValue+2
|
|
sta stack+2,X
|
|
short M set the relocation flag
|
|
lda symbolRelocatable
|
|
sta stack+4,X
|
|
long M
|
|
add2 sp,#5 reserve space on the operand stack
|
|
lda [ep] skip the name in the segment
|
|
and #$00FF
|
|
sec
|
|
adc ep
|
|
sta ep
|
|
bcc rf1
|
|
inc ep+2
|
|
rf1 rts
|
|
;
|
|
; SegDisp - disp from the start of the segment
|
|
;
|
|
SegDisp anop
|
|
|
|
jsr CheckStack make sure there is room on the stack
|
|
clc save the value + startpc
|
|
lda startpc
|
|
ldy #1
|
|
adc [ep],Y
|
|
sta stack,X
|
|
lda startpc+2
|
|
iny
|
|
iny
|
|
adc [ep],Y
|
|
sta stack+2,X
|
|
short M value is relocatable
|
|
lda #1
|
|
sta stack+4,X
|
|
long M
|
|
add4 ep,#5 skip the op code and operand
|
|
add2 sp,#5 reserve space on the operand stack
|
|
rts
|
|
;
|
|
; Shift:
|
|
;
|
|
Shift anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
|
|
lda shiftFlag a shift can only be done 1 time
|
|
beq shift0
|
|
phx
|
|
ph4 #0
|
|
ph2 #2
|
|
jsr Error
|
|
plx
|
|
stz shiftFlag
|
|
shift0 inc shiftFlag
|
|
|
|
lda stack,X save the shift count
|
|
sta shiftCount
|
|
lda stack+2,X
|
|
sta shiftCount+2
|
|
bmi sh2 restrict it to a reasonable range
|
|
bne sh1
|
|
lda shiftCount
|
|
cmp #32
|
|
blt sh4
|
|
sh1 lla shiftCount,32
|
|
bra sh4
|
|
sh2 inc A
|
|
bne sh3
|
|
lda shiftCount
|
|
cmp #-32
|
|
bge sh4
|
|
sh3 lla shiftCount,-32
|
|
|
|
sh4 lda stack-5,X save the shifted value
|
|
sta shiftValue
|
|
lda stack-3,X
|
|
sta shiftValue+2
|
|
|
|
lda stack+2,X if shift is to the right then
|
|
bpl shift2
|
|
lda stack,X shift to the right
|
|
tay
|
|
shift1 lsr stack-3,X
|
|
ror stack-5,X
|
|
iny
|
|
bne shift1
|
|
rts return
|
|
|
|
shift2 lda stack,X shift to the left
|
|
tay
|
|
beq shift4
|
|
shift3 asl stack-5,X
|
|
rol stack-3,X
|
|
dey
|
|
bne shift3
|
|
shift4 rts
|
|
;
|
|
; Sub:
|
|
;
|
|
Sub anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check2 make sure there are at least 2 operands
|
|
sec do the operation
|
|
lda stack-5,X
|
|
sbc stack,X
|
|
sta stack-5,X
|
|
lda stack-3,X
|
|
sbc stack+2,X
|
|
sta stack-3,X
|
|
|
|
lda stack-1,X if both operands are relative then
|
|
and stack+4,X
|
|
and #$00FF
|
|
beq su1
|
|
lda #0 result is a constant
|
|
sta stack-1,X
|
|
rts
|
|
|
|
su1 lda stack-1,X if either operand is relative and a
|
|
ora stack+4,X shift has occurred then
|
|
and #$00FF
|
|
beq su3
|
|
lda shiftFlag
|
|
beq su2
|
|
ph4 #0 Error(NULL,16)
|
|
ph2 #16
|
|
jsr Error
|
|
rts
|
|
|
|
su2 lda #1 one operand is relative, so the result
|
|
sta stack-1,X is also relative
|
|
su3 rts
|
|
;
|
|
; UMinus:
|
|
;
|
|
UMinus anop
|
|
|
|
inc4 ep update ep
|
|
jsr Check1 make sure there is at least 1 operand
|
|
sec do the operation
|
|
lda #0
|
|
sbc stack-5,X
|
|
sta stack-5,X
|
|
lda #0
|
|
sbc stack-3,X
|
|
sta stack-3,X
|
|
jsr NoRelocate1 make sure the operand is not relocatable
|
|
rts
|
|
;
|
|
; Value - constant value
|
|
;
|
|
Value anop
|
|
|
|
jsr CheckStack make sure there is room on the stack
|
|
ldy #1 place the value on the stack
|
|
ldx sp
|
|
lda [ep],Y
|
|
sta stack,X
|
|
ldy #3
|
|
lda [ep],Y
|
|
sta stack+2,X
|
|
short M value is not relocatable
|
|
lda #0
|
|
sta stack+4,X
|
|
long M
|
|
add4 ep,#5 skip the op code and operand
|
|
add2 sp,#5 reserve space on the operand stack
|
|
rts
|
|
;
|
|
; Weak - weak reference to a label
|
|
;
|
|
Weak anop
|
|
|
|
inc4 ep skip the op code
|
|
ph4 ep find the symbol value
|
|
ph2 #0
|
|
jsr GetSymbolValue
|
|
jsr CheckStack make sure there is room on the stack
|
|
lda symbolValue save the value
|
|
sta stack,X
|
|
lda symbolValue+2
|
|
sta stack+2,X
|
|
short M set the relocation flag
|
|
lda symbolRelocatable
|
|
sta stack+4,X
|
|
long M
|
|
add2 sp,#5 reserve space on the operand stack
|
|
lda [ep] skip the name in the segment
|
|
and #$00FF
|
|
sec
|
|
adc ep
|
|
sta ep
|
|
bcc wk1
|
|
inc ep+2
|
|
wk1 rts
|
|
;
|
|
; Table of expression handling subroutines
|
|
;
|
|
addr dc a'EndExp' $00 End
|
|
dc a'Add' $01 +
|
|
dc a'Sub' $02 -
|
|
dc a'Mul' $03 *
|
|
dc a'Div' $04 div
|
|
dc a'Mod' $05 mod
|
|
dc a'UMinus' $06 unary -
|
|
dc a'Shift' $07 << or >>
|
|
dc a'And' $08 and
|
|
dc a'Or' $09 or
|
|
dc a'Eor' $0A eor
|
|
dc a'Not' $0B not
|
|
dc a'LE' $0C <=
|
|
dc a'GE' $0D >=
|
|
dc a'NE' $0E <>
|
|
dc a'LT' $0F <
|
|
dc a'GT' $10 >
|
|
dc a'EQ' $11 =
|
|
dc a'BAnd' $12 &
|
|
dc a'BOr' $13 |
|
|
dc a'BEor' $14 bitwise eor
|
|
dc a'BNot' $15 bitwise not
|
|
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'PCounter' $80 program counter
|
|
dc a'Value' $81 absolute value
|
|
dc a'Weak' $82 weak label reference
|
|
dc a'Reference' $83 strong label reference
|
|
dc a'AttrLength' $84 length attribute
|
|
dc a'AttrType' $85 type attribute
|
|
dc a'AttrCount' $86 count attribute
|
|
dc a'SegDisp' $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
|
|
ret
|
|
end
|
|
|
|
****************************************************************
|
|
*
|
|
* SCmp4 - Four byte signed integer compare
|
|
*
|
|
* Inputs:
|
|
* 7,S - first argument
|
|
* 3,S - second argument
|
|
*
|
|
* Outputs:
|
|
* C - set if 7,S >= 3,S, else clear
|
|
* Z - set if 7,S = 3,S, else clear
|
|
*
|
|
****************************************************************
|
|
*
|
|
SCmp4 private
|
|
|
|
lda 9,S branch if both numbers have the same
|
|
eor 5,S sign
|
|
bpl cp1
|
|
lda 5,S do a comparison of oppositely signed
|
|
cmp 9,S numbers
|
|
rts
|
|
|
|
cp1 lda 9,S do a comparison of numbers with the
|
|
cmp 5,S same sign
|
|
bne cp2
|
|
lda 7,S
|
|
cmp 3,S
|
|
cp2 rts
|
|
end
|