Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added config switch to disable decimal mode tests
decimal mode tests can be disabled for the ADC & SBC instructions or also including the decimal mode bit of the processor status register.
- Loading branch information
Showing
2 changed files
with
433 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,355 @@ | ||
; 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 = 0 ; 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 = 1 ; 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 |
Oops, something went wrong.