Was using up too many S registers, so moved internal functions to use new registers I0 - I7, added IEEE rounding to MUL and DIV, refactored to reduce size, and trimmed trailing spaces.

This commit is contained in:
Russell-S-Harper 2018-08-21 09:14:16 -04:00
parent 6dc8517120
commit 8bbb5016cd
10 changed files with 440 additions and 475 deletions

View File

@ -10,5 +10,5 @@ page6.obj: rom.h macros.h page6.src
cpp -P page6.src | $(XAPP) > page6.asm
xa -M page6.asm -l page6.lbl -o page6.obj
clean:
clean:
rm -f page6.asm common.obj page6.obj common.lbl page6.lbl system.obj

View File

@ -43,7 +43,7 @@ _3 TAX ; save operand for later
ASL ; shift to get offset to register
ASL
TAX ; back to index
RTS ; "return" to routine
RTS ; "return" to routine
_4 TXA ; get operand
ASL ; shift to get offset to 0X instructions
TAY
@ -52,7 +52,7 @@ _4 TXA ; get operand
LDA FN_0X,Y ; push low address
PHA
TXA ; restore operand
RTS ; "return" to routine
RTS ; "return" to routine
_5 TXA ; get operand
AND #$F ; mask to get index
ASL ; shift to get offset to FX instructions
@ -158,15 +158,15 @@ _1 DEY ; transfer four bytes over
.)
_EXC .( ; EXC r 4r Rr <-> RS - exchange Rr with stack
LDY _RSI ; RS to RD
LDY _RSI ; RS to I0
LDA _RS-1,Y
STA _RD+3
STA _I0+3
LDA _RS-2,Y
STA _RD+2
STA _I0+2
LDA _RS-3,Y
STA _RD+1
STA _I0+1
LDA _RS-4,Y
STA _RD
STA _I0
LDA _R0,X ; copy Rr to RS
STA _RS-4,Y
LDA _R0+1,X
@ -175,70 +175,70 @@ _EXC .( ; EXC r 4r Rr <-> RS - exchange Rr with stack
STA _RS-2,Y
LDA _R0+3,X
STA _RS-1,Y
LDA _RD ; copy RD to Rr
LDA _I0 ; copy I0 to Rr
STA _R0,X
LDA _RD+1
LDA _I0+1
STA _R0+1,X
LDA _RD+2
LDA _I0+2
STA _R0+2,X
LDA _RD+3
LDA _I0+3
STA _R0+3,X
RTS
.)
_ADDRD .( ; add RD to register indexed by X
_ADDI0X .( ; add I0 to register indexed by X
LDA _R0+3,X
AND #_MSK_O ; check for existing overflow condition
BEQ _4
BEQ _1
EOR #_MSK_O
BNE _3 ; existing overflow, skip decrement operation
_4 CLC ; adding RD
LDA _RD
BNE _2 ; existing overflow, skip decrement operation
_1 CLC ; adding RD
LDA _I0
ADC _R0,X
STA _R0,X
LDA _RD+1
LDA _I0+1
ADC _R0+1,X
STA _R0+1,X
LDA _RD+2
LDA _I0+2
ADC _R0+2,X
STA _R0+2,X
LDA _RD+3
LDA _I0+3
ADC _R0+3,X
STA _R0+3,X
AND #_MSK_O ; check for overflow
BEQ _2
BEQ _3
EOR #_MSK_O
BEQ _2
_3 LDA _F ; set overflow
_2 LDA _F ; set overflow
ORA #_F_O
STA _F
BNE _5
_2 LDA _F ; clear overflow
BNE _4
_3 LDA _F ; clear overflow
AND #_F_O^$FF
STA _F
_5 RTS
_4 RTS
.)
_INR .( ; INR r 5r Rr <- Rr + 1.0 - increment register
LDA #0 ; set RD to plus one
STA _RD
LDA #0 ; set I0 to plus one
STA _I0
LDA #_PLS_1
STA _RD+1
STA _I0+1
LDA #0
STA _RD+2
STA _RD+3
BEQ _ADDRD
STA _I0+2
STA _I0+3
BEQ _ADDI0X
.)
_DCR .( ; DCR r 6r Rr <- Rr - 1.0 - decrement register
LDA #0 ; set RD to minus one
STA _RD
LDA #0 ; set I0 to minus one
STA _I0
LDA #_MNS_1
STA _RD+1
STA _I0+1
LDA #$FF
STA _RD+2
STA _RD+3
BNE _ADDRD
STA _I0+2
STA _I0+3
BNE _ADDI0X
.)
_TST .( ; TST r 7r F <- Rr <=> 0.0 - test register
@ -299,117 +299,195 @@ _2 INC _PCL ; advance PC
_3 RTS
.)
_RETZD .( ; clears register D, clears underflow, falls through to _TRFDR
_ZERI0 .( ; clears I0
LDA #0
STA _RD
STA _RD+1
STA _RD+2
STA _RD+3
STA _I0
STA _I0+1
STA _I0+2
STA _I0+3
RTS
.)
_TRFI0X .( ; transfer I0 to register indexed by X, MSB returned in A
LDA _I0
STA _R0,X
LDA _I0+1
STA _R0+1,X
LDA _I0+2
STA _R0+2,X
LDA _I0+3
STA _R0+3,X
RTS
.)
_RTZI0X .( ; clears I0, clears underflow, falls through to _RETI0X
JSR _ZERI0
LDA _F ; clear underflow
AND #_F_U^$FF
STA _F
.)
_TRFDR .( ; pulls X, transfers RD to X as r register, updates overflow flag
_RETI0X .( ; pulls X, transfers I0 to register indexed by X, updates overflow flag
PLA
TAX
LDA _RD ; transfer result to Rr
STA _R0,X
LDA _RD+1
STA _R0+1,X
LDA _RD+2
STA _R0+2,X
LDA _RD+3
STA _R0+3,X
JSR _TRFI0X ; transfer result to register indexed by X
AND #_MSK_O ; check for overflow
BEQ _4
BEQ _1
EOR #_MSK_O
BEQ _4
_3 LDA _F ; set overflow
BEQ _1
LDA _F ; set overflow
ORA #_F_O
STA _F
BNE _5
_4 LDA _F ; clear overflow
BNE _2
_1 LDA _F ; clear overflow
AND #_F_O^$FF
STA _F
_5 RTS
_2 RTS
.)
_ADD .( ; ADD r pq ar pq Rr <- Rp + Rq - addition
TXA
PHA ; save r register for later
JSR _GETPQ
CLC ; set RD to Rp + Rq
CLC ; set I0 to Rp + Rq
LDA _R0,X
ADC _R0,Y
STA _RD
STA _I0
LDA _R0+1,X
ADC _R0+1,Y
STA _RD+1
STA _I0+1
LDA _R0+2,X
ADC _R0+2,Y
STA _RD+2
STA _I0+2
LDA _R0+3,X
ADC _R0+3,Y
STA _RD+3
JMP _TRFDR ; pull X, transfer RD to r register, let it handle the return
STA _I0+3
JMP _RETI0X ; pull X, transfer I0 to r register, let it handle the return
.)
_SUB .( ; SUB r pq br pq Rr <- Rp - Rq - subtraction
TXA
PHA ; save r register for later
JSR _GETPQ
SEC ; set RD to Rp - Rq
SEC ; set I0 to Rp - Rq
LDA _R0,X
SBC _R0,Y
STA _RD
STA _I0
LDA _R0+1,X
SBC _R0+1,Y
STA _RD+1
STA _I0+1
LDA _R0+2,X
SBC _R0+2,Y
STA _RD+2
STA _I0+2
LDA _R0+3,X
SBC _R0+3,Y
STA _RD+3
JMP _TRFDR ; pull X, transfer RD to r register, let it handle the return
STA _I0+3
JMP _RETI0X ; pull X, transfer I0 to r register, let it handle the return
.)
_TRFQD .( ; transfers Y as q register to RD
LDA _R0,Y
STA _RD
LDA _R0+1,Y
STA _RD+1
LDA _R0+2,Y
STA _RD+2
LDA _R0+3,Y
STA _RD+3
RTS
.)
_NEGRY .( ; negates register at Y
_NEGX .( ; negates register at X
SEC
LDA #0
SBC _R0,Y
STA _R0,Y
SBC _R0,X
STA _R0,X
LDA #0
SBC _R0+1,Y
STA _R0+1,Y
SBC _R0+1,X
STA _R0+1,X
LDA #0
SBC _R0+2,Y
STA _R0+2,Y
SBC _R0+2,X
STA _R0+2,X
LDA #0
SBC _R0+3,Y
STA _R0+3,Y
SBC _R0+3,X
STA _R0+3,X
RTS
.)
_ABSRY .( ; sets register at Y to absolute value
LDA _R0+3,Y
BMI _NEGRY
_ABSX .( ; sets register at X to absolute value
LDA _R0+3,X
BMI _NEGX
RTS
.)
_BKRRD .( ; implement banker's rounding on quadword pointed by X
; The logic table below shows the expected results. The only differences are
; when the least significant byte (LSB) is 128 and the second byte (2B) is even
; vs odd.
;
; LSB 2B CARRY LSB + 127 + C CARRY* DELTA 2B*
; <127 EVEN 0 <254 0 0
; 127 EVEN 0 254 0 0
; 128 EVEN 0 255 0 0 <- not rounding up
; 129 EVEN 0 0 1 +1
; >129 EVEN 0 >0 1 +1
; <127 ODD 1 <255 0 0
; 127 ODD 1 255 0 0
; 128 ODD 1 0 1 +1 <- rounding up
; 129 ODD 1 1 1 +1
; >129 ODD 1 >1 1 +1
LDA _R0+1,X
ROR ; will set carry if odd
LDA _R0,X
ADC #127 ; adding just less than half
STA _R0,X
BCC _1
INC _R0+1,X ; propagate through the rest
BNE _1
INC _R0+2,X
BNE _1
INC _R0+3,X
BNE _1
INC _R1,X
BNE _1
INC _R1+1,X
BNE _1
INC _R1+2,X
BNE _1
INC _R1+3,X
_1 RTS
.)
_CPXI0 .( ; copy four bytes at X index to I0, returns MSB in A
LDA _R0,X
STA _I0
LDA _R0+1,X
STA _I0+1
LDA _R0+2,X
STA _I0+2
LDA _R0+3,X
STA _I0+3
RTS
.)
_RDXFI0 .( ; using X index, round quad-word, transfer to I0, set overflow in I0, set or clear the underflow flag
JSR _BKRRD ; banker's rounding
INX ; skip extra fraction
JSR _CPXI0 ; copy to I0
AND #_MSK_O ; consider the overflow bits
ORA _R1,X ; check all the other bytes
ORA _R1+1,X
ORA _R1+2,X
BEQ _1 ; all zeroes means no overflow
LDA _I0+3 ; overflow situation
AND #_MSK_O^$FF ; set overflow
ORA #_F_O
STA _I0+3
_1 LDA _I0 ; check for underflow
ORA _I0+1
ORA _I0+2
ORA _I0+3
BNE _2 ; non-zero result means no underflow
LDA _F ; we checked earlier for zero operands, so a zero result means underflow, set underflow
ORA #_F_U
STA _F
BNE _3
_2 LDA _F ; clear underflow
AND #_F_U^$FF
STA _F
_3 RTS
.)
_MUL .( ; MUL r pq cr pq Rr <- Rp * Rq - multiplication
TXA ; adapted from http://www.6502.org/source/integers/32muldiv.htm
PHA ; save r register for later
@ -419,355 +497,246 @@ _MUL .( ; MUL r pq cr pq Rr <- Rp * Rq - multiplication
ORA _R0+2,X
ORA _R0+3,X
BNE _1 ; p is non-zero
JMP _RETZD ; p is zero, return zero
JMP _RTZI0X ; p is zero, return zero
_1 LDA _R0,Y ; check for zero argument
ORA _R0+1,Y
ORA _R0+2,Y
ORA _R0+3,Y
BNE _2 ; q is non-zero
JMP _RETZD ; q is zero, return zero
_2 LDA _R0+3,X ; save sign of register p
AND #_MSK_O
PHA
JMP _RTZI0X ; q is zero, return zero
_2 LDA _R0+3,X
EOR _R0+3,Y
AND #_MSK_O ; save sign of product
PHA
JSR _TRFQD
TXA
TAY ; absolute value of register p
JSR _ABSRY
LDY #_RD-_R0 ; absolute value of register q saved in D
JSR _ABSRY
JSR _CPXI0 ; transfer p to I0
LDA _R0,Y ; transfer q to I1
STA _I1
LDA _R0+1,Y
STA _I1+1
LDA _R0+2,Y
STA _I1+2
LDA _R0+3,Y
STA _I1+3
LDX #_I0-_R0
JSR _ABSX ; set to absolute value
LDX #_I1-_R0
JSR _ABSX ; set to absolute value
LDA #0
STA _RB+4 ; clear upper half of product
STA _RB+5
STA _RB+6
STA _RB+7
LDY #34 ; thirty bit multiply and four bit shift
_3 LSR _RD+3 ; shift operand
ROR _RD+2
ROR _RD+1
ROR _RD
STA _I3 ; clear upper half of product in I3
STA _I3+1
STA _I3+2
STA _I3+3
LDY #34 ; thirty bit multiply and four bit shift to ensure product is aligned
_3 LSR _I1+3 ; get lowest bit of operand
ROR _I1+2
ROR _I1+1
ROR _I1
BCC _4 ; skip adding in product if bit is zero
CLC
LDA _RB+4 ; add in p register
ADC _R0,X
STA _RB+4
LDA _RB+5
ADC _R0+1,X
STA _RB+5
LDA _RB+6
ADC _R0+2,X
STA _RB+6
LDA _RB+7
ADC _R0+3,X
_4 ROR ; shift the product
STA _RB+7
ROR _RB+6
ROR _RB+5
ROR _RB+4
ROR _RB+3
ROR _RB+2
ROR _RB+1
ROR _RB
LDA _I3 ; add in p register
ADC _I0
STA _I3
LDA _I3+1
ADC _I0+1
STA _I3+1
LDA _I3+2
ADC _I0+2
STA _I3+2
LDA _I3+3
ADC _I0+3
STA _I3+3
_4 LSR _I3+3 ; shift the product down
ROR _I3+2
ROR _I3+1
ROR _I3
ROR _I2+3
ROR _I2+2
ROR _I2+1
ROR _I2
DEY
BNE _3 ; repeat until bits are done
LDA _RB+1 ; copy result to RD
STA _RD
LDA _RB+2
STA _RD+1
LDA _RB+3
STA _RD+2
LDA _RB+4
STA _RD+3
AND #_MSK_O ; consider the overflow bits
ORA _RB+5 ; check all the other bytes
ORA _RB+6
ORA _RB+7
BEQ _5 ; all zeroes means no overflow
LDA _RD+3 ; overflow situation, set accordingly
AND #_MSK_O^$FF ; set overflow
ORA #_F_O
STA _RD+3
BNE _6
_5 LDA _RD ; check for underflow
ORA _RD+1
ORA _RD+2
ORA _RD+3
BNE _6 ; non-zero result means no underflow
LDA _F ; we checked earlier for zero operands, so a zero result means underflow, set underflow
ORA #_F_U
STA _F
BNE _7
_6 LDA _F ; clear underflow
AND #_F_U^$FF
STA _F
_7 PLA ; set the sign of the product
BEQ _8
LDY #_RD-_R0 ; negate register D
JSR _NEGRY
_8 PLA ; reset the sign of register p
BEQ _9
TXA
TAY
JSR _NEGRY
_9 JMP _TRFDR ; pull X, transfer RD to r register, let it handle the return
LDX #_I2-_R0
JSR _RDXFI0 ; round and transfer to I0, set or clear underflow flag
PLA ; set the sign of the product
BEQ _5
LDX #_I0-_R0 ; negate I0
JSR _NEGX
_5 JMP _RETI0X ; pull X, transfer I0 to r register, let it handle the return
.)
_ZERQX .( ; zero quad-word (64 bits) at X
LDA #0
STA _R0,X
STA _R0+1,X
STA _R0+2,X
STA _R0+3,X
STA _R0+4,X
STA _R0+5,X
STA _R0+6,X
STA _R0+7,X
RTS
.)
_INTDM .( ; initialize for DIV and MOD, returns sign of result in A
TXA
PHA ; save r register for later
JSR _GETPQ
LDA _R0,X ; check for zero argument
ORA _R0+1,X
ORA _R0+2,X
ORA _R0+3,X
BNE _1 ; p is non-zero
JMP _RETZD ; p is zero, return zero
JMP _RTZI0X ; p is zero, return zero
_1 LDA _R0,Y ; check for zero argument
ORA _R0+1,Y
ORA _R0+2,Y
ORA _R0+3,Y
BNE _2 ; q is non-zero
BRK ; q is zero, abort and call exception handler (TODO)
_2 LDA _R0,X ; copy p to RD
STA _RD
LDA _R0+1,X
STA _RD+1
LDA _R0+2,X
STA _RD+2
LDA _R0+3,X
STA _RD+3
LDA _R0,Y ; copy q to RC
STA _RC
; I0 / I1 will form 64-bit quantity with high order bytes I1 as zero
_2 JSR _CPXI0 ; copy p to I0
LDX #_I1-_R0
JSR _ZERQX
; I2 / I3 will form 64-bit quantity with low order bytes I2 as zero
LDA _R0,Y ; copy q to I3
STA _I3
LDA _R0+1,Y
STA _RC+1
STA _I3+1
LDA _R0+2,Y
STA _RC+2
STA _I3+2
LDA _R0+3,Y
STA _RC+3
LDA #0 ; set RB to 1
STA _RB
LDA #_PLS_1
STA _RB+1
LDA #0
STA _RB+2
STA _RB+3
PLA ; restore r register
TAX
LDA #0 ; set r to 0
STA _R0,X
STA _R0+1,X
STA _R0+2,X
STA _R0+3,X
LDA _RD+3 ; get sign of result
EOR _RC+3
STA _I3+3
; I4 / I5 will form 64-bit result
LDX #_I4-_R0
JSR _ZERQX
LDA _I0+3 ; get sign of result
EOR _I3+3
AND #_MSK_O
RTS
.)
_CMPDC .( ; compare D to C, return result in status
LDA _RD+3
CMP _RC+3
_CMPDM .( ; compare I0/I1 to I2/I3, return result in status
LDA _I1+3
CMP _I3+3
BCC _1 ; definitely less
BNE _1 ; definitely greater
LDA _RD+2
CMP _RC+2
LDA _I1+2
CMP _I3+2
BCC _1 ; definitely less
BNE _1 ; definitely greater
LDA _RD+1
CMP _RC+1
LDA _I1+1
CMP _I3+1
BCC _1 ; definitely less
BNE _1 ; definitely greater
LDA _RD
CMP _RC
LDA _I1
CMP _I3
BCC _1 ; definitely less
BNE _1 ; definitely greater
LDA _I0+3
CMP _I2+3
BCC _1 ; definitely less
BNE _1 ; definitely greater
LDA _I0+2
CMP _I2+2
BCC _1 ; definitely less
BNE _1 ; definitely greater
LDA _I0+1
CMP _I2+1
BCC _1 ; definitely less
BNE _1 ; definitely greater
LDA _I0
CMP _I2
_1 RTS
.)
_UPDDM .( ; update DIV and MOD
SEC ; RD -= RC
LDA _RD
SBC _RC
STA _RD
LDA _RD+1
SBC _RC+1
STA _RD+1
LDA _RD+2
SBC _RC+2
STA _RD+2
LDA _RD+3
SBC _RC+3
STA _RD+3
CLC ; RX += RB
LDA _R0,X
ADC _RB
STA _R0,X
LDA _R0+1,X
ADC _RB+1
STA _R0+1,X
LDA _R0+2,X
ADC _RB+2
STA _R0+2,X
LDA _R0+3,X
ADC _RB+3
STA _R0+3,X
SEC ; I0/I1 -= I2/I3
LDA _I0
SBC _I2
STA _I0
LDA _I0+1
SBC _I2+1
STA _I0+1
LDA _I0+2
SBC _I2+2
STA _I0+2
LDA _I0+3
SBC _I2+3
STA _I0+3
LDA _I1
SBC _I3
STA _I1
LDA _I1+1
SBC _I3+1
STA _I1+1
LDA _I1+2
SBC _I3+2
STA _I1+2
LDA _I1+3
SBC _I3+3
STA _I1+3
RTS
.)
_SHUDM .( ; shift up for DIV and MOD
ASL _RC ; RC *= 2
ROL _RC+1
ROL _RC+2
ROL _RC+3
ASL _RB ; RB *= 2
ROL _RB+1
ROL _RB+2
ROL _RB+3
_SHUDM .( ; shift up for DIV and MOD, C should be set or cleared as required
ROL _I4 ; I4/I5 *= 2
ROL _I4+1
ROL _I4+2
ROL _I4+3
ROL _I5
ROL _I5+1
ROL _I5+2
ROL _I5+3
RTS
.)
_SHDDM .( ; shift down for DIV and MOD
CLC ; RC /= 2
ROR _RC+3
ROR _RC+2
ROR _RC+1
ROR _RC
CLC ; RB /= 2
ROR _RB+3
ROR _RB+2
ROR _RB+1
ROR _RB
CLC ; I2/I3 /= 2
ROR _I3+3
ROR _I3+2
ROR _I3+1
ROR _I3
ROR _I2+3
ROR _I2+2
ROR _I2+1
ROR _I2
RTS
.)
_DIV .( ; DIV r pq dr pq Rr <- Rp / Rq - division
TXA
PHA ; save r register for later
JSR _INTDM ; initialize
PHA ; save sign of result
LDY #_RD-_R0 ; absolute value of register p saved in D
JSR _ABSRY
LDY #_RC-_R0 ; absolute value of register q saved in C
JSR _ABSRY
_3 JSR _CMPDC ; is D < C?
BCC _4 ; yes, continue
BEQ _5 ; D = C
JSR _UPDDM ; confirmed D > C, so RD -= RC, RX += RB
JSR _SHUDM ; shift up
BCC _3 ; if carry is set, means a really bad overflow condition
LDA #$FF ; set to the maximum
STA _R0,X
STA _R0+1,X
STA _R0+2,X
LDA #_MAX_V|_F_O
STA _R0+3,X
BNE _9
_4 LDA _RB ; is RB > 0?
ORA _RB+1
ORA _RB+2
ORA _RB+3
BEQ _7 ; no, done
JSR _CMPDC ; is D >= C?
BCC _6 ; no, skip subtraction
_5 JSR _UPDDM ; RD -= RC, RX += RB
LDA _RD ; is RD > 0?
ORA _RD+1
ORA _RD+2
ORA _RD+3
BEQ _7 ; no, done
_6 JSR _SHDDM ; shift down
JMP _4
_7 LDA _R0,X ; check for underflow
ORA _R0+1,X
ORA _R0+2,X
ORA _R0+3,X
BNE _8 ; non-zero result means no underflow
LDA _F ; we checked earlier for zero operands, so a zero result means underflow, set underflow
ORA #_F_U
STA _F
BNE _A
_8 LDA _F ; clear underflow
AND #_F_U^$FF
STA _F
_9 LDA _R0+3,X ; check for overflow
AND #_MSK_O
BEQ _A ; all zero, no overflow
LDA _F ; set overflow
ORA #_F_O
STA _F
BNE _B
_A LDA _F ; clear overflow
AND #_F_O^$FF
STA _F
_B PLA ; set the sign of quotient
BEQ _C
TXA
TAY
JSR _NEGRY
_C RTS
LDX #_I0-_R0 ; absolute value of register p saved in I0
JSR _ABSX
LDX #_I3-_R0 ; absolute value of register q saved in I3
JSR _ABSX
LDY #51 ; 51 bits are enough, and ensure alignment
_1 JSR _CMPDM ; is I0/I1 < I2/I3
BCC _2 ; yes, skip subtraction
BEQ _4 ; special case when p = q
JSR _UPDDM ; I0/I1 -= I2/I3
_2 JSR _SHUDM ; I4/I5 *= 2 += CARRY
JSR _SHDDM ; I2/I3 /= 2
DEY
BNE _1
BEQ _5
_3 CLC ; special case when p = q, just shift up to the end
_4 JSR _SHUDM ; I4/I5 *= 2 += CARRY
DEY
BNE _3
_5 LDX #_I4-_R0
JSR _RDXFI0 ; round and transfer to I0, set or clear underflow flag
PLA ; set the sign of the product
BEQ _6
LDX #_I0-_R0 ; negate I0
JSR _NEGX
_6 JMP _RETI0X ; pull X, transfer I0 to r register, let it handle the return
.)
_MOD .( ; MOD r pq er pq Rr <- Rp % Rq - modulus
JSR _INTDM ; initialize
PHA ; save sign of result
LDY #_RD-_R0 ; absolute value of register p saved in D
JSR _ABSRY
LDY #_RC-_R0 ; absolute value of register q saved in C
JSR _ABSRY
_3 JSR _CMPDC ; is D < C?
BCC _4 ; yes, continue
BEQ _5 ; D = C
JSR _UPDDM ; confirmed D > C, so RD -= RC, RX += RB
JSR _SHUDM ; shift up
BCC _3 ; if carry is set, means a really bad overflow condition
LDA #1 ; set to "overflowed non-zero"
STA _R0,X
LDA #0
STA _R0+1,X
STA _R0+2,X
ORA #_F_O
STA _R0+3,X
BNE _9
_4 LDA _RB+1 ; is RB < 1?
CMP #_PLS_1
BCC _7 ; yes, done
JSR _CMPDC ; is D >= C?
BCC _6 ; no, skip subtraction
_5 JSR _UPDDM ; RD -= RC, RX += RB
LDA _RD ; is RD > 0?
ORA _RD+1
ORA _RD+2
ORA _RD+3
BEQ _7 ; no, done
_6 JSR _SHDDM ; shift down
JMP _4
_7 LDA _RD ; transfer RD to RX
STA _R0,X
LDA _RD+1
STA _R0+1,X
LDA _RD+2
STA _R0+2,X
LDA _RD+3
STA _R0+3,X
_8 LDA _F ; clear underflow
AND #_F_U^$FF
STA _F
_9 LDA _R0+3,X ; check for overflow
AND #_MSK_O
BEQ _A ; all zero, no overflow
LDA _F ; set overflow
ORA #_F_O
STA _F
BNE _B
_A LDA _F ; clear overflow
AND #_F_O^$FF
STA _F
_B PLA ; set the sign of modulus
BEQ _C
TXA
TAY
JSR _NEGRY
_C RTS
_MOD .(
RTS
.)
_ESC .( ; ESC 00 - escape back into regular assembler
PLA ; discard the COMMON _1 return address
PLA

View File

@ -46,8 +46,8 @@
; SVI pq 0e pq (int(Rp)) <- Rq - save indirect to memory
; CMR pq 0f pq F <- Rp <=> Rq - compare registers
; 64 bytes in page zero for common registers
_R0 = $c0
; 40 bytes in page zero for common registers
_R0 = $b8
_R1 = _R0 + 4
_R2 = _R1 + 4
_R3 = _R2 + 4
@ -57,16 +57,20 @@ _R6 = _R5 + 4
_R7 = _R6 + 4
_R8 = _R7 + 4
_R9 = _R8 + 4
_RA = _R9 + 4
_RB = _RA + 4 ; workspace for MUL, DIV, and MOD
_RC = _RB + 4 ; as above
_RD = _RC + 4 ; as above and for ADD, SUB, and EXC
_RE = _RD + 4 ; register E maintains common status
_RF = _RE + 4 ; register F saves/restores processor status
; register E maintains common status
; 32 bytes in page zero for internal registers
_I0 = $e0 ; workspace for ADD, SUB, MUL, DIV, MOD, EXC
_I1 = _I0 + 4
_I2 = _I1 + 4
_I3 = _I2 + 4
_I4 = _I3 + 4
_I5 = _I4 + 4
_I6 = _I5 + 4 ; register I6 maintains common status
_I7 = _I6 + 4 ; register I7 saves/restores processor status
; register I6 maintains common status
; (dd cc bb aa) aa: index for register stack RS / ccbb: program counter PC / dd: flags F UONPZLGE
_RSI = _RE ; register stack index
_RSI = _I6 ; register stack index
_PCL = _RSI + 1 ; program counter low
_PCH = _PCL + 1 ; program counter high
_F = _PCH + 1 ; flags
@ -82,9 +86,9 @@ _F_N = 32 ; if Rr < 0.0 (after TST)
_F_O = 64 ; if overflow (after arithmetic operations)
_F_U = 128 ; if underflow (after arithmetic operations)
; register F saves/restores processor status
; register I7 saves/restores processor status
; (dd cc bb aa) aa: accumulator, bb: index X, cc: index Y, dd: processor status
_ACC = _RF ; saved accumulator to restore
_ACC = _I7 ; saved accumulator to restore
_IDX = _ACC + 1 ; saved index X to restore
_IDY = _IDX + 1 ; saved index Y to restore
_PS = _IDY + 1 ; saved processor status to restore

View File

@ -3,7 +3,7 @@
#ifndef __MACROS_H
#define __MACROS_H
; registers
; common registers
#define R0 0
#define R1 1
#define R2 2
@ -14,12 +14,6 @@
#define R7 7
#define R8 8
#define R9 9
#define RA 10
#define RB 11
#define RC 12
#define RD 13
#define RE 14
#define RF 15
; system functions
#define S0 0
@ -32,12 +26,6 @@
#define S7 7
#define S8 8
#define S9 9
#define SA 10
#define SB 11
#define SC 12
#define SD 13
#define SE 14
#define SF 15
; user functions
#define U0 15
@ -50,12 +38,6 @@
#define U7 8
#define U8 7
#define U9 6
#define UA 5
#define UB 4
#define UC 3
#define UD 2
#define UE 1
#define UF 0
; macros
#define ESC .BYTE _ESC_C

View File

@ -5,9 +5,10 @@
HDR(DEMO)
CMN
SET(R0, 1024 * 1024 - 0.001)
SET(R1, 1/4)
MOD(R2, R0, R1)
SET(R0, 1048575.9995)
SET(R1, 3)
DIV(R2, R0, R1)
MUL(R3, R2, R1)
ESC
BRK

View File

@ -315,16 +315,16 @@ static void adc() {
penaltyop = 1;
value = getvalue();
result = (uint16_t)a + value + (uint16_t)(status & FLAG_CARRY);
carrycalc(result);
zerocalc(result);
overflowcalc(result, a, value);
signcalc(result);
#ifndef NES_CPU
if (status & FLAG_DECIMAL) {
clearcarry();
if ((a & 0x0F) > 0x09) {
a += 0x06;
}
@ -332,11 +332,11 @@ static void adc() {
a += 0x60;
setcarry();
}
clockticks6502++;
}
#endif
saveaccum(result);
}
@ -344,10 +344,10 @@ static void and() {
penaltyop = 1;
value = getvalue();
result = (uint16_t)a & value;
zerocalc(result);
signcalc(result);
saveaccum(result);
}
@ -358,7 +358,7 @@ static void asl() {
carrycalc(result);
zerocalc(result);
signcalc(result);
putvalue(result);
}
@ -392,7 +392,7 @@ static void beq() {
static void bit() {
value = getvalue();
result = (uint16_t)a & value;
zerocalc(result);
status = (status & 0x3F) | (uint8_t)(value & 0xC0);
}
@ -470,7 +470,7 @@ static void cmp() {
penaltyop = 1;
value = getvalue();
result = (uint16_t)a - value;
if (a >= (uint8_t)(value & 0x00FF)) setcarry();
else clearcarry();
if (a == (uint8_t)(value & 0x00FF)) setzero();
@ -481,7 +481,7 @@ static void cmp() {
static void cpx() {
value = getvalue();
result = (uint16_t)x - value;
if (x >= (uint8_t)(value & 0x00FF)) setcarry();
else clearcarry();
if (x == (uint8_t)(value & 0x00FF)) setzero();
@ -492,7 +492,7 @@ static void cpx() {
static void cpy() {
value = getvalue();
result = (uint16_t)y - value;
if (y >= (uint8_t)(value & 0x00FF)) setcarry();
else clearcarry();
if (y == (uint8_t)(value & 0x00FF)) setzero();
@ -503,23 +503,23 @@ static void cpy() {
static void dec() {
value = getvalue();
result = value - 1;
zerocalc(result);
signcalc(result);
putvalue(result);
}
static void dex() {
x--;
zerocalc(x);
signcalc(x);
}
static void dey() {
y--;
zerocalc(y);
signcalc(y);
}
@ -528,33 +528,33 @@ static void eor() {
penaltyop = 1;
value = getvalue();
result = (uint16_t)a ^ value;
zerocalc(result);
signcalc(result);
saveaccum(result);
}
static void inc() {
value = getvalue();
result = value + 1;
zerocalc(result);
signcalc(result);
putvalue(result);
}
static void inx() {
x++;
zerocalc(x);
signcalc(x);
}
static void iny() {
y++;
zerocalc(y);
signcalc(y);
}
@ -572,7 +572,7 @@ static void lda() {
penaltyop = 1;
value = getvalue();
a = (uint8_t)(value & 0x00FF);
zerocalc(a);
signcalc(a);
}
@ -581,7 +581,7 @@ static void ldx() {
penaltyop = 1;
value = getvalue();
x = (uint8_t)(value & 0x00FF);
zerocalc(x);
signcalc(x);
}
@ -590,7 +590,7 @@ static void ldy() {
penaltyop = 1;
value = getvalue();
y = (uint8_t)(value & 0x00FF);
zerocalc(y);
signcalc(y);
}
@ -598,12 +598,12 @@ static void ldy() {
static void lsr() {
value = getvalue();
result = value >> 1;
if (value & 1) setcarry();
else clearcarry();
zerocalc(result);
signcalc(result);
putvalue(result);
}
@ -624,10 +624,10 @@ static void ora() {
penaltyop = 1;
value = getvalue();
result = (uint16_t)a | value;
zerocalc(result);
signcalc(result);
saveaccum(result);
}
@ -641,7 +641,7 @@ static void php() {
static void pla() {
a = pull8();
zerocalc(a);
signcalc(a);
}
@ -653,23 +653,23 @@ static void plp() {
static void rol() {
value = getvalue();
result = (value << 1) | (status & FLAG_CARRY);
carrycalc(result);
zerocalc(result);
signcalc(result);
putvalue(result);
}
static void ror() {
value = getvalue();
result = (value >> 1) | ((status & FLAG_CARRY) << 7);
if (value & 1) setcarry();
else clearcarry();
zerocalc(result);
signcalc(result);
putvalue(result);
}
@ -688,7 +688,7 @@ static void sbc() {
penaltyop = 1;
value = getvalue() ^ 0x00FF;
result = (uint16_t)a + value + (uint16_t)(status & FLAG_CARRY);
carrycalc(result);
zerocalc(result);
overflowcalc(result, a, value);
@ -697,7 +697,7 @@ static void sbc() {
#ifndef NES_CPU
if (status & FLAG_DECIMAL) {
clearcarry();
a -= 0x66;
if ((a & 0x0F) > 0x09) {
a += 0x06;
@ -706,11 +706,11 @@ static void sbc() {
a += 0x60;
setcarry();
}
clockticks6502++;
}
#endif
saveaccum(result);
}
@ -740,28 +740,28 @@ static void sty() {
static void tax() {
x = a;
zerocalc(x);
signcalc(x);
}
static void tay() {
y = a;
zerocalc(y);
signcalc(y);
}
static void tsx() {
x = sp;
zerocalc(x);
signcalc(x);
}
static void txa() {
a = x;
zerocalc(a);
signcalc(a);
}
@ -772,7 +772,7 @@ static void txs() {
static void tya() {
a = y;
zerocalc(a);
signcalc(a);
}
@ -918,7 +918,7 @@ void (*loopexternal)();
void exec6502(uint32_t tickcount) {
clockgoal6502 += tickcount;
while (clockticks6502 < clockgoal6502) {
opcode = read6502(pc++);
status |= FLAG_CONSTANT;

View File

@ -26,10 +26,19 @@ void hook() {
int i, j;
printf("\n%04x %u %u\n", pc, instructions, clockticks6502);
for (i = 0x00c0; i < 0x0100; i += 16) {
printf("%04x ", i);
for (j = 0; j < 16; ++j)
printf("%02x%s", memory[i + j], (i + j + 1) % 16? " ": "\n");
for (i = 0x00b8; i < 0x00d8; i += 4) {
printf("R%d: ", (i - 0x00b8) / 4);
for (j = 0; j < 4; ++j)
printf("%02x ", memory[i + j]);
if (((i - 0x00b8) / 4) % 4 == 3)
printf("\n");
}
for (i = 0x00e0; i < 0x0100; i += 4) {
printf("I%d: ", (i - 0x00e0) / 4);
for (j = 0; j < 4; ++j)
printf("%02x ", memory[i + j]);
if (((i - 0x00e0) / 4) % 4 == 3)
printf("\n");
}
}

View File

@ -6,5 +6,5 @@ $(TGT): main.c $(TGT).h $(TGT).re $(TGT).l $(TGT).y
bison -d $(TGT).y
gcc main.c $(TGT).c $(TGT).tab.c $(TGT).yy.c -lfl -lm -o $(TGT)
clean:
clean:
rm -f $(TGT).c $(TGT).yy.h $(TGT).yy.c $(TGT).tab.h $(TGT).tab.c $(TGT)

View File

@ -46,7 +46,7 @@
#define TOKEN_LEN 256
#endif /* TOKEN_LEN */
#define TOKENS 128
#define IO_BUFFER (TOKENS * TOKEN_LEN)
#define IO_BUFFER (TOKENS * TOKEN_LEN)
typedef enum
{

View File

@ -21,7 +21,7 @@ int tokenizeInput(const char *cursor, TOKEN *tokens)
re2c:indent:top = 2;
re2c:yyfill:enable = 0;
re2c:yych:conversion = 1;
BELL = "\x07" ;
BACKSPACE = "\x08" ;
HORIZONTAL_TAB = "\x09" ;
@ -31,7 +31,7 @@ int tokenizeInput(const char *cursor, TOKEN *tokens)
CARRIAGE_RETURN = "\x0d" ;
ESCAPE = "\x1b" ;
DELETE = "\x7f" ;
SPACE = "\x20" ;
EXCLAMATION_MARK = "\x21" ;
QUOTATION_MARK = "\x22" ;
@ -65,24 +65,24 @@ int tokenizeInput(const char *cursor, TOKEN *tokens)
VERTICAL_LINE = "\x7c" ;
RIGHT_CURLY_BRACKET = "\x7d" ;
TILDE = "\x7e" ;
DIGIT = [0-9] ;
LETTER = [A-Za-z] ;
WHITE_SPACE = BELL | BACKSPACE | HORIZONTAL_TAB | ESCAPE | DELETE | SPACE ;
VALID = DIGIT | LETTER | EXCLAMATION_MARK | DOLLAR_SIGN | PERCENT_SIGN | AMPERSAND
| LEFT_PARENTHESIS | RIGHT_PARENTHESIS | ASTERISK | PLUS_SIGN | HYPHEN_MINUS
| FULL_STOP | SOLIDUS | LESS_THAN_SIGN | EQUALS_SIGN | GREATER_THAN_SIGN
| LOW_LINE | VERTICAL_LINE | TILDE | WHITE_SPACE ;
COMMAND = LOW_LINE [Ss][Ee][Tt] LOW_LINE [Vv] WHITE_SPACE* LEFT_PARENTHESIS WHITE_SPACE* QUOTATION_MARK VALID+ QUOTATION_MARK WHITE_SPACE* RIGHT_PARENTHESIS ;
DEFAULT = . ;
END_OF_LINE = ( LINE_FEED | VERTICAL_TAB | FORM_FEED | CARRIAGE_RETURN )+ ;
COMMAND { i = copyToken(tokens, i, TT_COMMAND, token, (int)(cursor - token)); continue; }
DEFAULT { i = copyToken(tokens, i, TT_DEFAULT, token, (int)(cursor - token)); continue; }
WHITE_SPACE { i = copyToken(tokens, i, TT_WHITE_SPACE, token, (int)(cursor - token)); continue; }