364 lines 18 KiB Plaintext Raw Blame History

 ```AS65 Assembler for R6502 [1.42]. Copyright 1994-2007, Frank A. Kingswood Page 1 ``` ```----------------------------------------------------- 6502_decimal_test.a65 ------------------------------------------------------ ``` ``` ``` ```355 lines read, no errors in pass 1. ``` ``` ; 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: ``` ```0001 = cputype = 1 ; 0 = 6502, 1 = 65C02, 2 = 65C816 ``` ```0000 = vld_bcd = 0 ; 0 = allow invalid bcd, 1 = valid bcd only ``` ```0000 = chk_a = 0 ; check accumulator ``` ```0000 = chk_n = 0 ; check sign (negative) flag ``` ```0000 = chk_v = 0 ; check overflow flag ``` ```0000 = chk_z = 0 ; check zero flag ``` ```0001 = chk_c = 1 ; check carry flag ``` ``` ``` ``` end_of_test macro ``` ``` db \$db ;execute 65C02 stop instruction ``` ``` endm ``` ``` ``` ``` bss ``` ```0000 = org 0 ``` ``` ; operands - register Y = carry in ``` ```0000 = N1 ds 1 ``` ```0001 = N2 ds 1 ``` ``` ; binary result ``` ```0002 = HA ds 1 ``` ```0003 = HNVZC ds 1 ``` ``` ;04 ``` ``` ; decimal result ``` ```0004 = DA ds 1 ``` ```0005 = DNVZC ds 1 ``` ``` ; predicted results ``` ```0006 = AR ds 1 ``` ```0007 = NF ds 1 ``` ``` ;08 ``` ```0008 = VF ds 1 ``` ```0009 = ZF ds 1 ``` ```000a = CF ds 1 ``` ```000b = ERROR ds 1 ``` ``` ;0C ``` ``` ; workspace ``` ```000c = N1L ds 1 ``` ```000d = N1H ds 1 ``` ```000e = N2L ds 1 ``` ```000f = N2H ds 2 ``` ``` ``` ``` code ``` ```0200 = org \$200 ``` ```0200 : a001 TEST ldy #1 ; initialize Y (used to loop through carry flag values) ``` ```0202 : 840b sty ERROR ; store 1 in ERROR until the test passes ``` ```0204 : a900 lda #0 ; initialize N1 and N2 ``` ```0206 : 8500 sta N1 ``` ```0208 : 8501 sta N2 ``` ```020a : a501 LOOP1 lda N2 ; N2L = N2 & \$0F ``` ```020c : 290f and #\$0F ; [1] see text ``` ``` if vld_bcd = 1 ``` ``` cmp #\$0a ``` ``` bcs NEXT2 ``` ``` endif ``` ```020e : 850e sta N2L ``` ```0210 : a501 lda N2 ; N2H = N2 & \$F0 ``` ```0212 : 29f0 and #\$F0 ; [2] see text ``` ``` if vld_bcd = 1 ``` ``` cmp #\$a0 ``` ``` bcs NEXT2 ``` ``` endif ``` ```0214 : 850f sta N2H ``` ```0216 : 090f ora #\$0F ; N2H+1 = (N2 & \$F0) + \$0F ``` ```0218 : 8510 sta N2H+1 ``` ```021a : a500 LOOP2 lda N1 ; N1L = N1 & \$0F ``` ```021c : 290f and #\$0F ; [3] see text ``` ``` if vld_bcd = 1 ``` ``` cmp #\$0a ``` ``` bcs NEXT1 ``` ``` endif ``` ```021e : 850c sta N1L ``` ```0220 : a500 lda N1 ; N1H = N1 & \$F0 ``` ```0222 : 29f0 and #\$F0 ; [4] see text ``` ``` if vld_bcd = 1 ``` ``` cmp #\$a0 ``` ``` bcs NEXT1 ``` ``` endif ``` ```0224 : 850d sta N1H ``` ```0226 : 204102 jsr ADD ``` ```0229 : 20c602 jsr A6502 ``` ```022c : 20bf02 jsr COMPARE ``` ```022f : d00f bne DONE ``` ``` ; jsr SUB ``` ``` ; jsr S6502 ``` ``` ; jsr COMPARE ``` ``` ; bne DONE ``` ```0231 : e600 NEXT1 inc N1 ; [5] see text ``` ```0233 : d0e5 bne LOOP2 ; loop through all 256 values of N1 ``` ```0235 : e601 NEXT2 inc N2 ; [6] see text ``` ```0237 : d0d1 bne LOOP1 ; loop through all 256 values of N2 ``` ```0239 : 88 dey ``` ```023a : 10ce bpl LOOP1 ; loop through both values of the carry flag ``` ```023c : a900 lda #0 ; test passed, so store 0 in ERROR ``` ```023e : 850b sta ERROR ``` ```0240 : DONE ``` ``` end_of_test ``` ```0240 : db > db \$db ;execute 65C02 stop instruction ``` ``` ``` ``` ``` ``` ; 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 ``` ``` ; ``` ```0241 : f8 ADD sed ; decimal mode ``` ```0242 : c001 cpy #1 ; set carry if Y = 1, clear carry if Y = 0 ``` ```0244 : a500 lda N1 ``` ```0246 : 6501 adc N2 ``` ```0248 : 8504 sta DA ; actual accumulator result in decimal mode ``` ```024a : 08 php ``` ```024b : 68 pla ``` ```024c : 8505 sta DNVZC ; actual flags result in decimal mode ``` ```024e : d8 cld ; binary mode ``` ```024f : c001 cpy #1 ; set carry if Y = 1, clear carry if Y = 0 ``` ```0251 : a500 lda N1 ``` ```0253 : 6501 adc N2 ``` ```0255 : 8502 sta HA ; accumulator result of N1+N2 using binary arithmetic ``` ``` ``` ```0257 : 08 php ``` ```0258 : 68 pla ``` ```0259 : 8503 sta HNVZC ; flags result of N1+N2 using binary arithmetic ``` ```025b : c001 cpy #1 ``` ```025d : a50c lda N1L ``` ```025f : 650e adc N2L ``` ```0261 : c90a cmp #\$0A ``` ```0263 : a200 ldx #0 ``` ```0265 : 9006 bcc A1 ``` ```0267 : e8 inx ``` ```0268 : 6905 adc #5 ; add 6 (carry is set) ``` ```026a : 290f and #\$0F ``` ```026c : 38 sec ``` ```026d : 050d A1 ora N1H ``` ``` ; ``` ``` ; if N1L + N2L < \$0A, then add N2 & \$F0 ``` ``` ; if N1L + N2L >= \$0A, then add (N2 & \$F0) + \$0F + 1 (carry is set) ``` ``` ; ``` ```026f : 750f adc N2H,x ``` ```0271 : 08 php ``` ```0272 : b004 bcs A2 ``` ```0274 : c9a0 cmp #\$A0 ``` ```0276 : 9003 bcc A3 ``` ```0278 : 695f A2 adc #\$5F ; add \$60 (carry is set) ``` ```027a : 38 sec ``` ```027b : 8506 A3 sta AR ; predicted accumulator result ``` ```027d : 08 php ``` ```027e : 68 pla ``` ```027f : 850a sta CF ; predicted carry result ``` ```0281 : 68 pla ``` ``` ; ``` ``` ; note that all 8 bits of the P register are stored in VF ``` ``` ; ``` ```0282 : 8508 sta VF ; predicted V flags ``` ```0284 : 60 rts ``` ``` ``` ``` ; Calculate the actual decimal mode accumulator and flags, and the ``` ``` ; accumulator and flag results when N2 is subtracted from N1 using binary ``` ``` ; arithmetic ``` ``` ; ``` ```0285 : f8 SUB sed ; decimal mode ``` ```0286 : c001 cpy #1 ; set carry if Y = 1, clear carry if Y = 0 ``` ```0288 : a500 lda N1 ``` ```028a : e501 sbc N2 ``` ```028c : 8504 sta DA ; actual accumulator result in decimal mode ``` ```028e : 08 php ``` ```028f : 68 pla ``` ```0290 : 8505 sta DNVZC ; actual flags result in decimal mode ``` ```0292 : d8 cld ; binary mode ``` ```0293 : c001 cpy #1 ; set carry if Y = 1, clear carry if Y = 0 ``` ```0295 : a500 lda N1 ``` ```0297 : e501 sbc N2 ``` ```0299 : 8502 sta HA ; accumulator result of N1-N2 using binary arithmetic ``` ``` ``` ```029b : 08 php ``` ```029c : 68 pla ``` ```029d : 8503 sta HNVZC ; flags result of N1-N2 using binary arithmetic ``` ```029f : 60 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 ``` ``` ; ``` ```02a0 : c001 SUB2 cpy #1 ; set carry if Y = 1, clear carry if Y = 0 ``` ```02a2 : a50c lda N1L ``` ```02a4 : e50e sbc N2L ``` ```02a6 : a200 ldx #0 ``` ```02a8 : b004 bcs S21 ``` ```02aa : e8 inx ``` ```02ab : 290f and #\$0F ``` ```02ad : 18 clc ``` ```02ae : 050d S21 ora N1H ``` ``` ; ``` ``` ; if N1L - N2L >= 0, then subtract N2 & \$F0 ``` ``` ; if N1L - N2L < 0, then subtract (N2 & \$F0) + \$0F + 1 (carry is clear) ``` ``` ; ``` ```02b0 : f50f sbc N2H,x ``` ```02b2 : b002 bcs S22 ``` ```02b4 : e95f sbc #\$5F ; subtract \$60 (carry is clear) ``` ```02b6 : e000 S22 cpx #0 ``` ```02b8 : f002 beq S23 ``` ```02ba : e906 sbc #6 ``` ```02bc : 8506 S23 sta AR ; predicted accumulator result ``` ```02be : 60 rts ``` ``` endif ``` ``` ``` ``` ; Compare accumulator actual results to predicted results ``` ``` ; ``` ``` ; Return: ``` ``` ; Z flag = 1 (BEQ branch) if same ``` ``` ; Z flag = 0 (BNE branch) if different ``` ``` ; ``` ```02bf : 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 ``` ```02bf : a505 lda DNVZC ``` ```02c1 : 450a eor CF ``` ```02c3 : 2901 and #1 ; mask off C flag ``` ``` endif ``` ```02c5 : 60 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 ``` ``` ``` ```02c6 : a506 A6502 lda AR ; 65C02 ``` ```02c8 : 08 php ``` ```02c9 : 68 pla ``` ```02ca : 8507 sta NF ``` ```02cc : 8509 sta ZF ``` ```02ce : 60 rts ``` ``` ``` ```02cf : 20a002 S6502 jsr SUB2 ``` ```02d2 : a506 lda AR ``` ```02d4 : 08 php ``` ```02d5 : 68 pla ``` ```02d6 : 8507 sta NF ``` ```02d8 : 8509 sta ZF ``` ```02da : a503 lda HNVZC ``` ```02dc : 8508 sta VF ``` ```02de : 850a sta CF ``` ```02e0 : 60 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 ``` ``` ``` ```02cf = end TEST ``` ``` ``` ```No errors in pass 2. ```