#### 356 lines 9.0 KiB Plaintext Raw Permalink Blame History

 ```; Verify decimal mode behavior ``` ```; Written by Bruce Clark. This code is public domain. ``` ```; see http://www.6502.org/tutorials/decimal_mode.html ``` ```; ``` ```; Returns: ``` ```; ERROR = 0 if the test passed ``` ```; ERROR = 1 if the test failed ``` ```; modify the code at the DONE label for desired program end ``` ```; ``` ```; 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) ``` ```; ``` ``` ``` ```; Configuration: ``` ```cputype = 1 ; 0 = 6502, 1 = 65C02, 2 = 65C816 ``` ```vld_bcd = 0 ; 0 = allow invalid bcd, 1 = valid bcd only ``` ```chk_a = 1 ; check accumulator ``` ```chk_n = 0 ; check sign (negative) flag ``` ```chk_v = 0 ; check overflow flag ``` ```chk_z = 0 ; check zero flag ``` ```chk_c = 0 ; check carry flag ``` ``` ``` ```end_of_test macro ``` ``` db \$db ;execute 65C02 stop instruction ``` ``` endm ``` ``` ``` ``` bss ``` ``` org 0 ``` ```; operands - register Y = carry in ``` ```N1 ds 1 ``` ```N2 ds 1 ``` ```; binary result ``` ```HA ds 1 ``` ```HNVZC ds 1 ``` ``` ;04 ``` ```; decimal result ``` ```DA ds 1 ``` ```DNVZC ds 1 ``` ```; predicted results ``` ```AR ds 1 ``` ```NF ds 1 ``` ``` ;08 ``` ```VF ds 1 ``` ```ZF ds 1 ``` ```CF ds 1 ``` ```ERROR ds 1 ``` ``` ;0C ``` ```; workspace ``` ```N1L ds 1 ``` ```N1H ds 1 ``` ```N2L ds 1 ``` ```N2H ds 2 ``` ``` ``` ``` code ``` ``` org \$200 ``` ```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 ``` ``` if vld_bcd = 1 ``` ``` cmp #\$0a ``` ``` bcs NEXT2 ``` ``` endif ``` ``` sta N2L ``` ``` lda N2 ; N2H = N2 & \$F0 ``` ``` and #\$F0 ; [2] see text ``` ``` if vld_bcd = 1 ``` ``` cmp #\$a0 ``` ``` bcs NEXT2 ``` ``` endif ``` ``` sta N2H ``` ``` ora #\$0F ; N2H+1 = (N2 & \$F0) + \$0F ``` ``` sta N2H+1 ``` ```LOOP2 lda N1 ; N1L = N1 & \$0F ``` ``` and #\$0F ; [3] see text ``` ``` if vld_bcd = 1 ``` ``` cmp #\$0a ``` ``` bcs NEXT1 ``` ``` endif ``` ``` sta N1L ``` ``` lda N1 ; N1H = N1 & \$F0 ``` ``` and #\$F0 ; [4] see text ``` ``` if vld_bcd = 1 ``` ``` cmp #\$a0 ``` ``` bcs NEXT1 ``` ``` endif ``` ``` sta N1H ``` ``` jsr ADD ``` ``` jsr A6502 ``` ``` jsr COMPARE ``` ``` bne DONE ``` ``` jsr SUB ``` ``` jsr S6502 ``` ``` jsr COMPARE ``` ``` bne DONE ``` ```NEXT1 inc N1 ; [5] see text ``` ``` bne LOOP2 ; loop through all 256 values of N1 ``` ```NEXT2 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 ``` ``` end_of_test ``` ``` ``` ```; 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 ``` ``` ``` ``` if cputype != 1 ``` ```; 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 ``` ``` endif ``` ``` ``` ``` if cputype = 1 ``` ```; 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 ``` ``` endif ``` ``` ``` ```; Compare accumulator actual results to predicted results ``` ```; ``` ```; Return: ``` ```; Z flag = 1 (BEQ branch) if same ``` ```; Z flag = 0 (BNE branch) if different ``` ```; ``` ```COMPARE ``` ``` if chk_a = 1 ``` ``` lda DA ``` ``` cmp AR ``` ``` bne C1 ``` ``` endif ``` ``` if chk_n = 1 ``` ``` lda DNVZC ; [7] see text ``` ``` eor NF ``` ``` and #\$80 ; mask off N flag ``` ``` bne C1 ``` ``` endif ``` ``` if chk_v = 1 ``` ``` lda DNVZC ; [8] see text ``` ``` eor VF ``` ``` and #\$40 ; mask off V flag ``` ``` bne C1 ; [9] see text ``` ``` endif ``` ``` if chk_z = 1 ``` ``` lda DNVZC ``` ``` eor ZF ; mask off Z flag ``` ``` and #2 ``` ``` bne C1 ; [10] see text ``` ``` endif ``` ``` if chk_c = 1 ``` ``` lda DNVZC ``` ``` eor CF ``` ``` and #1 ; mask off C flag ``` ``` endif ``` ```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 ``` ``` ``` ``` if cputype = 0 ``` ``` ``` ```A6502 lda VF ; 6502 ``` ```; ``` ```; 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 ``` ``` ``` ``` endif ``` ``` if cputype = 1 ``` ``` ``` ```A6502 lda AR ; 65C02 ``` ``` php ``` ``` pla ``` ``` sta NF ``` ``` sta ZF ``` ``` rts ``` ``` ``` ```S6502 jsr SUB2 ``` ``` lda AR ``` ``` php ``` ``` pla ``` ``` sta NF ``` ``` sta ZF ``` ``` lda HNVZC ``` ``` sta VF ``` ``` sta CF ``` ``` rts ``` ``` ``` ``` endif ``` ``` if cputype = 2 ``` ``` ``` ```A6502 lda AR ; 65C816 ``` ``` php ``` ``` pla ``` ``` sta NF ``` ``` sta ZF ``` ``` rts ``` ``` ``` ```S6502 jsr SUB1 ``` ``` lda AR ``` ``` php ``` ``` pla ``` ``` sta NF ``` ``` sta ZF ``` ``` lda HNVZC ``` ``` sta VF ``` ``` sta CF ``` ``` rts ``` ``` ``` ``` endif ``` ``` ``` ``` end TEST ```