; Decimal mode tests from Bruce Clark's fantastic Decimal Mode ; tutorial on 6502.org. Modified very slightly to allow choosing the ; CPU architecture (6502 or 65C02) without recompiling. ; http://www.6502.org/tutorials/decimal_mode.html#B bss org 0 ERROR ds 1 MODE ds 1 ; 0 for 6502, 1 for 65C02 AR ds 1 CF ds 1 DA ds 1 DNVZC ds 1 HA ds 1 HNVZC ds 1 N1 ds 1 N1H ds 1 N1L ds 1 N2 ds 1 N2L ds 1 NF ds 1 VF ds 1 ZF ds 1 N2H ds 2 code org $1000 lda MODE bne INIT65C02 INIT6502 lda #lo(A6502) sta ADD_ADDR + 1 lda #hi(A6502) sta ADD_ADDR + 2 lda #lo(S6502) sta SUB_ADDR + 1 lda #hi(S6502) sta SUB_ADDR + 2 jmp INITDONE INIT65C02 lda #lo(A65C02) sta ADD_ADDR + 1 lda #hi(A65C02) sta ADD_ADDR + 2 lda #lo(S65C02) sta SUB_ADDR + 1 lda #hi(S65C02) sta SUB_ADDR + 2 jmp INITDONE INITDONE jsr TEST lda #0 beq * ; done ; Verify decimal mode behavior ; ; Returns: ; ERROR = 0 if the test passed ; ERROR = 1 if the test failed ; ; This routine requires 17 bytes of RAM -- 1 byte each for: ; AR, CF, DA, DNVZC, ERROR, HA, HNVZC, N1, N1H, N1L, N2, N2L, NF, VF, and ZF ; and 2 bytes for N2H ; ; Variables: ; N1 and N2 are the two numbers to be added or subtracted ; N1H, N1L, N2H, and N2L are the upper 4 bits and lower 4 bits of N1 and N2 ; DA and DNVZC are the actual accumulator and flag results in decimal mode ; HA and HNVZC are the accumulator and flag results when N1 and N2 are ; added or subtracted using binary arithmetic ; AR, NF, VF, ZF, and CF are the predicted decimal mode accumulator and ; flag results, calculated using binary arithmetic ; ; This program takes approximately 1 minute at 1 MHz (a few seconds more on ; a 65C02 than a 6502 or 65816) ; TEST ldy #1 ; initialize y (used to loop through carry flag values) sty ERROR ; store 1 in ERROR until the test passes lda #0 ; initialize N1 and N2 sta N1 sta N2 LOOP1 lda N2 ; N2L = N2 & $0F and #$0F ; [1] see text sta N2L lda N2 ; N2H = N2 & $F0 and #$F0 ; [2] see text sta N2H ora #$0F ; N2H+1 = (N2 & $F0) + $0F sta N2H+1 LOOP2 lda N1 ; N1L = N1 & $0F and #$0F ; [3] see text sta N1L lda N1 ; N1H = N1 & $F0 and #$F0 ; [4] see text sta N1H jsr ADD ADD_ADDR = * jsr A6502 jsr COMPARE bne DONE jsr SUB SUB_ADDR = * jsr S6502 jsr COMPARE bne DONE inc N1 ; [5] see text bne LOOP2 ; loop through all 256 values of N1 inc N2 ; [6] see text bne LOOP1 ; loop through all 256 values of N2 dey bpl LOOP1 ; loop through both values of the carry flag lda #0 ; test passed, so store 0 in ERROR sta ERROR DONE rts ; Calculate the actual decimal mode accumulator and flags, the accumulator ; and flag results when N1 is added to N2 using binary arithmetic, the ; predicted accumulator result, the predicted carry flag, and the predicted ; V flag ; ADD sed ; decimal mode cpy #1 ; set carry if Y = 1, clear carry if Y = 0 lda N1 adc N2 sta DA ; actual accumulator result in decimal mode php pla sta DNVZC ; actual flags result in decimal mode cld ; binary mode cpy #1 ; set carry if Y = 1, clear carry if Y = 0 lda N1 adc N2 sta HA ; accumulator result of N1+N2 using binary arithmetic php pla sta HNVZC ; flags result of N1+N2 using binary arithmetic cpy #1 lda N1L adc N2L cmp #$0A ldx #0 bcc A1 inx adc #5 ; add 6 (carry is set) and #$0F sec A1 ora N1H ; ; if N1L + N2L < $0A, then add N2 & $F0 ; if N1L + N2L >= $0A, then add (N2 & $F0) + $0F + 1 (carry is set) ; adc N2H,x php bcs A2 cmp #$A0 bcc A3 A2 adc #$5F ; add $60 (carry is set) sec A3 sta AR ; predicted accumulator result php pla sta CF ; predicted carry result pla ; ; note that all 8 bits of the P register are stored in VF ; sta VF ; predicted V flags rts ; Calculate the actual decimal mode accumulator and flags, and the ; accumulator and flag results when N2 is subtracted from N1 using binary ; arithmetic ; SUB sed ; decimal mode cpy #1 ; set carry if Y = 1, clear carry if Y = 0 lda N1 sbc N2 sta DA ; actual accumulator result in decimal mode php pla sta DNVZC ; actual flags result in decimal mode cld ; binary mode cpy #1 ; set carry if Y = 1, clear carry if Y = 0 lda N1 sbc N2 sta HA ; accumulator result of N1-N2 using binary arithmetic php pla sta HNVZC ; flags result of N1-N2 using binary arithmetic rts ; Calculate the predicted SBC accumulator result for the 6502 and 65816 ; SUB1 cpy #1 ; set carry if Y = 1, clear carry if Y = 0 lda N1L sbc N2L ldx #0 bcs S11 inx sbc #5 ; subtract 6 (carry is clear) and #$0F clc S11 ora N1H ; ; if N1L - N2L >= 0, then subtract N2 & $F0 ; if N1L - N2L < 0, then subtract (N2 & $F0) + $0F + 1 (carry is clear) ; sbc N2H,x bcs S12 sbc #$5F ; subtract $60 (carry is clear) S12 sta AR rts ; Calculate the predicted SBC accumulator result for the 6502 and 65C02 ; SUB2 cpy #1 ; set carry if Y = 1, clear carry if Y = 0 lda N1L sbc N2L ldx #0 bcs S21 inx and #$0F clc S21 ora N1H ; ; if N1L - N2L >= 0, then subtract N2 & $F0 ; if N1L - N2L < 0, then subtract (N2 & $F0) + $0F + 1 (carry is clear) ; sbc N2H,x bcs S22 sbc #$5F ; subtract $60 (carry is clear) S22 cpx #0 beq S23 sbc #6 S23 sta AR ; predicted accumulator result rts ; Compare accumulator actual results to predicted results ; ; Return: ; Z flag = 1 (BEQ branch) if same ; Z flag = 0 (BNE branch) if different ; COMPARE lda DA cmp AR bne C1 lda DNVZC ; [7] see text eor NF and #$80 ; mask off N flag bne C1 lda DNVZC ; [8] see text eor VF and #$40 ; mask off V flag bne C1 ; [9] see text lda DNVZC eor ZF ; mask off Z flag and #2 bne C1 ; [10] see text lda DNVZC eor CF and #1 ; mask off C flag C1 rts ; These routines store the predicted values for ADC and SBC for the 6502, ; 65C02, and 65816 in AR, CF, NF, VF, and ZF A6502 lda VF ; ; since all 8 bits of the P register were stored in VF, bit 7 of VF contains ; the N flag for NF ; sta NF lda HNVZC sta ZF rts S6502 jsr SUB1 lda HNVZC sta NF sta VF sta ZF sta CF rts A65C02 lda AR php pla sta NF sta ZF rts S65C02 jsr SUB2 lda AR php pla sta NF sta ZF lda HNVZC sta VF sta CF rts A65816 lda AR php pla sta NF sta ZF rts S65816 jsr SUB1 lda AR php pla sta NF sta ZF lda HNVZC sta VF sta CF rts