mirror of
https://github.com/Klaus2m5/6502_65C02_functional_tests.git
synced 2024-12-22 03:30:57 +00:00
d0cd6d09af
self modifying immediate opcodes now execute in data RAM. the remaining self modifying branch range test is supplemented by an early pretest to check for correct relative addressing.
2754 lines
74 KiB
Plaintext
2754 lines
74 KiB
Plaintext
;
|
|
; 6 5 C 0 2 E X T E N D E D O P C O D E S T E S T
|
|
;
|
|
; Copyright (C) 2013-2015 Klaus Dormann
|
|
;
|
|
; This program is free software: you can redistribute it and/or modify
|
|
; it under the terms of the GNU General Public License as published by
|
|
; the Free Software Foundation, either version 3 of the License, or
|
|
; (at your option) any later version.
|
|
;
|
|
; This program is distributed in the hope that it will be useful,
|
|
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
; GNU General Public License for more details.
|
|
;
|
|
; You should have received a copy of the GNU General Public License
|
|
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
; This program is designed to test all additional 65C02 opcodes, addressing
|
|
; modes and functionality not available in the NMOS version of the 6502.
|
|
; The 6502_functional_test is a prerequisite to this test.
|
|
; NMI, IRQ, BRK, STP & WAI are covered in the 6502_interrupt_test.
|
|
;
|
|
; version 24-aug-2015
|
|
; contact info at http://2m5.de or email K@2m5.de
|
|
;
|
|
; assembled with AS65 from http://www.kingswood-consulting.co.uk/assemblers/
|
|
; command line switches: -l -m -s2 -w -x -h0
|
|
; | | | | | no page headers in listing
|
|
; | | | | 65C02 extensions
|
|
; | | | wide listing (133 char/col)
|
|
; | | write intel hex file instead of binary
|
|
; | expand macros in listing
|
|
; generate pass2 listing
|
|
;
|
|
; No IO - should be run from a monitor with access to registers.
|
|
; To run load intel hex image with a load command, than alter PC to 400 hex
|
|
; (code_segment) and enter a go command.
|
|
; Loop on program counter determines error or successful completion of test.
|
|
; Check listing for relevant traps (jump/branch *).
|
|
; Please note that in early tests some instructions will have to be used before
|
|
; they are actually tested!
|
|
;
|
|
; RESET, NMI or IRQ should not occur and will be trapped if vectors are enabled.
|
|
; Tests documented behavior of the original 65C02 only!
|
|
; Decimal ops will only be tested with valid BCD operands and the V flag will
|
|
; be ignored as it is absolutely useless in decimal mode.
|
|
;
|
|
; Debugging hints:
|
|
; Most of the code is written sequentially. if you hit a trap, check the
|
|
; immediately preceeding code for the instruction to be tested. Results are
|
|
; tested first, flags are checked second by pushing them onto the stack and
|
|
; pulling them to the accumulator after the result was checked. The "real"
|
|
; flags are no longer valid for the tested instruction at this time!
|
|
; If the tested instruction was indexed, the relevant index (X or Y) must
|
|
; also be checked. Opposed to the flags, X and Y registers are still valid.
|
|
;
|
|
; versions:
|
|
; 19-jul-2013 1st version distributed for testing
|
|
; 23-jul-2013 fixed BRA out of range due to larger trap macros
|
|
; added RAM integrity check
|
|
; 16-aug-2013 added error report to standard output option
|
|
; 23-aug-2015 change revoked
|
|
; 24-aug-2015 all self modifying immediate opcodes now execute in data RAM
|
|
|
|
|
|
; C O N F I G U R A T I O N
|
|
|
|
;ROM_vectors writable (0=no, 1=yes)
|
|
;if ROM vectors can not be used interrupts will not be trapped
|
|
;as a consequence BRK can not be tested but will be emulated to test RTI
|
|
ROM_vectors = 1
|
|
|
|
;load_data_direct (0=move from code segment, 1=load directly)
|
|
;loading directly is preferred but may not be supported by your platform
|
|
;0 produces only consecutive object code, 1 is not suitable for a binary image
|
|
load_data_direct = 1
|
|
|
|
;I_flag behavior (0=force enabled, 1=force disabled, 2=prohibit change, 3=allow
|
|
;change) 2 requires extra code and is not recommended.
|
|
I_flag = 3
|
|
|
|
;configure memory - try to stay away from memory used by the system
|
|
;zero_page memory start address, $4e (78) consecutive Bytes required
|
|
; add 2 if I_flag = 2
|
|
zero_page = $a
|
|
|
|
;data_segment memory start address, $63 (99) consecutive Bytes required
|
|
; + 12 Bytes at data_segment + $f9 (JMP indirect page cross test)
|
|
data_segment = $200
|
|
if (data_segment & $ff) != 0
|
|
ERROR ERROR ERROR low byte of data_segment MUST be $00 !!
|
|
endif
|
|
|
|
;code_segment memory start address, 10kB of consecutive space required
|
|
; add 1 kB if I_flag = 2
|
|
code_segment = $400
|
|
|
|
;added WDC only opcodes WAI & STP (0=test as NOPs, >0=no test)
|
|
wdc_op = 1
|
|
|
|
;added Rockwell & WDC opcodes BBR, BBS, RMB & SMB
|
|
;(0=test as NOPs, 1=full test, >1=no test)
|
|
rkwl_wdc_op = 1
|
|
|
|
;report errors through I/O channel (0=use standard self trap loops, 1=include
|
|
;report.i65 as I/O channel, add 3 kB)
|
|
report = 0
|
|
|
|
;RAM integrity test option. Checks for undesired RAM writes.
|
|
;set lowest non RAM or RAM mirror address page (-1=disable, 0=64k, $40=16k)
|
|
;leave disabled if a monitor, OS or background interrupt is allowed to alter RAM
|
|
ram_top = -1
|
|
|
|
noopt ;do not take shortcuts
|
|
|
|
;macros for error & success traps to allow user modification
|
|
;example:
|
|
;trap macro
|
|
; jsr my_error_handler
|
|
; endm
|
|
;trap_eq macro
|
|
; bne skip\?
|
|
; trap ;failed equal (zero)
|
|
;skip\?
|
|
; endm
|
|
;
|
|
; my_error_handler should pop the calling address from the stack and report it.
|
|
; putting larger portions of code (more than 3 bytes) inside the trap macro
|
|
; may lead to branch range problems for some tests.
|
|
if report = 0
|
|
trap macro
|
|
jmp * ;failed anyway
|
|
endm
|
|
trap_eq macro
|
|
beq * ;failed equal (zero)
|
|
endm
|
|
trap_ne macro
|
|
bne * ;failed not equal (non zero)
|
|
endm
|
|
trap_cs macro
|
|
bcs * ;failed carry set
|
|
endm
|
|
trap_cc macro
|
|
bcc * ;failed carry clear
|
|
endm
|
|
trap_mi macro
|
|
bmi * ;failed minus (bit 7 set)
|
|
endm
|
|
trap_pl macro
|
|
bpl * ;failed plus (bit 7 clear)
|
|
endm
|
|
trap_vs macro
|
|
bvs * ;failed overflow set
|
|
endm
|
|
trap_vc macro
|
|
bvc * ;failed overflow clear
|
|
endm
|
|
; please observe that during the test the stack gets invalidated
|
|
; therefore a RTS inside the success macro is not possible
|
|
success macro
|
|
jmp * ;test passed, no errors
|
|
endm
|
|
endif
|
|
if report = 1
|
|
trap macro
|
|
jsr report_error
|
|
endm
|
|
trap_eq macro
|
|
bne skip\?
|
|
trap ;failed equal (zero)
|
|
skip\?
|
|
endm
|
|
trap_ne macro
|
|
beq skip\?
|
|
trap ;failed not equal (non zero)
|
|
skip\?
|
|
endm
|
|
trap_cs macro
|
|
bcc skip\?
|
|
trap ;failed carry set
|
|
skip\?
|
|
endm
|
|
trap_cc macro
|
|
bcs skip\?
|
|
trap ;failed carry clear
|
|
skip\?
|
|
endm
|
|
trap_mi macro
|
|
bpl skip\?
|
|
trap ;failed minus (bit 7 set)
|
|
skip\?
|
|
endm
|
|
trap_pl macro
|
|
bmi skip\?
|
|
trap ;failed plus (bit 7 clear)
|
|
skip\?
|
|
endm
|
|
trap_vs macro
|
|
bvc skip\?
|
|
trap ;failed overflow set
|
|
skip\?
|
|
endm
|
|
trap_vc macro
|
|
bvs skip\?
|
|
trap ;failed overflow clear
|
|
skip\?
|
|
endm
|
|
; please observe that during the test the stack gets invalidated
|
|
; therefore a RTS inside the success macro is not possible
|
|
success macro
|
|
jsr report_success
|
|
endm
|
|
endif
|
|
|
|
|
|
carry equ %00000001 ;flag bits in status
|
|
zero equ %00000010
|
|
intdis equ %00000100
|
|
decmode equ %00001000
|
|
break equ %00010000
|
|
reserv equ %00100000
|
|
overfl equ %01000000
|
|
minus equ %10000000
|
|
|
|
fc equ carry
|
|
fz equ zero
|
|
fzc equ carry+zero
|
|
fv equ overfl
|
|
fvz equ overfl+zero
|
|
fn equ minus
|
|
fnc equ minus+carry
|
|
fnz equ minus+zero
|
|
fnzc equ minus+zero+carry
|
|
fnv equ minus+overfl
|
|
|
|
fao equ break+reserv ;bits always on after PHP, BRK
|
|
fai equ fao+intdis ;+ forced interrupt disable
|
|
m8 equ $ff ;8 bit mask
|
|
m8i equ $ff&~intdis ;8 bit mask - interrupt disable
|
|
|
|
;macros to allow masking of status bits.
|
|
;masking of interrupt enable/disable on load and compare
|
|
;masking of always on bits after PHP or BRK (unused & break) on compare
|
|
if I_flag = 0
|
|
load_flag macro
|
|
lda #\1&m8i ;force enable interrupts (mask I)
|
|
endm
|
|
cmp_flag macro
|
|
cmp #(\1|fao)&m8i ;I_flag is always enabled + always on bits
|
|
endm
|
|
eor_flag macro
|
|
eor #(\1&m8i|fao) ;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
|
|
cmp #(\1|fai)&m8 ;I_flag is always disabled + always on bits
|
|
endm
|
|
eor_flag macro
|
|
eor #(\1|fai) ;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
|
|
cmp #(\1|fao)&m8i ;expected flags + always on bits, mask I
|
|
endm
|
|
eor_flag macro
|
|
eor flag_I_on ;I_flag is never changed
|
|
eor #(\1&m8i|fao) ;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
|
|
cmp #(\1|fao)&m8 ;expected flags + always on bits
|
|
endm
|
|
eor_flag macro
|
|
eor #\1|fao ;invert expected flags + always on bits
|
|
endm
|
|
endif
|
|
|
|
;macros to set (register|memory|zeropage) & status
|
|
set_stat macro ;setting flags in the processor status register
|
|
load_flag \1
|
|
pha ;use stack to load status
|
|
plp
|
|
endm
|
|
|
|
set_a macro ;precharging accu & status
|
|
load_flag \2
|
|
pha ;use stack to load status
|
|
lda #\1 ;precharge accu
|
|
plp
|
|
endm
|
|
|
|
set_x macro ;precharging index & status
|
|
load_flag \2
|
|
pha ;use stack to load status
|
|
ldx #\1 ;precharge index x
|
|
plp
|
|
endm
|
|
|
|
set_y macro ;precharging index & status
|
|
load_flag \2
|
|
pha ;use stack to load status
|
|
ldy #\1 ;precharge index y
|
|
plp
|
|
endm
|
|
|
|
set_ax macro ;precharging indexed accu & immediate status
|
|
load_flag \2
|
|
pha ;use stack to load status
|
|
lda \1,x ;precharge accu
|
|
plp
|
|
endm
|
|
|
|
set_ay macro ;precharging indexed accu & immediate status
|
|
load_flag \2
|
|
pha ;use stack to load status
|
|
lda \1,y ;precharge accu
|
|
plp
|
|
endm
|
|
|
|
set_z macro ;precharging indexed zp & immediate status
|
|
load_flag \2
|
|
pha ;use stack to load status
|
|
lda \1,x ;load to zeropage
|
|
sta zpt
|
|
plp
|
|
endm
|
|
|
|
set_zx macro ;precharging zp,x & immediate status
|
|
load_flag \2
|
|
pha ;use stack to load status
|
|
lda \1,x ;load to indexed zeropage
|
|
sta zpt,x
|
|
plp
|
|
endm
|
|
|
|
set_abs macro ;precharging indexed memory & immediate status
|
|
load_flag \2
|
|
pha ;use stack to load status
|
|
lda \1,x ;load to memory
|
|
sta abst
|
|
plp
|
|
endm
|
|
|
|
set_absx macro ;precharging abs,x & immediate status
|
|
load_flag \2
|
|
pha ;use stack to load status
|
|
lda \1,x ;load to indexed memory
|
|
sta abst,x
|
|
plp
|
|
endm
|
|
|
|
;macros to test (register|memory|zeropage) & status & (mask)
|
|
tst_stat macro ;testing flags in the processor status register
|
|
php ;save status
|
|
pla ;use stack to retrieve status
|
|
pha
|
|
cmp_flag \1
|
|
trap_ne
|
|
plp ;restore status
|
|
endm
|
|
|
|
tst_a macro ;testing result in accu & flags
|
|
php ;save flags
|
|
cmp #\1 ;test result
|
|
trap_ne
|
|
pla ;load status
|
|
pha
|
|
cmp_flag \2
|
|
trap_ne
|
|
plp ;restore status
|
|
endm
|
|
|
|
tst_as macro ;testing result in accu & flags, save accu
|
|
pha
|
|
php ;save flags
|
|
cmp #\1 ;test result
|
|
trap_ne
|
|
pla ;load status
|
|
pha
|
|
cmp_flag \2
|
|
trap_ne
|
|
plp ;restore status
|
|
pla
|
|
endm
|
|
|
|
tst_x macro ;testing result in x index & flags
|
|
php ;save flags
|
|
cpx #\1 ;test result
|
|
trap_ne
|
|
pla ;load status
|
|
pha
|
|
cmp_flag \2
|
|
trap_ne
|
|
plp ;restore status
|
|
endm
|
|
|
|
tst_y macro ;testing result in y index & flags
|
|
php ;save flags
|
|
cpy #\1 ;test result
|
|
trap_ne
|
|
pla ;load status
|
|
pha
|
|
cmp_flag \2
|
|
trap_ne
|
|
plp ;restore status
|
|
endm
|
|
|
|
tst_ax macro ;indexed testing result in accu & flags
|
|
php ;save flags
|
|
cmp \1,x ;test result
|
|
trap_ne
|
|
pla ;load status
|
|
eor_flag \3
|
|
cmp \2,x ;test flags
|
|
trap_ne ;
|
|
endm
|
|
|
|
tst_ay macro ;indexed testing result in accu & flags
|
|
php ;save flags
|
|
cmp \1,y ;test result
|
|
trap_ne ;
|
|
pla ;load status
|
|
eor_flag \3
|
|
cmp \2,y ;test flags
|
|
trap_ne
|
|
endm
|
|
|
|
tst_z macro ;indexed testing result in zp & flags
|
|
php ;save flags
|
|
lda zpt
|
|
cmp \1,x ;test result
|
|
trap_ne
|
|
pla ;load status
|
|
eor_flag \3
|
|
cmp \2,x ;test flags
|
|
trap_ne
|
|
endm
|
|
|
|
tst_zx macro ;testing result in zp,x & flags
|
|
php ;save flags
|
|
lda zpt,x
|
|
cmp \1,x ;test result
|
|
trap_ne
|
|
pla ;load status
|
|
eor_flag \3
|
|
cmp \2,x ;test flags
|
|
trap_ne
|
|
endm
|
|
|
|
tst_abs macro ;indexed testing result in memory & flags
|
|
php ;save flags
|
|
lda abst
|
|
cmp \1,x ;test result
|
|
trap_ne
|
|
pla ;load status
|
|
eor_flag \3
|
|
cmp \2,x ;test flags
|
|
trap_ne
|
|
endm
|
|
|
|
tst_absx macro ;testing result in abs,x & flags
|
|
php ;save flags
|
|
lda abst,x
|
|
cmp \1,x ;test result
|
|
trap_ne
|
|
pla ;load status
|
|
eor_flag \3
|
|
cmp \2,x ;test flags
|
|
trap_ne
|
|
endm
|
|
|
|
; RAM integrity test
|
|
; verifies that none of the previous tests has altered RAM outside of the
|
|
; designated write areas.
|
|
; uses zpt word as indirect pointer, zpt+2 word as checksum
|
|
if ram_top > -1
|
|
check_ram macro
|
|
cld
|
|
lda #0
|
|
sta zpt ;set low byte of indirect pointer
|
|
sta zpt+3 ;checksum high byte
|
|
ldx #11 ;reset modifiable RAM
|
|
ccs1\? sta jxi_tab,x ;JMP indirect page cross area
|
|
dex
|
|
bpl ccs1\?
|
|
clc
|
|
ldx #zp_bss-zero_page ;zeropage - write test area
|
|
ccs3\? adc zero_page,x
|
|
bcc ccs2\?
|
|
inc zpt+3 ;carry to high byte
|
|
clc
|
|
ccs2\? inx
|
|
bne ccs3\?
|
|
ldx #hi(data_segment) ;set high byte of indirect pointer
|
|
stx zpt+1
|
|
ldy #lo(data_bss)+6 ;data after write & execute test area
|
|
ccs5\? adc (zpt),y
|
|
bcc ccs4\?
|
|
inc zpt+3 ;carry to high byte
|
|
clc
|
|
ccs4\? iny
|
|
bne ccs5\?
|
|
inx ;advance RAM high address
|
|
stx zpt+1
|
|
cpx #ram_top
|
|
bne ccs5\?
|
|
sta zpt+2 ;checksum low is
|
|
cmp ram_chksm ;checksum low expected
|
|
trap_ne ;checksum mismatch
|
|
lda zpt+3 ;checksum high is
|
|
cmp ram_chksm+1 ;checksum high expected
|
|
trap_ne ;checksum mismatch
|
|
endm
|
|
else
|
|
check_ram macro
|
|
;RAM check disabled - RAM size not set
|
|
endm
|
|
endif
|
|
|
|
next_test macro ;make sure, tests don't jump the fence
|
|
lda test_case ;previous test
|
|
cmp #test_num
|
|
trap_ne ;test is out of sequence
|
|
test_num = test_num + 1
|
|
lda #test_num ;*** next tests' number
|
|
sta test_case
|
|
;check_ram ;uncomment to find altered RAM after each test
|
|
endm
|
|
|
|
if load_data_direct = 1
|
|
data
|
|
else
|
|
bss ;uninitialized segment, copy of data at end of code!
|
|
endif
|
|
org zero_page
|
|
if I_flag = 2
|
|
;masking for I bit in status
|
|
flag_I_on ds 1 ;or mask to load flags
|
|
flag_I_off ds 1 ;and mask to load flags
|
|
endif
|
|
zpt ;5 bytes store/modify test area
|
|
;add/subtract operand generation and result/flag prediction
|
|
adfc ds 1 ;carry flag before op
|
|
ad1 ds 1 ;operand 1 - accumulator
|
|
ad2 ds 1 ;operand 2 - memory / immediate
|
|
adrl ds 1 ;expected result bits 0-7
|
|
adrh ds 1 ;expected result bit 8 (carry)
|
|
adrf ds 1 ;expected flags NV0000ZC (-V in decimal mode)
|
|
sb2 ds 1 ;operand 2 complemented for subtract
|
|
zp_bss
|
|
zp1 db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
|
|
zp7f db $7f ;test pattern for compare
|
|
;logical zeropage operands
|
|
zpOR db 0,$1f,$71,$80 ;test pattern for OR
|
|
zpAN db $0f,$ff,$7f,$80 ;test pattern for AND
|
|
zpEO db $ff,$0f,$8f,$8f ;test pattern for EOR
|
|
;indirect addressing pointers
|
|
ind1 dw abs1 ;indirect pointer to pattern in absolute memory
|
|
dw abs1+1
|
|
dw abs1+2
|
|
dw abs1+3
|
|
dw abs7f
|
|
inw1 dw abs1-$f8 ;indirect pointer for wrap-test pattern
|
|
indt dw abst ;indirect pointer to store area in absolute memory
|
|
dw abst+1
|
|
dw abst+2
|
|
dw abst+3
|
|
inwt dw abst-$f8 ;indirect pointer for wrap-test store
|
|
indAN dw absAN ;indirect pointer to AND pattern in absolute memory
|
|
dw absAN+1
|
|
dw absAN+2
|
|
dw absAN+3
|
|
indEO dw absEO ;indirect pointer to EOR pattern in absolute memory
|
|
dw absEO+1
|
|
dw absEO+2
|
|
dw absEO+3
|
|
indOR dw absOR ;indirect pointer to OR pattern in absolute memory
|
|
dw absOR+1
|
|
dw absOR+2
|
|
dw absOR+3
|
|
;add/subtract indirect pointers
|
|
adi2 dw ada2 ;indirect pointer to operand 2 in absolute memory
|
|
sbi2 dw sba2 ;indirect pointer to complemented operand 2 (SBC)
|
|
adiy2 dw ada2-$ff ;with offset for indirect indexed
|
|
sbiy2 dw sba2-$ff
|
|
zp_bss_end
|
|
|
|
org data_segment
|
|
pg_x ds 2 ;high JMP indirect address for page cross bug
|
|
test_case ds 1 ;current test number
|
|
ram_chksm ds 2 ;checksum for RAM integrity test
|
|
;add/subtract operand copy - abs tests write area
|
|
abst ;5 bytes store/modify test area
|
|
ada2 ds 1 ;operand 2
|
|
sba2 ds 1 ;operand 2 complemented for subtract
|
|
ds 3 ;fill remaining bytes
|
|
data_bss
|
|
if load_data_direct = 1
|
|
ex_adci adc #0 ;execute immediate opcodes
|
|
rts
|
|
ex_sbci sbc #0 ;execute immediate opcodes
|
|
rts
|
|
else
|
|
ex_adci ds 3
|
|
ex_sbci ds 3
|
|
endif
|
|
abs1 db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
|
|
abs7f db $7f ;test pattern for compare
|
|
;loads
|
|
fLDx db fn,fn,0,fz ;expected flags for load
|
|
;shifts
|
|
rASL ;expected result ASL & ROL -carry
|
|
rROL db $86,$04,$82,0 ; "
|
|
rROLc db $87,$05,$83,1 ;expected result ROL +carry
|
|
rLSR ;expected result LSR & ROR -carry
|
|
rROR db $61,$41,$20,0 ; "
|
|
rRORc db $e1,$c1,$a0,$80 ;expected result ROR +carry
|
|
fASL ;expected flags for shifts
|
|
fROL db fnc,fc,fn,fz ;no carry in
|
|
fROLc db fnc,fc,fn,0 ;carry in
|
|
fLSR
|
|
fROR db fc,0,fc,fz ;no carry in
|
|
fRORc db fnc,fn,fnc,fn ;carry in
|
|
;increments (decrements)
|
|
rINC db $7f,$80,$ff,0,1 ;expected result for INC/DEC
|
|
fINC db 0,fn,fn,fz,0 ;expected flags for INC/DEC
|
|
;logical memory operand
|
|
absOR db 0,$1f,$71,$80 ;test pattern for OR
|
|
absAN db $0f,$ff,$7f,$80 ;test pattern for AND
|
|
absEO db $ff,$0f,$8f,$8f ;test pattern for EOR
|
|
;logical accu operand
|
|
absORa db 0,$f1,$1f,0 ;test pattern for OR
|
|
absANa db $f0,$ff,$ff,$ff ;test pattern for AND
|
|
absEOa db $ff,$f0,$f0,$0f ;test pattern for EOR
|
|
;logical results
|
|
absrlo db 0,$ff,$7f,$80
|
|
absflo db fz,fn,0,fn
|
|
data_bss_end
|
|
;define area for page crossing JMP (abs) & JMP (abs,x) test
|
|
jxi_tab equ data_segment + $100 - 7 ;JMP (jxi_tab,x) x=6
|
|
ji_tab equ data_segment + $100 - 3 ;JMP (ji_tab+2)
|
|
jxp_tab equ data_segment + $100 ;JMP (jxp_tab-255) x=255
|
|
|
|
|
|
code
|
|
org code_segment
|
|
start cld
|
|
ldx #$ff
|
|
txs
|
|
lda #0 ;*** test 0 = initialize
|
|
sta test_case
|
|
test_num = 0
|
|
|
|
;stop interrupts before initializing BSS
|
|
if I_flag = 1
|
|
sei
|
|
endif
|
|
|
|
;initialize I/O for report channel
|
|
if report = 1
|
|
jsr report_init
|
|
endif
|
|
|
|
;initialize BSS segment
|
|
if load_data_direct != 1
|
|
ldx #zp_end-zp_init-1
|
|
ld_zp lda zp_init,x
|
|
sta zp_bss,x
|
|
dex
|
|
bpl ld_zp
|
|
ldx #data_end-data_init-1
|
|
ld_data lda data_init,x
|
|
sta data_bss,x
|
|
dex
|
|
bpl ld_data
|
|
if ROM_vectors = 1
|
|
ldx #5
|
|
ld_vect lda vec_init,x
|
|
sta vec_bss,x
|
|
dex
|
|
bpl ld_vect
|
|
endif
|
|
endif
|
|
|
|
;retain status of interrupt flag
|
|
if I_flag = 2
|
|
php
|
|
pla
|
|
and #4 ;isolate flag
|
|
sta flag_I_on ;or mask
|
|
eor #lo(~4) ;reverse
|
|
sta flag_I_off ;and mask
|
|
endif
|
|
|
|
;generate checksum for RAM integrity test
|
|
if ram_top > -1
|
|
lda #0
|
|
sta zpt ;set low byte of indirect pointer
|
|
sta ram_chksm+1 ;checksum high byte
|
|
ldx #11 ;reset modifiable RAM
|
|
gcs1 sta jxi_tab,x ;JMP indirect page cross area
|
|
dex
|
|
bpl gcs1
|
|
clc
|
|
ldx #zp_bss-zero_page ;zeropage - write test area
|
|
gcs3 adc zero_page,x
|
|
bcc gcs2
|
|
inc ram_chksm+1 ;carry to high byte
|
|
clc
|
|
gcs2 inx
|
|
bne gcs3
|
|
ldx #hi(data_segment) ;set high byte of indirect pointer
|
|
stx zpt+1
|
|
ldy #lo(data_bss)+6 ;data after write & execute test area
|
|
gcs5 adc (zpt),y
|
|
bcc gcs4
|
|
inc ram_chksm+1 ;carry to high byte
|
|
clc
|
|
gcs4 iny
|
|
bne gcs5
|
|
inx ;advance RAM high address
|
|
stx zpt+1
|
|
cpx #ram_top
|
|
bne gcs5
|
|
sta ram_chksm ;checksum complete
|
|
endif
|
|
next_test
|
|
|
|
;testing stack operations PHX PHY PLX PLY
|
|
lda #$99 ;protect a
|
|
ldx #$ff ;initialize stack
|
|
txs
|
|
ldx #$55
|
|
phx
|
|
ldx #$aa
|
|
phx
|
|
cpx $1fe ;on stack ?
|
|
trap_ne
|
|
tsx
|
|
cpx #$fd ;sp decremented?
|
|
trap_ne
|
|
ply
|
|
cpy #$aa ;successful retreived from stack?
|
|
trap_ne
|
|
ply
|
|
cpy #$55
|
|
trap_ne
|
|
cpy $1ff ;remains on stack?
|
|
trap_ne
|
|
tsx
|
|
cpx #$ff ;sp incremented?
|
|
trap_ne
|
|
|
|
ldy #$a5
|
|
phy
|
|
ldy #$5a
|
|
phy
|
|
cpy $1fe ;on stack ?
|
|
trap_ne
|
|
tsx
|
|
cpx #$fd ;sp decremented?
|
|
trap_ne
|
|
plx
|
|
cpx #$5a ;successful retreived from stack?
|
|
trap_ne
|
|
plx
|
|
cpx #$a5
|
|
trap_ne
|
|
cpx $1ff ;remains on stack?
|
|
trap_ne
|
|
tsx
|
|
cpx #$ff ;sp incremented?
|
|
trap_ne
|
|
cmp #$99 ;unchanged?
|
|
trap_ne
|
|
next_test
|
|
|
|
; test PHX does not alter flags or X but PLX does
|
|
ldy #$aa ;protect y
|
|
set_x 1,$ff ;push
|
|
phx
|
|
tst_x 1,$ff
|
|
set_x 0,0
|
|
phx
|
|
tst_x 0,0
|
|
set_x $ff,$ff
|
|
phx
|
|
tst_x $ff,$ff
|
|
set_x 1,0
|
|
phx
|
|
tst_x 1,0
|
|
set_x 0,$ff
|
|
phx
|
|
tst_x 0,$ff
|
|
set_x $ff,0
|
|
phx
|
|
tst_x $ff,0
|
|
set_x 0,$ff ;pull
|
|
plx
|
|
tst_x $ff,$ff-zero
|
|
set_x $ff,0
|
|
plx
|
|
tst_x 0,zero
|
|
set_x $fe,$ff
|
|
plx
|
|
tst_x 1,$ff-zero-minus
|
|
set_x 0,0
|
|
plx
|
|
tst_x $ff,minus
|
|
set_x $ff,$ff
|
|
plx
|
|
tst_x 0,$ff-minus
|
|
set_x $fe,0
|
|
plx
|
|
tst_x 1,0
|
|
cpy #$aa ;Y unchanged
|
|
trap_ne
|
|
next_test
|
|
|
|
; test PHY does not alter flags or Y but PLY does
|
|
ldx #$55 ;x & a protected
|
|
set_y 1,$ff ;push
|
|
phy
|
|
tst_y 1,$ff
|
|
set_y 0,0
|
|
phy
|
|
tst_y 0,0
|
|
set_y $ff,$ff
|
|
phy
|
|
tst_y $ff,$ff
|
|
set_y 1,0
|
|
phy
|
|
tst_y 1,0
|
|
set_y 0,$ff
|
|
phy
|
|
tst_y 0,$ff
|
|
set_y $ff,0
|
|
phy
|
|
tst_y $ff,0
|
|
set_y 0,$ff ;pull
|
|
ply
|
|
tst_y $ff,$ff-zero
|
|
set_y $ff,0
|
|
ply
|
|
tst_y 0,zero
|
|
set_y $fe,$ff
|
|
ply
|
|
tst_y 1,$ff-zero-minus
|
|
set_y 0,0
|
|
ply
|
|
tst_y $ff,minus
|
|
set_y $ff,$ff
|
|
ply
|
|
tst_y 0,$ff-minus
|
|
set_y $fe,0
|
|
ply
|
|
tst_y 1,0
|
|
cpx #$55 ;x unchanged?
|
|
trap_ne
|
|
next_test
|
|
|
|
; PC modifying instructions (BRA, BBR, BBS, 1, 2, 3 byte NOPs, JMP(abs,x))
|
|
; testing unconditional branch BRA
|
|
|
|
ldx #$81 ;protect unused registers
|
|
ldy #$7e
|
|
set_a 0,$ff
|
|
bra br1 ;branch should always be taken
|
|
trap
|
|
br1
|
|
tst_a 0,$ff
|
|
set_a $ff,0
|
|
bra br2 ;branch should always be taken
|
|
trap
|
|
br2
|
|
tst_a $ff,0
|
|
cpx #$81
|
|
trap_ne
|
|
cpy #$7e
|
|
trap_ne
|
|
next_test
|
|
|
|
ldy #0 ;branch range test
|
|
bra bra0
|
|
|
|
bra1 cpy #1
|
|
trap_ne ;long range backward
|
|
iny
|
|
bra bra2
|
|
|
|
bra3 cpy #3
|
|
trap_ne ;long range backward
|
|
iny
|
|
bra bra4
|
|
|
|
bra5 cpy #5
|
|
trap_ne ;long range backward
|
|
iny
|
|
ldy #0
|
|
bra brf0
|
|
|
|
iny
|
|
iny
|
|
iny
|
|
iny
|
|
brf0 bra brf1
|
|
|
|
iny
|
|
iny
|
|
iny
|
|
brf1 iny
|
|
bra brf2
|
|
|
|
iny
|
|
iny
|
|
brf2 iny
|
|
iny
|
|
bra brf3
|
|
|
|
iny
|
|
brf3 iny
|
|
iny
|
|
iny
|
|
bra brf4
|
|
|
|
brf4 iny
|
|
iny
|
|
iny
|
|
iny
|
|
cpy #10
|
|
trap_ne ;short range forward
|
|
bra brb0
|
|
|
|
brb4 dey
|
|
dey
|
|
dey
|
|
dey
|
|
bra brb5
|
|
|
|
brb3 dey
|
|
dey
|
|
dey
|
|
bra brb4
|
|
|
|
brb2 dey
|
|
dey
|
|
bra brb3
|
|
|
|
brb1 dey
|
|
bra brb2
|
|
|
|
brb0 bra brb1
|
|
|
|
brb5 cpy #0
|
|
trap_ne ;short range backward
|
|
bra bra6
|
|
|
|
bra4 cpy #4
|
|
trap_ne ;long range forward
|
|
iny
|
|
bra bra5
|
|
|
|
bra2 cpy #2
|
|
trap_ne ;long range forward
|
|
iny
|
|
bra bra3
|
|
|
|
bra0 cpy #0
|
|
trap_ne ;long range forward
|
|
iny
|
|
bra bra1
|
|
|
|
bra6
|
|
next_test
|
|
|
|
if rkwl_wdc_op = 1
|
|
; testing BBR & BBS
|
|
|
|
bbt macro ;\1 = bitnum
|
|
lda #(1<<\1) ;testing 1 bit on
|
|
sta zpt
|
|
set_a $33,0 ;with flags off
|
|
bbr \1,zpt,fail1\?
|
|
bbs \1,zpt,ok1\?
|
|
trap ;bbs branch not taken
|
|
fail1\?
|
|
trap ;bbr branch taken
|
|
ok1\?
|
|
tst_a $33,0
|
|
set_a $cc,$ff ;with flags on
|
|
bbr \1,zpt,fail2\?
|
|
bbs \1,zpt,ok2\?
|
|
trap ;bbs branch not taken
|
|
fail2\?
|
|
trap ;bbr branch taken
|
|
ok2\?
|
|
tst_a $cc,$ff
|
|
lda zpt
|
|
cmp #(1<<\1)
|
|
trap_ne ;zp altered
|
|
lda #$ff-(1<<\1) ;testing 1 bit off
|
|
sta zpt
|
|
set_a $33,0 ;with flags off
|
|
bbs \1,zpt,fail3\?
|
|
bbr \1,zpt,ok3\?
|
|
trap ;bbr branch not taken
|
|
fail3\?
|
|
trap ;bbs branch taken
|
|
ok3\?
|
|
tst_a $33,0
|
|
set_a $cc,$ff ;with flags on
|
|
bbs \1,zpt,fail4\?
|
|
bbr \1,zpt,ok4\?
|
|
trap ;bbr branch not taken
|
|
fail4\?
|
|
trap ;bbs branch taken
|
|
ok4\?
|
|
tst_a $cc,$ff
|
|
lda zpt
|
|
cmp #$ff-(1<<\1)
|
|
trap_ne ;zp altered
|
|
endm
|
|
|
|
ldx #$11 ;test bbr/bbs integrity
|
|
ldy #$22
|
|
bbt 0
|
|
bbt 1
|
|
bbt 2
|
|
bbt 3
|
|
bbt 4
|
|
bbt 5
|
|
bbt 6
|
|
bbt 7
|
|
cpx #$11
|
|
trap_ne ;x overwritten
|
|
cpy #$22
|
|
trap_ne ;y overwritten
|
|
next_test
|
|
|
|
bbrc macro ;\1 = bitnum
|
|
bbr \1,zpt,skip\?
|
|
eor #(1<<\1)
|
|
skip\?
|
|
endm
|
|
bbsc macro ;\1 = bitnum
|
|
bbs \1,zpt,skip\?
|
|
eor #(1<<\1)
|
|
skip\?
|
|
endm
|
|
|
|
lda #0 ;combined bit test
|
|
sta zpt
|
|
bbcl lda #0
|
|
bbrc 0
|
|
bbrc 1
|
|
bbrc 2
|
|
bbrc 3
|
|
bbrc 4
|
|
bbrc 5
|
|
bbrc 6
|
|
bbrc 7
|
|
eor zpt
|
|
trap_ne ;failed bbr bitnum in accu
|
|
lda #$ff
|
|
bbsc 0
|
|
bbsc 1
|
|
bbsc 2
|
|
bbsc 3
|
|
bbsc 4
|
|
bbsc 5
|
|
bbsc 6
|
|
bbsc 7
|
|
eor zpt
|
|
trap_ne ;failed bbs bitnum in accu
|
|
inc zpt
|
|
bne bbcl
|
|
next_test
|
|
endif
|
|
|
|
; testing NOP
|
|
|
|
nop_test macro ;\1 = opcode, \2 = # of bytes
|
|
ldy #$42
|
|
ldx #4-\2
|
|
db \1 ;test nop length
|
|
if \2 = 1
|
|
dex
|
|
dex
|
|
endif
|
|
if \2 = 2
|
|
iny
|
|
dex
|
|
endif
|
|
if \2 = 3
|
|
iny
|
|
iny
|
|
endif
|
|
dex
|
|
trap_ne ;wrong number of bytes
|
|
set_a $ff-\1,0
|
|
db \1 ;test nop integrity - flags off
|
|
nop
|
|
nop
|
|
tst_a $ff-\1,0
|
|
set_a $aa-\1,$ff
|
|
db \1 ;test nop integrity - flags on
|
|
nop
|
|
nop
|
|
tst_a $aa-\1,$ff
|
|
cpy #$42
|
|
trap_ne ;y changed
|
|
cpx #0
|
|
trap_ne ;x changed
|
|
endm
|
|
|
|
nop_test $02,2
|
|
nop_test $22,2
|
|
nop_test $42,2
|
|
nop_test $62,2
|
|
nop_test $82,2
|
|
nop_test $c2,2
|
|
nop_test $e2,2
|
|
nop_test $44,2
|
|
nop_test $54,2
|
|
nop_test $d4,2
|
|
nop_test $f4,2
|
|
nop_test $5c,3
|
|
nop_test $dc,3
|
|
nop_test $fc,3
|
|
nop_test $03,1
|
|
nop_test $13,1
|
|
nop_test $23,1
|
|
nop_test $33,1
|
|
nop_test $43,1
|
|
nop_test $53,1
|
|
nop_test $63,1
|
|
nop_test $73,1
|
|
nop_test $83,1
|
|
nop_test $93,1
|
|
nop_test $a3,1
|
|
nop_test $b3,1
|
|
nop_test $c3,1
|
|
nop_test $d3,1
|
|
nop_test $e3,1
|
|
nop_test $f3,1
|
|
nop_test $0b,1
|
|
nop_test $1b,1
|
|
nop_test $2b,1
|
|
nop_test $3b,1
|
|
nop_test $4b,1
|
|
nop_test $5b,1
|
|
nop_test $6b,1
|
|
nop_test $7b,1
|
|
nop_test $8b,1
|
|
nop_test $9b,1
|
|
nop_test $ab,1
|
|
nop_test $bb,1
|
|
nop_test $eb,1
|
|
nop_test $fb,1
|
|
if rkwl_wdc_op = 0 ;NOPs not available on Rockwell & WDC 65C02
|
|
nop_test $07,1
|
|
nop_test $17,1
|
|
nop_test $27,1
|
|
nop_test $37,1
|
|
nop_test $47,1
|
|
nop_test $57,1
|
|
nop_test $67,1
|
|
nop_test $77,1
|
|
nop_test $87,1
|
|
nop_test $97,1
|
|
nop_test $a7,1
|
|
nop_test $b7,1
|
|
nop_test $c7,1
|
|
nop_test $d7,1
|
|
nop_test $e7,1
|
|
nop_test $f7,1
|
|
nop_test $0f,1
|
|
nop_test $1f,1
|
|
nop_test $2f,1
|
|
nop_test $3f,1
|
|
nop_test $4f,1
|
|
nop_test $5f,1
|
|
nop_test $6f,1
|
|
nop_test $7f,1
|
|
nop_test $8f,1
|
|
nop_test $9f,1
|
|
nop_test $af,1
|
|
nop_test $bf,1
|
|
nop_test $cf,1
|
|
nop_test $df,1
|
|
nop_test $ef,1
|
|
nop_test $ff,1
|
|
endif
|
|
if wdc_op = 0 ;NOPs not available on WDC 65C02 (WAI, STP)
|
|
nop_test $cb,1
|
|
nop_test $db,1
|
|
endif
|
|
next_test
|
|
|
|
; jump indirect (test page cross bug is fixed)
|
|
ldx #3 ;prepare table
|
|
ji1 lda ji_adr,x
|
|
sta ji_tab,x
|
|
dex
|
|
bpl ji1
|
|
lda #hi(ji_px) ;high address if page cross bug
|
|
sta pg_x
|
|
set_stat 0
|
|
lda #'I'
|
|
ldx #'N'
|
|
ldy #'D' ;N=0, V=0, Z=0, C=0
|
|
jmp (ji_tab)
|
|
nop
|
|
trap_ne ;runover protection
|
|
|
|
dey
|
|
dey
|
|
ji_ret php ;either SP or Y count will fail, if we do not hit
|
|
dey
|
|
dey
|
|
dey
|
|
plp
|
|
trap_eq ;returned flags OK?
|
|
trap_pl
|
|
trap_cc
|
|
trap_vc
|
|
cmp #('I'^$aa) ;returned registers OK?
|
|
trap_ne
|
|
cpx #('N'+1)
|
|
trap_ne
|
|
cpy #('D'-6)
|
|
trap_ne
|
|
tsx ;SP check
|
|
cpx #$ff
|
|
trap_ne
|
|
next_test
|
|
|
|
; jump indexed indirect
|
|
ldx #11 ;prepare table
|
|
jxi1 lda jxi_adr,x
|
|
sta jxi_tab,x
|
|
dex
|
|
bpl jxi1
|
|
lda #hi(jxi_px) ;high address if page cross bug
|
|
sta pg_x
|
|
set_stat 0
|
|
lda #'X'
|
|
ldx #4
|
|
ldy #'I' ;N=0, V=0, Z=0, C=0
|
|
jmp (jxi_tab,x)
|
|
nop
|
|
trap_ne ;runover protection
|
|
|
|
dey
|
|
dey
|
|
jxi_ret php ;either SP or Y count will fail, if we do not hit
|
|
dey
|
|
dey
|
|
dey
|
|
plp
|
|
trap_eq ;returned flags OK?
|
|
trap_pl
|
|
trap_cc
|
|
trap_vc
|
|
cmp #('X'^$aa) ;returned registers OK?
|
|
trap_ne
|
|
cpx #6
|
|
trap_ne
|
|
cpy #('I'-6)
|
|
trap_ne
|
|
tsx ;SP check
|
|
cpx #$ff
|
|
trap_ne
|
|
|
|
lda #lo(jxp_ok) ;test with index causing a page cross
|
|
sta jxp_tab
|
|
lda #hi(jxp_ok)
|
|
sta jxp_tab+1
|
|
lda #lo(jxp_px)
|
|
sta pg_x
|
|
lda #hi(jxp_px)
|
|
sta pg_x+1
|
|
ldx #$ff
|
|
jmp (jxp_tab-$ff,x)
|
|
|
|
jxp_px
|
|
trap ;page cross by index to wrong page
|
|
|
|
jxp_ok
|
|
next_test
|
|
|
|
if ROM_vectors = 1
|
|
; test BRK clears decimal mode
|
|
sed
|
|
brk
|
|
nop
|
|
brk_ret
|
|
next_test
|
|
endif
|
|
|
|
; testing accumulator increment/decrement INC A & DEC A
|
|
ldx #$ac ;protect x & y
|
|
ldy #$dc
|
|
set_a $fe,$ff
|
|
inc a ;ff
|
|
tst_as $ff,$ff-zero
|
|
inc a ;00
|
|
tst_as 0,$ff-minus
|
|
inc a ;01
|
|
tst_as 1,$ff-minus-zero
|
|
dec a ;00
|
|
tst_as 0,$ff-minus
|
|
dec a ;ff
|
|
tst_as $ff,$ff-zero
|
|
dec a ;fe
|
|
set_a $fe,0
|
|
inc a ;ff
|
|
tst_as $ff,minus
|
|
inc a ;00
|
|
tst_as 0,zero
|
|
inc a ;01
|
|
tst_as 1,0
|
|
dec a ;00
|
|
tst_as 0,zero
|
|
dec a ;ff
|
|
tst_as $ff,minus
|
|
cpx #$ac
|
|
trap_ne ;x altered during test
|
|
cpy #$dc
|
|
trap_ne ;y altered during test
|
|
tsx
|
|
cpx #$ff
|
|
trap_ne ;sp push/pop mismatch
|
|
next_test
|
|
|
|
; testing load / store accumulator LDA / STA (zp)
|
|
ldx #$99 ;protect x & y
|
|
ldy #$66
|
|
set_stat 0
|
|
lda (ind1)
|
|
php ;test stores do not alter flags
|
|
eor #$c3
|
|
plp
|
|
sta (indt)
|
|
php ;flags after load/store sequence
|
|
eor #$c3
|
|
cmp #$c3 ;test result
|
|
trap_ne
|
|
pla ;load status
|
|
eor_flag 0
|
|
cmp fLDx ;test flags
|
|
trap_ne
|
|
set_stat 0
|
|
lda (ind1+2)
|
|
php ;test stores do not alter flags
|
|
eor #$c3
|
|
plp
|
|
sta (indt+2)
|
|
php ;flags after load/store sequence
|
|
eor #$c3
|
|
cmp #$82 ;test result
|
|
trap_ne
|
|
pla ;load status
|
|
eor_flag 0
|
|
cmp fLDx+1 ;test flags
|
|
trap_ne
|
|
set_stat 0
|
|
lda (ind1+4)
|
|
php ;test stores do not alter flags
|
|
eor #$c3
|
|
plp
|
|
sta (indt+4)
|
|
php ;flags after load/store sequence
|
|
eor #$c3
|
|
cmp #$41 ;test result
|
|
trap_ne
|
|
pla ;load status
|
|
eor_flag 0
|
|
cmp fLDx+2 ;test flags
|
|
trap_ne
|
|
set_stat 0
|
|
lda (ind1+6)
|
|
php ;test stores do not alter flags
|
|
eor #$c3
|
|
plp
|
|
sta (indt+6)
|
|
php ;flags after load/store sequence
|
|
eor #$c3
|
|
cmp #0 ;test result
|
|
trap_ne
|
|
pla ;load status
|
|
eor_flag 0
|
|
cmp fLDx+3 ;test flags
|
|
trap_ne
|
|
cpx #$99
|
|
trap_ne ;x altered during test
|
|
cpy #$66
|
|
trap_ne ;y altered during test
|
|
|
|
ldy #3 ;testing store result
|
|
ldx #0
|
|
tstai1 lda abst,y
|
|
eor #$c3
|
|
cmp abs1,y
|
|
trap_ne ;store to indirect data
|
|
txa
|
|
sta abst,y ;clear
|
|
dey
|
|
bpl tstai1
|
|
|
|
ldx #$99 ;protect x & y
|
|
ldy #$66
|
|
set_stat $ff
|
|
lda (ind1)
|
|
php ;test stores do not alter flags
|
|
eor #$c3
|
|
plp
|
|
sta (indt)
|
|
php ;flags after load/store sequence
|
|
eor #$c3
|
|
cmp #$c3 ;test result
|
|
trap_ne
|
|
pla ;load status
|
|
eor_flag lo~fnz ;mask bits not altered
|
|
cmp fLDx ;test flags
|
|
trap_ne
|
|
set_stat $ff
|
|
lda (ind1+2)
|
|
php ;test stores do not alter flags
|
|
eor #$c3
|
|
plp
|
|
sta (indt+2)
|
|
php ;flags after load/store sequence
|
|
eor #$c3
|
|
cmp #$82 ;test result
|
|
trap_ne
|
|
pla ;load status
|
|
eor_flag lo~fnz ;mask bits not altered
|
|
cmp fLDx+1 ;test flags
|
|
trap_ne
|
|
set_stat $ff
|
|
lda (ind1+4)
|
|
php ;test stores do not alter flags
|
|
eor #$c3
|
|
plp
|
|
sta (indt+4)
|
|
php ;flags after load/store sequence
|
|
eor #$c3
|
|
cmp #$41 ;test result
|
|
trap_ne
|
|
pla ;load status
|
|
eor_flag lo~fnz ;mask bits not altered
|
|
cmp fLDx+2 ;test flags
|
|
trap_ne
|
|
set_stat $ff
|
|
lda (ind1+6)
|
|
php ;test stores do not alter flags
|
|
eor #$c3
|
|
plp
|
|
sta (indt+6)
|
|
php ;flags after load/store sequence
|
|
eor #$c3
|
|
cmp #0 ;test result
|
|
trap_ne
|
|
pla ;load status
|
|
eor_flag lo~fnz ;mask bits not altered
|
|
cmp fLDx+3 ;test flags
|
|
trap_ne
|
|
cpx #$99
|
|
trap_ne ;x altered during test
|
|
cpy #$66
|
|
trap_ne ;y altered during test
|
|
|
|
ldy #3 ;testing store result
|
|
ldx #0
|
|
tstai2 lda abst,y
|
|
eor #$c3
|
|
cmp abs1,y
|
|
trap_ne ;store to indirect data
|
|
txa
|
|
sta abst,y ;clear
|
|
dey
|
|
bpl tstai2
|
|
tsx
|
|
cpx #$ff
|
|
trap_ne ;sp push/pop mismatch
|
|
next_test
|
|
|
|
; testing STZ - zp / abs / zp,x / abs,x
|
|
ldy #123 ;protect y
|
|
ldx #4 ;precharge test area
|
|
lda #7
|
|
tstz1 sta zpt,x
|
|
asl a
|
|
dex
|
|
bpl tstz1
|
|
ldx #4
|
|
set_a $55,$ff
|
|
stz zpt
|
|
stz zpt+1
|
|
stz zpt+2
|
|
stz zpt+3
|
|
stz zpt+4
|
|
tst_a $55,$ff
|
|
tstz2 lda zpt,x ;verify zeros stored
|
|
trap_ne ;non zero after STZ zp
|
|
dex
|
|
bpl tstz2
|
|
ldx #4 ;precharge test area
|
|
lda #7
|
|
tstz3 sta zpt,x
|
|
asl a
|
|
dex
|
|
bpl tstz3
|
|
ldx #4
|
|
set_a $aa,0
|
|
stz zpt
|
|
stz zpt+1
|
|
stz zpt+2
|
|
stz zpt+3
|
|
stz zpt+4
|
|
tst_a $aa,0
|
|
tstz4 lda zpt,x ;verify zeros stored
|
|
trap_ne ;non zero after STZ zp
|
|
dex
|
|
bpl tstz4
|
|
|
|
ldx #4 ;precharge test area
|
|
lda #7
|
|
tstz5 sta abst,x
|
|
asl a
|
|
dex
|
|
bpl tstz5
|
|
ldx #4
|
|
set_a $55,$ff
|
|
stz abst
|
|
stz abst+1
|
|
stz abst+2
|
|
stz abst+3
|
|
stz abst+4
|
|
tst_a $55,$ff
|
|
tstz6 lda abst,x ;verify zeros stored
|
|
trap_ne ;non zero after STZ abs
|
|
dex
|
|
bpl tstz6
|
|
ldx #4 ;precharge test area
|
|
lda #7
|
|
tstz7 sta abst,x
|
|
asl a
|
|
dex
|
|
bpl tstz7
|
|
ldx #4
|
|
set_a $aa,0
|
|
stz abst
|
|
stz abst+1
|
|
stz abst+2
|
|
stz abst+3
|
|
stz abst+4
|
|
tst_a $aa,0
|
|
tstz8 lda abst,x ;verify zeros stored
|
|
trap_ne ;non zero after STZ abs
|
|
dex
|
|
bpl tstz8
|
|
|
|
ldx #4 ;precharge test area
|
|
lda #7
|
|
tstz11 sta zpt,x
|
|
asl a
|
|
dex
|
|
bpl tstz11
|
|
ldx #4
|
|
tstz15
|
|
set_a $55,$ff
|
|
stz zpt,x
|
|
tst_a $55,$ff
|
|
dex
|
|
bpl tstz15
|
|
ldx #4
|
|
tstz12 lda zpt,x ;verify zeros stored
|
|
trap_ne ;non zero after STZ zp
|
|
dex
|
|
bpl tstz12
|
|
ldx #4 ;precharge test area
|
|
lda #7
|
|
tstz13 sta zpt,x
|
|
asl a
|
|
dex
|
|
bpl tstz13
|
|
ldx #4
|
|
tstz16
|
|
set_a $aa,0
|
|
stz zpt,x
|
|
tst_a $aa,0
|
|
dex
|
|
bpl tstz16
|
|
ldx #4
|
|
tstz14 lda zpt,x ;verify zeros stored
|
|
trap_ne ;non zero after STZ zp
|
|
dex
|
|
bpl tstz14
|
|
|
|
ldx #4 ;precharge test area
|
|
lda #7
|
|
tstz21 sta abst,x
|
|
asl a
|
|
dex
|
|
bpl tstz21
|
|
ldx #4
|
|
tstz25
|
|
set_a $55,$ff
|
|
stz abst,x
|
|
tst_a $55,$ff
|
|
dex
|
|
bpl tstz25
|
|
ldx #4
|
|
tstz22 lda abst,x ;verify zeros stored
|
|
trap_ne ;non zero after STZ zp
|
|
dex
|
|
bpl tstz22
|
|
ldx #4 ;precharge test area
|
|
lda #7
|
|
tstz23 sta abst,x
|
|
asl a
|
|
dex
|
|
bpl tstz23
|
|
ldx #4
|
|
tstz26
|
|
set_a $aa,0
|
|
stz abst,x
|
|
tst_a $aa,0
|
|
dex
|
|
bpl tstz26
|
|
ldx #4
|
|
tstz24 lda abst,x ;verify zeros stored
|
|
trap_ne ;non zero after STZ zp
|
|
dex
|
|
bpl tstz24
|
|
|
|
cpy #123
|
|
trap_ne ;y altered during test
|
|
tsx
|
|
cpx #$ff
|
|
trap_ne ;sp push/pop mismatch
|
|
next_test
|
|
|
|
; testing BIT - zp,x / abs,x / #
|
|
ldy #$42
|
|
ldx #3
|
|
set_a $ff,0
|
|
bit zp1,x ;00 - should set Z / clear NV
|
|
tst_a $ff,fz
|
|
dex
|
|
set_a 1,0
|
|
bit zp1,x ;41 - should set V (M6) / clear NZ
|
|
tst_a 1,fv
|
|
dex
|
|
set_a 1,0
|
|
bit zp1,x ;82 - should set N (M7) & Z / clear V
|
|
tst_a 1,fnz
|
|
dex
|
|
set_a 1,0
|
|
bit zp1,x ;c3 - should set N (M7) & V (M6) / clear Z
|
|
tst_a 1,fnv
|
|
|
|
set_a 1,$ff
|
|
bit zp1,x ;c3 - should set N (M7) & V (M6) / clear Z
|
|
tst_a 1,~fz
|
|
inx
|
|
set_a 1,$ff
|
|
bit zp1,x ;82 - should set N (M7) & Z / clear V
|
|
tst_a 1,~fv
|
|
inx
|
|
set_a 1,$ff
|
|
bit zp1,x ;41 - should set V (M6) / clear NZ
|
|
tst_a 1,~fnz
|
|
inx
|
|
set_a $ff,$ff
|
|
bit zp1,x ;00 - should set Z / clear NV
|
|
tst_a $ff,~fnv
|
|
|
|
set_a $ff,0
|
|
bit abs1,x ;00 - should set Z / clear NV
|
|
tst_a $ff,fz
|
|
dex
|
|
set_a 1,0
|
|
bit abs1,x ;41 - should set V (M6) / clear NZ
|
|
tst_a 1,fv
|
|
dex
|
|
set_a 1,0
|
|
bit abs1,x ;82 - should set N (M7) & Z / clear V
|
|
tst_a 1,fnz
|
|
dex
|
|
set_a 1,0
|
|
bit abs1,x ;c3 - should set N (M7) & V (M6) / clear Z
|
|
tst_a 1,fnv
|
|
|
|
set_a 1,$ff
|
|
bit abs1,x ;c3 - should set N (M7) & V (M6) / clear Z
|
|
tst_a 1,~fz
|
|
inx
|
|
set_a 1,$ff
|
|
bit abs1,x ;82 - should set N (M7) & Z / clear V
|
|
tst_a 1,~fv
|
|
inx
|
|
set_a 1,$ff
|
|
bit abs1,x ;41 - should set V (M6) / clear NZ
|
|
tst_a 1,~fnz
|
|
inx
|
|
set_a $ff,$ff
|
|
bit abs1,x ;00 - should set Z / clear NV
|
|
tst_a $ff,~fnv
|
|
|
|
set_a $ff,0
|
|
bit #$00 ;00 - should set Z
|
|
tst_a $ff,fz
|
|
dex
|
|
set_a 1,0
|
|
bit #$41 ;41 - should clear Z
|
|
tst_a 1,0
|
|
; *** DEBUG INFO ***
|
|
; if it fails the previous test and your BIT # has set the V flag
|
|
; see http://forum.6502.org/viewtopic.php?f=2&t=2241&p=27243#p27239
|
|
; why it shouldn't alter N or V flags on a BIT #
|
|
dex
|
|
set_a 1,0
|
|
bit #$82 ;82 - should set Z
|
|
tst_a 1,fz
|
|
dex
|
|
set_a 1,0
|
|
bit #$c3 ;c3 - should clear Z
|
|
tst_a 1,0
|
|
|
|
set_a 1,$ff
|
|
bit #$c3 ;c3 - clear Z
|
|
tst_a 1,~fz
|
|
inx
|
|
set_a 1,$ff
|
|
bit #$82 ;82 - should set Z
|
|
tst_a 1,$ff
|
|
inx
|
|
set_a 1,$ff
|
|
bit #$41 ;41 - should clear Z
|
|
tst_a 1,~fz
|
|
inx
|
|
set_a $ff,$ff
|
|
bit #$00 ;00 - should set Z
|
|
tst_a $ff,$ff
|
|
|
|
cpx #3
|
|
trap_ne ;x altered during test
|
|
cpy #$42
|
|
trap_ne ;y altered during test
|
|
tsx
|
|
cpx #$ff
|
|
trap_ne ;sp push/pop mismatch
|
|
next_test
|
|
|
|
; testing TRB, TSB - zp / abs
|
|
|
|
trbt macro ;\1 = memory, \2 = flags
|
|
sty \1
|
|
load_flag \2
|
|
pha
|
|
lda zpt+1
|
|
plp
|
|
trb \1
|
|
php
|
|
cmp zpt+1
|
|
trap_ne ;accu was changed
|
|
pla
|
|
pha
|
|
ora #fz ;mask Z
|
|
cmp_flag \2|fz
|
|
trap_ne ;flags changed except Z
|
|
pla
|
|
and #fz
|
|
cmp zpt+2
|
|
trap_ne ;Z flag invalid
|
|
lda zpt+3
|
|
cmp zpt
|
|
trap_ne ;altered bits in memory wrong
|
|
endm
|
|
|
|
tsbt macro ;\1 = memory, \2 = flags
|
|
sty \1
|
|
load_flag \2
|
|
pha
|
|
lda zpt+1
|
|
plp
|
|
tsb \1
|
|
php
|
|
cmp zpt+1
|
|
trap_ne ;accu was changed
|
|
pla
|
|
pha
|
|
ora #fz ;mask Z
|
|
cmp_flag \2|fz
|
|
trap_ne ;flags changed except Z
|
|
pla
|
|
and #fz
|
|
cmp zpt+2
|
|
trap_ne ;Z flag invalid
|
|
lda zpt+4
|
|
cmp zpt
|
|
trap_ne ;altered bits in memory wrong
|
|
endm
|
|
|
|
ldx #$c0
|
|
ldy #0 ;op1 - memory save
|
|
; zpt ;op1 - memory modifiable
|
|
stz zpt+1 ;op2 - accu
|
|
; zpt+2 ;and flags
|
|
; zpt+3 ;memory after reset
|
|
; zpt+4 ;memory after set
|
|
|
|
tbt1 tya
|
|
and zpt+1 ;set Z by anding the 2 operands
|
|
php
|
|
pla
|
|
and #fz ;mask Z
|
|
sta zpt+2
|
|
tya ;reset op1 bits by op2
|
|
eor #$ff
|
|
ora zpt+1
|
|
eor #$ff
|
|
sta zpt+3
|
|
tya ;set op1 bits by op2
|
|
ora zpt+1
|
|
sta zpt+4
|
|
|
|
trbt zpt,$ff
|
|
trbt abst,$ff
|
|
trbt zpt,0
|
|
trbt abst,0
|
|
tsbt zpt,$ff
|
|
tsbt abst,$ff
|
|
tsbt zpt,0
|
|
tsbt abst,0
|
|
|
|
iny ;iterate op1
|
|
bne tbt3
|
|
inc zpt+1 ;iterate op2
|
|
beq tbt2
|
|
tbt3 jmp tbt1
|
|
tbt2
|
|
cpx #$c0
|
|
trap_ne ;x altered during test
|
|
tsx
|
|
cpx #$ff
|
|
trap_ne ;sp push/pop mismatch
|
|
next_test
|
|
|
|
if rkwl_wdc_op
|
|
; testing RMB, SMB - zp
|
|
rmbt macro ;\1 = bitnum
|
|
lda #$ff
|
|
sta zpt
|
|
set_a $a5,0
|
|
rmb \1,zpt
|
|
tst_a $a5,0
|
|
lda zpt
|
|
cmp #$ff-(1<<\1)
|
|
trap_ne ;wrong bits set or cleared
|
|
lda #1<<\1
|
|
sta zpt
|
|
set_a $5a,$ff
|
|
rmb \1,zpt
|
|
tst_a $5a,$ff
|
|
lda zpt
|
|
trap_ne ;wrong bits set or cleared
|
|
endm
|
|
smbt macro ;\1 = bitnum
|
|
lda #$ff-(1<<\1)
|
|
sta zpt
|
|
set_a $a5,0
|
|
smb \1,zpt
|
|
tst_a $a5,0
|
|
lda zpt
|
|
cmp #$ff
|
|
trap_ne ;wrong bits set or cleared
|
|
lda #0
|
|
sta zpt
|
|
set_a $5a,$ff
|
|
smb \1,zpt
|
|
tst_a $5a,$ff
|
|
lda zpt
|
|
cmp #1<<\1
|
|
trap_ne ;wrong bits set or cleared
|
|
endm
|
|
|
|
ldx #$ba ;protect x & y
|
|
ldy #$d0
|
|
rmbt 0
|
|
rmbt 1
|
|
rmbt 2
|
|
rmbt 3
|
|
rmbt 4
|
|
rmbt 5
|
|
rmbt 6
|
|
rmbt 7
|
|
smbt 0
|
|
smbt 1
|
|
smbt 2
|
|
smbt 3
|
|
smbt 4
|
|
smbt 5
|
|
smbt 6
|
|
smbt 7
|
|
cpx #$ba
|
|
trap_ne ;x altered during test
|
|
cpy #$d0
|
|
trap_ne ;y altered during test
|
|
tsx
|
|
cpx #$ff
|
|
trap_ne ;sp push/pop mismatch
|
|
next_test
|
|
endif
|
|
|
|
; testing CMP - (zp)
|
|
ldx #$de ;protect x & y
|
|
ldy #$ad
|
|
set_a $80,0
|
|
cmp (ind1+8)
|
|
tst_a $80,fc
|
|
set_a $7f,0
|
|
cmp (ind1+8)
|
|
tst_a $7f,fzc
|
|
set_a $7e,0
|
|
cmp (ind1+8)
|
|
tst_a $7e,fn
|
|
set_a $80,$ff
|
|
cmp (ind1+8)
|
|
tst_a $80,~fnz
|
|
set_a $7f,$ff
|
|
cmp (ind1+8)
|
|
tst_a $7f,~fn
|
|
set_a $7e,$ff
|
|
cmp (ind1+8)
|
|
tst_a $7e,~fzc
|
|
cpx #$de
|
|
trap_ne ;x altered during test
|
|
cpy #$ad
|
|
trap_ne ;y altered during test
|
|
tsx
|
|
cpx #$ff
|
|
trap_ne ;sp push/pop mismatch
|
|
next_test
|
|
|
|
; testing logical instructions - AND EOR ORA (zp)
|
|
ldx #$42 ;protect x & y
|
|
|
|
ldy #0 ;AND
|
|
lda indAN ;set indirect address
|
|
sta zpt
|
|
lda indAN+1
|
|
sta zpt+1
|
|
tand1
|
|
set_ay absANa,0
|
|
and (zpt)
|
|
tst_ay absrlo,absflo,0
|
|
inc zpt
|
|
iny
|
|
cpy #4
|
|
bne tand1
|
|
dey
|
|
dec zpt
|
|
tand2
|
|
set_ay absANa,$ff
|
|
and (zpt)
|
|
tst_ay absrlo,absflo,$ff-fnz
|
|
dec zpt
|
|
dey
|
|
bpl tand2
|
|
|
|
ldy #0 ;EOR
|
|
lda indEO ;set indirect address
|
|
sta zpt
|
|
lda indEO+1
|
|
sta zpt+1
|
|
teor1
|
|
set_ay absEOa,0
|
|
eor (zpt)
|
|
tst_ay absrlo,absflo,0
|
|
inc zpt
|
|
iny
|
|
cpy #4
|
|
bne teor1
|
|
dey
|
|
dec zpt
|
|
teor2
|
|
set_ay absEOa,$ff
|
|
eor (zpt)
|
|
tst_ay absrlo,absflo,$ff-fnz
|
|
dec zpt
|
|
dey
|
|
bpl teor2
|
|
|
|
ldy #0 ;ORA
|
|
lda indOR ;set indirect address
|
|
sta zpt
|
|
lda indOR+1
|
|
sta zpt+1
|
|
tora1
|
|
set_ay absORa,0
|
|
ora (zpt)
|
|
tst_ay absrlo,absflo,0
|
|
inc zpt
|
|
iny
|
|
cpy #4
|
|
bne tora1
|
|
dey
|
|
dec zpt
|
|
tora2
|
|
set_ay absORa,$ff
|
|
ora (zpt)
|
|
tst_ay absrlo,absflo,$ff-fnz
|
|
dec zpt
|
|
dey
|
|
bpl tora2
|
|
|
|
cpx #$42
|
|
trap_ne ;x altered during test
|
|
tsx
|
|
cpx #$ff
|
|
trap_ne ;sp push/pop mismatch
|
|
next_test
|
|
|
|
if I_flag = 3
|
|
cli
|
|
endif
|
|
|
|
; full binary add/subtract test - (zp) only
|
|
; iterates through all combinations of operands and carry input
|
|
; uses increments/decrements to predict result & result flags
|
|
cld
|
|
ldx #ad2 ;for indexed test
|
|
ldy #$ff ;max range
|
|
lda #0 ;start with adding zeroes & no carry
|
|
sta adfc ;carry in - for diag
|
|
sta ad1 ;operand 1 - accumulator
|
|
sta ad2 ;operand 2 - memory or immediate
|
|
sta ada2 ;non zp
|
|
sta adrl ;expected result bits 0-7
|
|
sta adrh ;expected result bit 8 (carry out)
|
|
lda #$ff ;complemented operand 2 for subtract
|
|
sta sb2
|
|
sta sba2 ;non zp
|
|
lda #2 ;expected Z-flag
|
|
sta adrf
|
|
tadd clc ;test with carry clear
|
|
jsr chkadd
|
|
inc adfc ;now with carry
|
|
inc adrl ;result +1
|
|
php ;save N & Z from low result
|
|
php
|
|
pla ;accu holds expected flags
|
|
and #$82 ;mask N & Z
|
|
plp
|
|
bne tadd1
|
|
inc adrh ;result bit 8 - carry
|
|
tadd1 ora adrh ;merge C to expected flags
|
|
sta adrf ;save expected flags except overflow
|
|
sec ;test with carry set
|
|
jsr chkadd
|
|
dec adfc ;same for operand +1 but no carry
|
|
inc ad1
|
|
bne tadd ;iterate op1
|
|
lda #0 ;preset result to op2 when op1 = 0
|
|
sta adrh
|
|
inc ada2
|
|
inc ad2
|
|
php ;save NZ as operand 2 becomes the new result
|
|
pla
|
|
and #$82 ;mask N00000Z0
|
|
sta adrf ;no need to check carry as we are adding to 0
|
|
dec sb2 ;complement subtract operand 2
|
|
dec sba2
|
|
lda ad2
|
|
sta adrl
|
|
bne tadd ;iterate op2
|
|
|
|
cpx #ad2
|
|
trap_ne ;x altered during test
|
|
cpy #$ff
|
|
trap_ne ;y altered during test
|
|
tsx
|
|
cpx #$ff
|
|
trap_ne ;sp push/pop mismatch
|
|
next_test
|
|
|
|
; decimal add/subtract test
|
|
; *** WARNING - tests documented behavior only! ***
|
|
; only valid BCD operands are tested, the V flag is ignored
|
|
; although V is declared as beeing valid on the 65C02 it has absolutely
|
|
; no use in BCD math. No sign = no overflow!
|
|
; iterates through all valid combinations of operands and carry input
|
|
; uses increments/decrements to predict result & carry flag
|
|
sed
|
|
ldx #ad2 ;for indexed test
|
|
ldy #$ff ;max range
|
|
lda #$99 ;start with adding 99 to 99 with carry
|
|
sta ad1 ;operand 1 - accumulator
|
|
sta ad2 ;operand 2 - memory or immediate
|
|
sta ada2 ;non zp
|
|
sta adrl ;expected result bits 0-7
|
|
lda #1 ;set carry in & out
|
|
sta adfc ;carry in - for diag
|
|
sta adrh ;expected result bit 8 (carry out)
|
|
lda #$81 ;set N & C (99 + 99 + C = 99 + C)
|
|
sta adrf
|
|
lda #0 ;complemented operand 2 for subtract
|
|
sta sb2
|
|
sta sba2 ;non zp
|
|
tdad sec ;test with carry set
|
|
jsr chkdad
|
|
dec adfc ;now with carry clear
|
|
lda adrl ;decimal adjust result
|
|
bne tdad1 ;skip clear carry & preset result 99 (9A-1)
|
|
dec adrh
|
|
lda #$99
|
|
sta adrl
|
|
bne tdad3
|
|
tdad1 and #$f ;lower nibble mask
|
|
bne tdad2 ;no decimal adjust needed
|
|
dec adrl ;decimal adjust (?0-6)
|
|
dec adrl
|
|
dec adrl
|
|
dec adrl
|
|
dec adrl
|
|
dec adrl
|
|
tdad2 dec adrl ;result -1
|
|
tdad3 php ;save valid flags
|
|
pla
|
|
and #$82 ;N-----Z-
|
|
ora adrh ;N-----ZC
|
|
sta adrf
|
|
clc ;test with carry clear
|
|
jsr chkdad
|
|
inc adfc ;same for operand -1 but with carry
|
|
lda ad1 ;decimal adjust operand 1
|
|
beq tdad5 ;iterate operand 2
|
|
and #$f ;lower nibble mask
|
|
bne tdad4 ;skip decimal adjust
|
|
dec ad1 ;decimal adjust (?0-6)
|
|
dec ad1
|
|
dec ad1
|
|
dec ad1
|
|
dec ad1
|
|
dec ad1
|
|
tdad4 dec ad1 ;operand 1 -1
|
|
jmp tdad ;iterate op1
|
|
|
|
tdad5 lda #$99 ;precharge op1 max
|
|
sta ad1
|
|
lda ad2 ;decimal adjust operand 2
|
|
beq tdad7 ;end of iteration
|
|
and #$f ;lower nibble mask
|
|
bne tdad6 ;skip decimal adjust
|
|
dec ad2 ;decimal adjust (?0-6)
|
|
dec ad2
|
|
dec ad2
|
|
dec ad2
|
|
dec ad2
|
|
dec ad2
|
|
inc sb2 ;complemented decimal adjust for subtract (?9+6)
|
|
inc sb2
|
|
inc sb2
|
|
inc sb2
|
|
inc sb2
|
|
inc sb2
|
|
tdad6 dec ad2 ;operand 2 -1
|
|
inc sb2 ;complemented operand for subtract
|
|
lda sb2
|
|
sta sba2 ;copy as non zp operand
|
|
lda ad2
|
|
sta ada2 ;copy as non zp operand
|
|
sta adrl ;new result since op1+carry=00+carry +op2=op2
|
|
php ;save flags
|
|
pla
|
|
and #$82 ;N-----Z-
|
|
ora #1 ;N-----ZC
|
|
sta adrf
|
|
inc adrh ;result carry
|
|
jmp tdad ;iterate op2
|
|
|
|
tdad7 cpx #ad2
|
|
trap_ne ;x altered during test
|
|
cpy #$ff
|
|
trap_ne ;y altered during test
|
|
tsx
|
|
cpx #$ff
|
|
trap_ne ;sp push/pop mismatch
|
|
cld
|
|
|
|
lda test_case
|
|
cmp #test_num
|
|
trap_ne ;previous test is out of sequence
|
|
lda #$f0 ;mark opcode testing complete
|
|
sta test_case
|
|
|
|
; final RAM integrity test
|
|
; verifies that none of the previous tests has altered RAM outside of the
|
|
; designated write areas.
|
|
check_ram
|
|
; *** DEBUG INFO ***
|
|
; to debug checksum errors uncomment check_ram in the next_test macro to
|
|
; narrow down the responsible opcode.
|
|
; may give false errors when monitor, OS or other background activity is
|
|
; allowed during previous tests.
|
|
|
|
|
|
; S U C C E S S ************************************************
|
|
; -------------
|
|
success ;if you get here everything went well
|
|
; -------------
|
|
; S U C C E S S ************************************************
|
|
jmp start ;run again
|
|
|
|
; core subroutine of the decimal add/subtract test
|
|
; *** WARNING - tests documented behavior only! ***
|
|
; only valid BCD operands are tested, V flag is ignored
|
|
; iterates through all valid combinations of operands and carry input
|
|
; uses increments/decrements to predict result & carry flag
|
|
chkdad
|
|
; decimal ADC / SBC zp
|
|
php ;save carry for subtract
|
|
lda ad1
|
|
adc ad2 ;perform add
|
|
php
|
|
cmp adrl ;check result
|
|
trap_ne ;bad result
|
|
pla ;check flags
|
|
and #$83 ;mask N-----ZC
|
|
cmp adrf
|
|
trap_ne ;bad flags
|
|
plp
|
|
php ;save carry for next add
|
|
lda ad1
|
|
sbc sb2 ;perform subtract
|
|
php
|
|
cmp adrl ;check result
|
|
trap_ne ;bad result
|
|
pla ;check flags
|
|
and #$83 ;mask N-----ZC
|
|
cmp adrf
|
|
trap_ne ;bad flags
|
|
plp
|
|
; decimal ADC / SBC abs
|
|
php ;save carry for subtract
|
|
lda ad1
|
|
adc ada2 ;perform add
|
|
php
|
|
cmp adrl ;check result
|
|
trap_ne ;bad result
|
|
pla ;check flags
|
|
and #$83 ;mask N-----ZC
|
|
cmp adrf
|
|
trap_ne ;bad flags
|
|
plp
|
|
php ;save carry for next add
|
|
lda ad1
|
|
sbc sba2 ;perform subtract
|
|
php
|
|
cmp adrl ;check result
|
|
trap_ne ;bad result
|
|
pla ;check flags
|
|
and #$83 ;mask N-----ZC
|
|
cmp adrf
|
|
trap_ne ;bad flags
|
|
plp
|
|
; decimal ADC / SBC #
|
|
php ;save carry for subtract
|
|
lda ad2
|
|
sta ex_adci+1 ;set ADC # operand
|
|
lda ad1
|
|
jsr ex_adci ;execute ADC # in RAM
|
|
php
|
|
cmp adrl ;check result
|
|
trap_ne ;bad result
|
|
pla ;check flags
|
|
and #1 ;mask carry
|
|
cmp adrh
|
|
trap_ne ;bad carry
|
|
plp
|
|
php ;save carry for next add
|
|
lda sb2
|
|
sta ex_sbci+1 ;set SBC # operand
|
|
lda ad1
|
|
jsr ex_sbci ;execute SBC # in RAM
|
|
php
|
|
cmp adrl ;check result
|
|
trap_ne ;bad result
|
|
pla ;check flags
|
|
and #1 ;mask carry
|
|
cmp adrh
|
|
trap_ne ;bad carry
|
|
plp
|
|
; decimal ADC / SBC zp,x
|
|
php ;save carry for subtract
|
|
lda ad1
|
|
adc 0,x ;perform add
|
|
php
|
|
cmp adrl ;check result
|
|
trap_ne ;bad result
|
|
pla ;check flags
|
|
and #$83 ;mask N-----ZC
|
|
cmp adrf
|
|
trap_ne ;bad flags
|
|
plp
|
|
php ;save carry for next add
|
|
lda ad1
|
|
sbc sb2-ad2,x ;perform subtract
|
|
php
|
|
cmp adrl ;check result
|
|
trap_ne ;bad result
|
|
pla ;check flags
|
|
and #$83 ;mask N-----ZC
|
|
cmp adrf
|
|
trap_ne ;bad flags
|
|
plp
|
|
; decimal ADC / SBC abs,x
|
|
php ;save carry for subtract
|
|
lda ad1
|
|
adc ada2-ad2,x ;perform add
|
|
php
|
|
cmp adrl ;check result
|
|
trap_ne ;bad result
|
|
pla ;check flags
|
|
and #$83 ;mask N-----ZC
|
|
cmp adrf
|
|
trap_ne ;bad flags
|
|
plp
|
|
php ;save carry for next add
|
|
lda ad1
|
|
sbc sba2-ad2,x ;perform subtract
|
|
php
|
|
cmp adrl ;check result
|
|
trap_ne ;bad result
|
|
pla ;check flags
|
|
and #$83 ;mask N-----ZC
|
|
cmp adrf
|
|
trap_ne ;bad flags
|
|
plp
|
|
; decimal ADC / SBC abs,y
|
|
php ;save carry for subtract
|
|
lda ad1
|
|
adc ada2-$ff,y ;perform add
|
|
php
|
|
cmp adrl ;check result
|
|
trap_ne ;bad result
|
|
pla ;check flags
|
|
and #$83 ;mask N-----ZC
|
|
cmp adrf
|
|
trap_ne ;bad flags
|
|
plp
|
|
php ;save carry for next add
|
|
lda ad1
|
|
sbc sba2-$ff,y ;perform subtract
|
|
php
|
|
cmp adrl ;check result
|
|
trap_ne ;bad result
|
|
pla ;check flags
|
|
and #$83 ;mask N-----ZC
|
|
cmp adrf
|
|
trap_ne ;bad flags
|
|
plp
|
|
; decimal ADC / SBC (zp,x)
|
|
php ;save carry for subtract
|
|
lda ad1
|
|
adc (lo adi2-ad2,x) ;perform add
|
|
php
|
|
cmp adrl ;check result
|
|
trap_ne ;bad result
|
|
pla ;check flags
|
|
and #$83 ;mask N-----ZC
|
|
cmp adrf
|
|
trap_ne ;bad flags
|
|
plp
|
|
php ;save carry for next add
|
|
lda ad1
|
|
sbc (lo sbi2-ad2,x) ;perform subtract
|
|
php
|
|
cmp adrl ;check result
|
|
trap_ne ;bad result
|
|
pla ;check flags
|
|
and #$83 ;mask N-----ZC
|
|
cmp adrf
|
|
trap_ne ;bad flags
|
|
plp
|
|
; decimal ADC / SBC (abs),y
|
|
php ;save carry for subtract
|
|
lda ad1
|
|
adc (adiy2),y ;perform add
|
|
php
|
|
cmp adrl ;check result
|
|
trap_ne ;bad result
|
|
pla ;check flags
|
|
and #$83 ;mask N-----ZC
|
|
cmp adrf
|
|
trap_ne ;bad flags
|
|
plp
|
|
php ;save carry for next add
|
|
lda ad1
|
|
sbc (sbiy2),y ;perform subtract
|
|
php
|
|
cmp adrl ;check result
|
|
trap_ne ;bad result
|
|
pla ;check flags
|
|
and #$83 ;mask N-----ZC
|
|
cmp adrf
|
|
trap_ne ;bad flags
|
|
plp
|
|
; decimal ADC / SBC (zp)
|
|
php ;save carry for subtract
|
|
lda ad1
|
|
adc (adi2) ;perform add
|
|
php
|
|
cmp adrl ;check result
|
|
trap_ne ;bad result
|
|
pla ;check flags
|
|
and #$83 ;mask N-----ZC
|
|
cmp adrf
|
|
trap_ne ;bad flags
|
|
plp
|
|
php ;save carry for next add
|
|
lda ad1
|
|
sbc (sbi2) ;perform subtract
|
|
php
|
|
cmp adrl ;check result
|
|
trap_ne ;bad result
|
|
pla ;check flags
|
|
and #$83 ;mask N-----ZC
|
|
cmp adrf
|
|
trap_ne ;bad flags
|
|
plp
|
|
rts
|
|
|
|
; core subroutine of the full binary add/subtract test
|
|
; iterates through all combinations of operands and carry input
|
|
; uses increments/decrements to predict result & result flags
|
|
chkadd lda adrf ;add V-flag if overflow
|
|
and #$83 ;keep N-----ZC / clear V
|
|
pha
|
|
lda ad1 ;test sign unequal between operands
|
|
eor ad2
|
|
bmi ckad1 ;no overflow possible - operands have different sign
|
|
lda ad1 ;test sign equal between operands and result
|
|
eor adrl
|
|
bpl ckad1 ;no overflow occured - operand and result have same sign
|
|
pla
|
|
ora #$40 ;set V
|
|
pha
|
|
ckad1 pla
|
|
sta adrf ;save expected flags
|
|
; binary ADC / SBC (zp)
|
|
php ;save carry for subtract
|
|
lda ad1
|
|
adc (adi2) ;perform add
|
|
php
|
|
cmp adrl ;check result
|
|
trap_ne ;bad result
|
|
pla ;check flags
|
|
and #$c3 ;mask NV----ZC
|
|
cmp adrf
|
|
trap_ne ;bad flags
|
|
plp
|
|
php ;save carry for next add
|
|
lda ad1
|
|
sbc (sbi2) ;perform subtract
|
|
php
|
|
cmp adrl ;check result
|
|
trap_ne ;bad result
|
|
pla ;check flags
|
|
and #$c3 ;mask NV----ZC
|
|
cmp adrf
|
|
trap_ne ;bad flags
|
|
plp
|
|
rts
|
|
|
|
; target for the jump indirect test
|
|
ji_adr dw test_ji
|
|
dw ji_ret
|
|
|
|
dey
|
|
dey
|
|
test_ji
|
|
php ;either SP or Y count will fail, if we do not hit
|
|
dey
|
|
dey
|
|
dey
|
|
plp
|
|
trap_cs ;flags loaded?
|
|
trap_vs
|
|
trap_mi
|
|
trap_eq
|
|
cmp #'I' ;registers loaded?
|
|
trap_ne
|
|
cpx #'N'
|
|
trap_ne
|
|
cpy #('D'-3)
|
|
trap_ne
|
|
pha ;save a,x
|
|
txa
|
|
pha
|
|
tsx
|
|
cpx #$fd ;check SP
|
|
trap_ne
|
|
pla ;restore x
|
|
tax
|
|
set_stat $ff
|
|
pla ;restore a
|
|
inx ;return registers with modifications
|
|
eor #$aa ;N=1, V=1, Z=0, C=1
|
|
jmp (ji_tab+2)
|
|
nop
|
|
nop
|
|
trap ;runover protection
|
|
|
|
; target for the jump indirect test
|
|
jxi_adr dw trap_ind
|
|
dw trap_ind
|
|
dw test_jxi ;+4
|
|
dw jxi_ret ;+6
|
|
dw trap_ind
|
|
dw trap_ind
|
|
|
|
dey
|
|
dey
|
|
test_jxi
|
|
php ;either SP or Y count will fail, if we do not hit
|
|
dey
|
|
dey
|
|
dey
|
|
plp
|
|
trap_cs ;flags loaded?
|
|
trap_vs
|
|
trap_mi
|
|
trap_eq
|
|
cmp #'X' ;registers loaded?
|
|
trap_ne
|
|
cpx #4
|
|
trap_ne
|
|
cpy #('I'-3)
|
|
trap_ne
|
|
pha ;save a,x
|
|
txa
|
|
pha
|
|
tsx
|
|
cpx #$fd ;check SP
|
|
trap_ne
|
|
pla ;restore x
|
|
tax
|
|
set_stat $ff
|
|
pla ;restore a
|
|
inx ;return registers with modifications
|
|
inx
|
|
eor #$aa ;N=1, V=1, Z=0, C=1
|
|
jmp (jxi_tab,x)
|
|
nop
|
|
nop
|
|
trap ;runover protection
|
|
|
|
; JMP (abs,x) with bad x
|
|
nop
|
|
nop
|
|
trap_ind
|
|
nop
|
|
nop
|
|
trap ;near miss indexed indirect jump
|
|
|
|
;trap in case of unexpected IRQ, NMI, BRK, RESET
|
|
nmi_trap
|
|
trap ;check stack for conditions at NMI
|
|
res_trap
|
|
trap ;unexpected RESET
|
|
irq_trap
|
|
php ;save decimal flag
|
|
tsx ;test break on stack
|
|
lda $102,x
|
|
and #break
|
|
trap_eq ;check stack for conditions at IRQ
|
|
if ROM_vectors = 1
|
|
pla ;test decimal mode cleared
|
|
and #decmode
|
|
trap_ne ;decimal mode not cleared after BRK
|
|
plp ;pop saved flags
|
|
pla ;return address low
|
|
cmp #lo(brk_ret)
|
|
trap_ne ;unexpected BRK
|
|
pla ;return address high
|
|
cmp #hi(brk_ret)
|
|
trap_ne ;unexpected BRK
|
|
jmp brk_ret
|
|
else
|
|
trap_ne ;check stack for conditions at BRK
|
|
endif
|
|
|
|
if report = 1
|
|
include "report.i65"
|
|
endif
|
|
|
|
;copy of data to initialize BSS segment
|
|
if load_data_direct != 1
|
|
zp_init
|
|
zp1_ db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
|
|
zp7f_ db $7f ;test pattern for compare
|
|
;logical zeropage operands
|
|
zpOR_ db 0,$1f,$71,$80 ;test pattern for OR
|
|
zpAN_ db $0f,$ff,$7f,$80 ;test pattern for AND
|
|
zpEO_ db $ff,$0f,$8f,$8f ;test pattern for EOR
|
|
;indirect addressing pointers
|
|
ind1_ dw abs1 ;indirect pointer to pattern in absolute memory
|
|
dw abs1+1
|
|
dw abs1+2
|
|
dw abs1+3
|
|
dw abs7f
|
|
inw1_ dw abs1-$f8 ;indirect pointer for wrap-test pattern
|
|
indt_ dw abst ;indirect pointer to store area in absolute memory
|
|
dw abst+1
|
|
dw abst+2
|
|
dw abst+3
|
|
inwt_ dw abst-$f8 ;indirect pointer for wrap-test store
|
|
indAN_ dw absAN ;indirect pointer to AND pattern in absolute memory
|
|
dw absAN+1
|
|
dw absAN+2
|
|
dw absAN+3
|
|
indEO_ dw absEO ;indirect pointer to EOR pattern in absolute memory
|
|
dw absEO+1
|
|
dw absEO+2
|
|
dw absEO+3
|
|
indOR_ dw absOR ;indirect pointer to OR pattern in absolute memory
|
|
dw absOR+1
|
|
dw absOR+2
|
|
dw absOR+3
|
|
;add/subtract indirect pointers
|
|
adi2_ dw ada2 ;indirect pointer to operand 2 in absolute memory
|
|
sbi2_ dw sba2 ;indirect pointer to complemented operand 2 (SBC)
|
|
adiy2_ dw ada2-$ff ;with offset for indirect indexed
|
|
sbiy2_ dw sba2-$ff
|
|
zp_end
|
|
if (zp_end - zp_init) != (zp_bss_end - zp_bss)
|
|
;force assembler error if size is different
|
|
ERROR ERROR ERROR ;mismatch between bss and zeropage data
|
|
endif
|
|
data_init
|
|
ex_adc_ adc #0 ;execute immediate opcodes
|
|
rts
|
|
ex_sbc_ sbc #0 ;execute immediate opcodes
|
|
rts
|
|
abs1_ db $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
|
|
abs7f_ db $7f ;test pattern for compare
|
|
;loads
|
|
fLDx_ db fn,fn,0,fz ;expected flags for load
|
|
;shifts
|
|
rASL_ ;expected result ASL & ROL -carry
|
|
rROL_ db $86,$04,$82,0 ; "
|
|
rROLc_ db $87,$05,$83,1 ;expected result ROL +carry
|
|
rLSR_ ;expected result LSR & ROR -carry
|
|
rROR_ db $61,$41,$20,0 ; "
|
|
rRORc_ db $e1,$c1,$a0,$80 ;expected result ROR +carry
|
|
fASL_ ;expected flags for shifts
|
|
fROL_ db fnc,fc,fn,fz ;no carry in
|
|
fROLc_ db fnc,fc,fn,0 ;carry in
|
|
fLSR_
|
|
fROR_ db fc,0,fc,fz ;no carry in
|
|
fRORc_ db fnc,fn,fnc,fn ;carry in
|
|
;increments (decrements)
|
|
rINC_ db $7f,$80,$ff,0,1 ;expected result for INC/DEC
|
|
fINC_ db 0,fn,fn,fz,0 ;expected flags for INC/DEC
|
|
;logical memory operand
|
|
absOR_ db 0,$1f,$71,$80 ;test pattern for OR
|
|
absAN_ db $0f,$ff,$7f,$80 ;test pattern for AND
|
|
absEO_ db $ff,$0f,$8f,$8f ;test pattern for EOR
|
|
;logical accu operand
|
|
absORa_ db 0,$f1,$1f,0 ;test pattern for OR
|
|
absANa_ db $f0,$ff,$ff,$ff ;test pattern for AND
|
|
absEOa_ db $ff,$f0,$f0,$0f ;test pattern for EOR
|
|
;logical results
|
|
absrlo_ db 0,$ff,$7f,$80
|
|
absflo_ db fz,fn,0,fn
|
|
data_end
|
|
if (data_end - data_init) != (data_bss_end - data_bss)
|
|
;force assembler error if size is different
|
|
ERROR ERROR ERROR ;mismatch between bss and data
|
|
endif
|
|
|
|
vec_init
|
|
dw nmi_trap
|
|
dw res_trap
|
|
dw irq_trap
|
|
vec_bss equ $fffa
|
|
endif ;end of RAM init data
|
|
|
|
; code at end of image due to the need to add blank space as required
|
|
if ($ff & (ji_ret - * - 2)) < ($ff & (jxi_ret - * - 2))
|
|
; JMP (abs) when $xxff and $xx00 are from same page
|
|
ds lo(ji_ret - * - 2)
|
|
nop
|
|
nop
|
|
ji_px nop ;low address byte matched with ji_ret
|
|
nop
|
|
trap ;jmp indirect page cross bug
|
|
|
|
; JMP (abs,x) when $xxff and $xx00 are from same page
|
|
ds lo(jxi_ret - * - 2)
|
|
nop
|
|
nop
|
|
jxi_px nop ;low address byte matched with jxi_ret
|
|
nop
|
|
trap ;jmp indexed indirect page cross bug
|
|
else
|
|
; JMP (abs,x) when $xxff and $xx00 are from same page
|
|
ds lo(jxi_ret - * - 2)
|
|
nop
|
|
nop
|
|
jxi_px nop ;low address byte matched with jxi_ret
|
|
nop
|
|
trap ;jmp indexed indirect page cross bug
|
|
|
|
; JMP (abs) when $xxff and $xx00 are from same page
|
|
ds lo(ji_ret - * - 2)
|
|
nop
|
|
nop
|
|
ji_px nop ;low address byte matched with ji_ret
|
|
nop
|
|
trap ;jmp indirect page cross bug
|
|
endif
|
|
|
|
if (load_data_direct = 1) & (ROM_vectors = 1)
|
|
org $fffa ;vectors
|
|
dw nmi_trap
|
|
dw res_trap
|
|
dw irq_trap
|
|
endif
|
|
|
|
end start
|
|
|