6502_65C02_functional_tests/65C02_extended_opcodes_test.a65c

2746 lines
74 KiB
Plaintext
Raw Normal View History

2013-08-07 16:56:09 +00:00
;
; 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 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.
;
2013-08-16 11:30:31 +00:00
; version 16-aug-2013
2013-08-07 16:56:09 +00:00
; 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
2013-08-16 11:30:31 +00:00
; 16-aug-2013 added error report to standard output option
2013-08-07 16:56:09 +00:00
; C O N F I G U R A T I O N
2013-08-16 11:30:31 +00:00
2013-08-07 16:56:09 +00:00
;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
2013-08-16 11:30:31 +00:00
2013-08-07 16:56:09 +00:00
;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
2013-08-16 11:30:31 +00:00
2013-08-07 16:56:09 +00:00
;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
2013-08-16 11:30:31 +00:00
2013-08-07 16:56:09 +00:00
;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
2013-08-16 11:30:31 +00:00
2013-08-07 16:56:09 +00:00
;data_segment memory start address, $5D (93) 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
2013-08-16 11:30:31 +00:00
2013-08-07 16:56:09 +00:00
;code_segment memory start address, 10kB of consecutive space required
; add 1 kB if I_flag = 2
;parts of the code are self modifying and must reside in RAM
code_segment = $400
2013-08-16 11:30:31 +00:00
2013-08-07 16:56:09 +00:00
;added WDC only opcodes WAI & STP (0=test as NOPs, >0=no test)
wdc_op = 1
2013-08-16 11:30:31 +00:00
2013-08-07 16:56:09 +00:00
;added Rockwell & WDC opcodes BBR, BBS, RMB & SMB
;(0=test as NOPs, 1=full test, >1=no test)
rkwl_wdc_op = 1
2013-08-16 11:30:31 +00:00
;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
2013-08-07 16:56:09 +00:00
;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.
2013-08-16 11:30:31 +00:00
if report = 0
2013-08-07 16:56:09 +00:00
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
2013-08-16 11:30:31 +00:00
; please observe that during the test the stack gets invalidated
; therefore a RTS inside the success macro is not possible
2013-08-07 16:56:09 +00:00
success macro
jmp * ;test passed, no errors
endm
2013-08-16 11:30:31 +00:00
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
2013-08-07 16:56:09 +00:00
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
php ;use stack to retrieve status
pla
cmp_flag \1
trap_ne
plp ;restore status
endm
tst_a macro ;testing result in accu & flags
php ;save flags
php
cmp #\1 ;test result
trap_ne
pla ;load status
cmp_flag \2
trap_ne
plp ;restore status
endm
tst_as macro ;testing result in accu & flags, save accu
pha
php ;save flags
php
cmp #\1 ;test result
trap_ne
pla ;load status
cmp_flag \2
trap_ne
plp ;restore status
pla
endm
tst_x macro ;testing result in x index & flags
php ;save flags
php
cpx #\1 ;test result
trap_ne
pla ;load status
cmp_flag \2
trap_ne
plp ;restore status
endm
tst_y macro ;testing result in y index & flags
php ;save flags
php
cpy #\1 ;test result
trap_ne
pla ;load status
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\?
sta chkdadi ;self modifying code
sta chkdsbi
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) ;data after write 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
2013-08-16 11:30:31 +00:00
lda #test_num ;*** next tests' number
2013-08-07 16:56:09 +00:00
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
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
2013-08-16 11:30:31 +00:00
2013-08-07 16:56:09 +00:00
code
org code_segment
start cld
2013-08-16 11:30:31 +00:00
ldx #$ff
txs
2013-08-07 16:56:09 +00:00
lda #0 ;*** test 0 = initialize
sta test_case
test_num = 0
;stop interrupts before initializing BSS
if I_flag = 1
sei
endif
2013-08-16 11:30:31 +00:00
;initialize I/O for report channel
if report = 1
jsr report_init
endif
2013-08-07 16:56:09 +00:00
;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
sta chkdadi ;self modifying code
sta chkdsbi
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) ;data after write 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