From 8bbb5016cd5386cf7e7083526f0e0771266f2ae1 Mon Sep 17 00:00:00 2001 From: Russell-S-Harper Date: Tue, 21 Aug 2018 09:14:16 -0400 Subject: [PATCH] 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. --- common/Makefile | 2 +- common/common.asm | 729 +++++++++++++++++++--------------------- common/common.h | 28 +- common/macros.h | 20 +- common/page6.src | 7 +- emulator/emulator.c | 88 ++--- emulator/main.c | 17 +- xa-pre-process/Makefile | 2 +- xa-pre-process/xapp.h | 2 +- xa-pre-process/xapp.re | 20 +- 10 files changed, 440 insertions(+), 475 deletions(-) diff --git a/common/Makefile b/common/Makefile index fe478a7..689893c 100644 --- a/common/Makefile +++ b/common/Makefile @@ -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 diff --git a/common/common.asm b/common/common.asm index 3af6950..0517cf6 100644 --- a/common/common.asm +++ b/common/common.asm @@ -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 diff --git a/common/common.h b/common/common.h index f314054..893b745 100644 --- a/common/common.h +++ b/common/common.h @@ -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 diff --git a/common/macros.h b/common/macros.h index 264ae55..aef0d60 100644 --- a/common/macros.h +++ b/common/macros.h @@ -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 diff --git a/common/page6.src b/common/page6.src index 5c025d4..f5f71a8 100644 --- a/common/page6.src +++ b/common/page6.src @@ -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 diff --git a/emulator/emulator.c b/emulator/emulator.c index 8f51170..c7f3299 100644 --- a/emulator/emulator.c +++ b/emulator/emulator.c @@ -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; diff --git a/emulator/main.c b/emulator/main.c index 4d0af6d..7aa7202 100644 --- a/emulator/main.c +++ b/emulator/main.c @@ -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"); } } diff --git a/xa-pre-process/Makefile b/xa-pre-process/Makefile index 6b199fa..fbb819b 100644 --- a/xa-pre-process/Makefile +++ b/xa-pre-process/Makefile @@ -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) diff --git a/xa-pre-process/xapp.h b/xa-pre-process/xapp.h index c24451e..736de49 100644 --- a/xa-pre-process/xapp.h +++ b/xa-pre-process/xapp.h @@ -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 { diff --git a/xa-pre-process/xapp.re b/xa-pre-process/xapp.re index ebe2718..6cb6193 100644 --- a/xa-pre-process/xapp.re +++ b/xa-pre-process/xapp.re @@ -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; }