mirror of
https://github.com/Klaus2m5/6502_65C02_functional_tests.git
synced 2024-12-14 10:32:27 +00:00
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.
This commit is contained in:
parent
d0cd6d09af
commit
54768c6dc0
355
6502_decimal_test.a65
Normal file
355
6502_decimal_test.a65
Normal file
@ -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
|
@ -21,7 +21,7 @@
|
||||
; addressing modes with focus on propper setting of the processor status
|
||||
; register bits.
|
||||
;
|
||||
; version 24-aug-2015
|
||||
; version 21-oct-2015
|
||||
; contact info at http://2m5.de or email K@2m5.de
|
||||
;
|
||||
; assembled with AS65 from http://www.kingswood-consulting.co.uk/assemblers/
|
||||
@ -72,6 +72,7 @@
|
||||
; 23-aug-2015 added option to disable self modifying tests
|
||||
; 24-aug-2015 all self modifying immediate opcodes now execute in data RAM
|
||||
; added small branch offset pretest
|
||||
; 21-oct-2015 added option to disable decimal mode ADC & SBC tests
|
||||
|
||||
|
||||
; C O N F I G U R A T I O N
|
||||
@ -120,6 +121,10 @@ report = 0
|
||||
;leave disabled if a monitor, OS or background interrupt is allowed to alter RAM
|
||||
ram_top = -1
|
||||
|
||||
;disable test decimal mode ADC & SBC, 0=enable, 1=disable,
|
||||
;2=disable including decimal flag in processor status
|
||||
disable_decimal = 0
|
||||
|
||||
noopt ;do not take shortcuts
|
||||
|
||||
;macros for error & success traps to allow user modification
|
||||
@ -244,12 +249,16 @@ fnv equ minus+overfl
|
||||
|
||||
fao equ break+reserv ;bits always on after PHP, BRK
|
||||
fai equ fao+intdis ;+ forced interrupt disable
|
||||
faod equ fao+decmode ;+ ignore decimal
|
||||
faid equ fai+decmode ;+ ignore decimal
|
||||
m8 equ $ff ;8 bit mask
|
||||
m8i equ $ff&~intdis ;8 bit mask - interrupt disable
|
||||
|
||||
;macros to allow masking of status bits.
|
||||
;masking test of decimal bit
|
||||
;masking of interrupt enable/disable on load and compare
|
||||
;masking of always on bits after PHP or BRK (unused & break) on compare
|
||||
if disable_decimal < 2
|
||||
if I_flag = 0
|
||||
load_flag macro
|
||||
lda #\1&m8i ;force enable interrupts (mask I)
|
||||
@ -298,6 +307,64 @@ eor_flag macro
|
||||
eor #\1|fao ;invert expected flags + always on bits
|
||||
endm
|
||||
endif
|
||||
else
|
||||
if I_flag = 0
|
||||
load_flag macro
|
||||
lda #\1&m8i ;force enable interrupts (mask I)
|
||||
endm
|
||||
cmp_flag macro
|
||||
ora #decmode ;ignore decimal mode bit
|
||||
cmp #(\1|faod)&m8i ;I_flag is always enabled + always on bits
|
||||
endm
|
||||
eor_flag macro
|
||||
ora #decmode ;ignore decimal mode bit
|
||||
eor #(\1&m8i|faod) ;mask I, invert expected flags + always on bits
|
||||
endm
|
||||
endif
|
||||
if I_flag = 1
|
||||
load_flag macro
|
||||
lda #\1|intdis ;force disable interrupts
|
||||
endm
|
||||
cmp_flag macro
|
||||
ora #decmode ;ignore decimal mode bit
|
||||
cmp #(\1|faid)&m8 ;I_flag is always disabled + always on bits
|
||||
endm
|
||||
eor_flag macro
|
||||
ora #decmode ;ignore decimal mode bit
|
||||
eor #(\1|faid) ;invert expected flags + always on bits + I
|
||||
endm
|
||||
endif
|
||||
if I_flag = 2
|
||||
load_flag macro
|
||||
lda #\1
|
||||
ora flag_I_on ;restore I-flag
|
||||
and flag_I_off
|
||||
endm
|
||||
cmp_flag macro
|
||||
eor flag_I_on ;I_flag is never changed
|
||||
ora #decmode ;ignore decimal mode bit
|
||||
cmp #(\1|faod)&m8i ;expected flags + always on bits, mask I
|
||||
endm
|
||||
eor_flag macro
|
||||
eor flag_I_on ;I_flag is never changed
|
||||
ora #decmode ;ignore decimal mode bit
|
||||
eor #(\1&m8i|faod) ;mask I, invert expected flags + always on bits
|
||||
endm
|
||||
endif
|
||||
if I_flag = 3
|
||||
load_flag macro
|
||||
lda #\1 ;allow test to change I-flag (no mask)
|
||||
endm
|
||||
cmp_flag macro
|
||||
ora #decmode ;ignore decimal mode bit
|
||||
cmp #(\1|faod)&m8 ;expected flags + always on bits
|
||||
endm
|
||||
eor_flag macro
|
||||
ora #decmode ;ignore decimal mode bit
|
||||
eor #\1|faod ;invert expected flags + always on bits
|
||||
endm
|
||||
endif
|
||||
endif
|
||||
|
||||
;macros to set (register|memory|zeropage) & status
|
||||
set_stat macro ;setting flags in the processor status register
|
||||
@ -501,9 +568,9 @@ ccs3\? adc zero_page,x
|
||||
clc
|
||||
ccs2\? inx
|
||||
bne ccs3\?
|
||||
ldx #hi(data_segment) ;set high byte of indirect pointer
|
||||
ldx #hi(abs1) ;set high byte of indirect pointer
|
||||
stx zpt+1
|
||||
ldy #lo(data_bss)+15 ;data after write & execute test area
|
||||
ldy #lo(abs1) ;data after write & execute test area
|
||||
ccs5\? adc (zpt),y
|
||||
bcc ccs4\?
|
||||
inc zpt+3 ;carry to high byte
|
||||
@ -764,9 +831,9 @@ gcs3 adc zero_page,x
|
||||
clc
|
||||
gcs2 inx
|
||||
bne gcs3
|
||||
ldx #hi(data_segment) ;set high byte of indirect pointer
|
||||
ldx #hi(abs1) ;set high byte of indirect pointer
|
||||
stx zpt+1
|
||||
ldy #lo(data_bss)+15 ;data after write & execute test area
|
||||
ldy #lo(abs1) ;data after write & execute test area
|
||||
gcs5 adc (zpt),y
|
||||
bcc gcs4
|
||||
inc ram_chksm+1 ;carry to high byte
|
||||
@ -4666,7 +4733,7 @@ tand1 lda zpAN,x
|
||||
bpl tand1
|
||||
|
||||
ldx #3 ;zp
|
||||
tand2 lda zpAN,x
|
||||
tand2 lda zpAN,x
|
||||
sta zpt
|
||||
set_ax absANa,0
|
||||
and zpt
|
||||
@ -5101,6 +5168,7 @@ tadd1 ora adrh ;merge C to expected flags
|
||||
lda ad2
|
||||
sta adrl
|
||||
bne tadd ;iterate op2
|
||||
if disable_decimal < 1
|
||||
next_test
|
||||
|
||||
; decimal add/subtract test
|
||||
@ -5239,7 +5307,8 @@ bin_rti_ret
|
||||
adc #$55
|
||||
cmp #$aa
|
||||
trap_ne ;expected binary result after rti D=0
|
||||
|
||||
endif
|
||||
|
||||
lda test_case
|
||||
cmp #test_num
|
||||
trap_ne ;previous test is out of sequence
|
||||
@ -5264,6 +5333,7 @@ bin_rti_ret
|
||||
; S U C C E S S ************************************************
|
||||
jmp start ;run again
|
||||
|
||||
if disable_decimal < 1
|
||||
; core subroutine of the decimal add/subtract test
|
||||
; *** WARNING - tests documented behavior only! ***
|
||||
; only valid BCD operands are tested, N V Z flags are ignored
|
||||
@ -5459,6 +5529,7 @@ chkdad
|
||||
trap_ne ;bad carry
|
||||
plp
|
||||
rts
|
||||
endif
|
||||
|
||||
; core subroutine of the full binary add/subtract test
|
||||
; iterates through all combinations of operands and carry input
|
||||
|
Loading…
Reference in New Issue
Block a user