diff --git a/examples/asm/functional_test/6502_functional_test.bin b/examples/asm/functional_test/6502_functional_test.bin
index 8a20227..24ce1ce 100644
Binary files a/examples/asm/functional_test/6502_functional_test.bin and b/examples/asm/functional_test/6502_functional_test.bin differ
diff --git a/examples/asm/functional_test/6502_functional_test.ca65 b/examples/asm/functional_test/6502_functional_test.ca65
new file mode 100644
index 0000000..255f765
--- /dev/null
+++ b/examples/asm/functional_test/6502_functional_test.ca65
@@ -0,0 +1,6125 @@
+;
+; 6 5 0 2 F U N C T I O N A L T E S T
+;
+; Copyright (C) 2012-2020 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 .
+
+
+; This program is designed to test all opcodes of a 6502 emulator using all
+; addressing modes with focus on propper setting of the processor status
+; register bits.
+;
+; version 05-jan-2020
+; contact info at http://2m5.de or email K@2m5.de
+;
+; assembled with CA65, linked with LD65 (cc65.github.io):
+; ca65 -l 6502_functional_test.lst 6502_functional_test.ca65
+; ld65 6502_functional_test.o -o 6502_functional_test.bin \
+; -m 6502_functional_test.map -C example.cfg
+; example linker config (example.cfg):
+; MEMORY {
+; RAM: start = $0000, size=$8000, type = rw, fill = yes, \
+; fillval = $FF, file = %O;
+; ROM: start = $8000, size=$7FFA, type = ro, fill = yes, \
+; fillval = $FF, file = %O;
+; ROM_VECTORS: start = $FFFA, size=6, type = ro, fill = yes, \
+; fillval = $FF, file = %O;
+; }
+; SEGMENTS {
+; ZEROPAGE: load=RAM, type=rw;
+; DATA: load=RAM, type=rw, offset=$0200;
+; CODE: load=RAM, type=rw, offset=$0400;
+; VECTORS: load=ROM_VECTORS, type=ro;
+; }
+;
+; 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 NMOS 6502 only! No unofficial
+; opcodes. Additional opcodes of newer versions of the CPU (65C02, 65816) will
+; not be tested. Decimal ops will only be tested with valid BCD operands and
+; N V Z flags will be ignored.
+;
+; 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:
+; 28-jul-2012 1st version distributed for testing
+; 29-jul-2012 fixed references to location 0, now #0
+; added license - GPLv3
+; 30-jul-2012 added configuration options
+; 01-aug-2012 added trap macro to allow user to change error handling
+; 01-dec-2012 fixed trap in branch field must be a branch
+; 02-mar-2013 fixed PLA flags not tested
+; 19-jul-2013 allowed ROM vectors to be loaded when load_data_direct = 0
+; added test sequence check to detect if tests jump their fence
+; 23-jul-2013 added RAM integrity check option
+; 16-aug-2013 added error report to standard output option
+; 13-dec-2014 added binary/decimal opcode table switch test
+; 14-dec-2014 improved relative address test
+; 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
+; 04-dec-2017 fixed BRK only tested with interrupts enabled
+; added option to skip the remainder of a failing test
+; in report.i65
+; 05-jan-2020 fixed shifts not testing zero result and flag when last 1-bit
+; is shifted out
+
+; 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 = 0
+
+;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. SEI & CLI can only be
+;tested if you allow changing the interrupt status (I_flag = 3)
+I_flag = 1
+
+;configure memory - try to stay away from memory used by the system
+;zero_page memory start address, $52 (82) consecutive Bytes required
+; add 2 if I_flag = 2
+zero_page = $a
+
+;data_segment memory start address, $7B (123) consecutive Bytes required
+; check that this matches the linker configuration file
+data_segment = $200
+ .if (data_segment & $ff) <> 0
+ .error "low byte of data_segment MUST be $00 !!"
+ .endif
+
+;code_segment memory start address, 13.1kB of consecutive space required
+; add 2.5 kB if I_flag = 2
+; check that this matches the linker configuration file
+code_segment = $400
+
+;self modifying code may be disabled to allow running in ROM
+;0=part of the code is self modifying and must reside in RAM
+;1=tests disabled: branch range
+disable_selfmod = 1
+
+;report errors through I/O channel (0=use standard self trap loops, 1=include
+;report.i65 as I/O channel, add 3.5 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
+
+;disable test decimal mode ADC & SBC, 0=enable, 1=disable,
+;2=disable including decimal flag in processor status
+disable_decimal = 0
+
+;macros for error & success traps to allow user modification
+;example:
+; .macro trap
+; jsr my_error_handler
+; .endmacro
+; .macro trap_eq
+; bne :+
+; trap ;failed equal (zero)
+;:
+; .endmacro
+;
+; 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
+ .macro trap
+ jmp * ;failed anyway
+ .endmacro
+ .macro trap_eq
+ beq * ;failed equal (zero)
+ .endmacro
+ .macro trap_ne
+ bne * ;failed not equal (non zero)
+ .endmacro
+ .macro trap_cs
+ bcs * ;failed carry set
+ .endmacro
+ .macro trap_cc
+ bcc * ;failed carry clear
+ .endmacro
+ .macro trap_mi
+ bmi * ;failed minus (bit 7 set)
+ .endmacro
+ .macro trap_pl
+ bpl * ;failed plus (bit 7 clear)
+ .endmacro
+ .macro trap_vs
+ bvs * ;failed overflow set
+ .endmacro
+ .macro trap_vc
+ bvc * ;failed overflow clear
+ .endmacro
+; please observe that during the test the stack gets invalidated
+; therefore a RTS inside the success macro is not possible
+ .macro success
+ jmp * ;test passed, no errors
+ .endmacro
+ .endif
+ .if report = 1
+ .macro trap
+ jsr report_error
+ .endmacro
+ .macro trap_eq
+ bne :+
+ trap ;failed equal (zero)
+:
+ .endmacro
+ .macro trap_ne
+ beq :+
+ trap ;failed not equal (non zero)
+:
+ .endmacro
+ .macro trap_cs
+ bcc :+
+ trap ;failed carry set
+:
+ .endmacro
+ .macro trap_cc
+ bcs :+
+ trap ;failed carry clear
+:
+ .endmacro
+ .macro trap_mi
+ bpl :+
+ trap ;failed minus (bit 7 set)
+:
+ .endmacro
+ .macro trap_pl
+ bmi :+
+ trap ;failed plus (bit 7 clear)
+:
+ .endmacro
+ .macro trap_vs
+ bvc :+
+ trap ;failed overflow set
+:
+ .endmacro
+ .macro trap_vc
+ bvs :+
+ trap ;failed overflow clear
+:
+ .endmacro
+; please observe that during the test the stack gets invalidated
+; therefore a RTS inside the success macro is not possible
+ .macro success
+ jsr report_success
+ .endmacro
+ .endif
+
+ .define equ =
+
+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
+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
+ .macro load_flag p1
+ lda #p1&m8i ;force enable interrupts (mask I)
+ .endmacro
+ .macro cmp_flag p1
+ cmp #(p1|fao)&m8i ;I_flag is always enabled + always on bits
+ .endmacro
+ .macro eor_flag p1
+ eor #(p1&m8i|fao) ;mask I, invert expected flags + always on bits
+ .endmacro
+ .endif
+ .if I_flag = 1
+ .macro load_flag p1
+ lda #p1|intdis ;force disable interrupts
+ .endmacro
+ .macro cmp_flag p1
+ cmp #(p1|fai)&m8 ;I_flag is always disabled + always on bits
+ .endmacro
+ .macro eor_flag p1
+ eor #(p1|fai) ;invert expected flags + always on bits + I
+ .endmacro
+ .endif
+ .if I_flag = 2
+ .macro load_flag p1
+ lda #p1
+ ora flag_I_on ;restore I-flag
+ and flag_I_off
+ .endmacro
+ .macro cmp_flag p1
+ eor flag_I_on ;I_flag is never changed
+ cmp #(p1|fao)&m8i ;expected flags + always on bits, mask I
+ .endmacro
+ .macro eor_flag p1
+ eor flag_I_on ;I_flag is never changed
+ eor #(p1&m8i|fao) ;mask I, invert expected flags + always on bits
+ .endmacro
+ .endif
+ .if I_flag = 3
+ .macro load_flag p1
+ lda #p1 ;allow test to change I-flag (no mask)
+ .endmacro
+ .macro cmp_flag p1
+ cmp #(p1|fao)&m8 ;expected flags + always on bits
+ .endmacro
+ .macro eor_flag p1
+ eor #p1|fao ;invert expected flags + always on bits
+ .endmacro
+ .endif
+ .else
+ .if I_flag = 0
+ .macro load_flag p1
+ lda #p1&m8i ;force enable interrupts (mask I)
+ .endmacro
+ .macro cmp_flag p1
+ ora #decmode ;ignore decimal mode bit
+ cmp #(p1|faod)&m8i ;I_flag is always enabled + always on bits
+ .endmacro
+ .macro eor_flag p1
+ ora #decmode ;ignore decimal mode bit
+ eor #(p1&m8i|faod) ;mask I, invert expected flags + always on bits
+ .endmacro
+ .endif
+ .if I_flag = 1
+ .macro load_flag p1
+ lda #p1|intdis ;force disable interrupts
+ .endmacro
+ .macro cmp_flag p1
+ ora #decmode ;ignore decimal mode bit
+ cmp #(p1|faid)&m8 ;I_flag is always disabled + always on bits
+ .endmacro
+ .macro eor_flag p1
+ ora #decmode ;ignore decimal mode bit
+ eor #(p1|faid) ;invert expected flags + always on bits + I
+ .endmacro
+ .endif
+ .if I_flag = 2
+ .macro load_flag p1
+ lda #p1
+ ora flag_I_on ;restore I-flag
+ and flag_I_off
+ .endmacro
+ .macro cmp_flag p1
+ eor flag_I_on ;I_flag is never changed
+ ora #decmode ;ignore decimal mode bit
+ cmp #(p1|faod)&m8i ;expected flags + always on bits, mask I
+ .endmacro
+ .macro eor_flag p1
+ eor flag_I_on ;I_flag is never changed
+ ora #decmode ;ignore decimal mode bit
+ eor #(p1&m8i|faod) ;mask I, invert expected flags + always on bits
+ .endmacro
+ .endif
+ .if I_flag = 3
+ .macro load_flag p1
+ lda #p1 ;allow test to change I-flag (no mask)
+ .endmacro
+ .macro cmp_flag p1
+ ora #decmode ;ignore decimal mode bit
+ cmp #(p1|faod)&m8 ;expected flags + always on bits
+ .endmacro
+ .macro eor_flag p1
+ ora #decmode ;ignore decimal mode bit
+ eor #p1|faod ;invert expected flags + always on bits
+ .endmacro
+ .endif
+ .endif
+
+;macros to set (register|memory|zeropage) & status
+ .macro set_stat p1 ;setting flags in the processor status register
+ load_flag p1
+ pha ;use stack to load status
+ plp
+ .endmacro
+
+ .macro set_a p1,p2 ;precharging accu & status
+ load_flag p2
+ pha ;use stack to load status
+ lda #p1 ;precharge accu
+ plp
+ .endmacro
+
+ .macro set_x p1,p2 ;precharging index & status
+ load_flag p2
+ pha ;use stack to load status
+ ldx #p1 ;precharge index x
+ plp
+ .endmacro
+
+ .macro set_y p1,p2 ;precharging index & status
+ load_flag p2
+ pha ;use stack to load status
+ ldy #p1 ;precharge index y
+ plp
+ .endmacro
+
+ .macro set_ax p1,p2 ;precharging indexed accu & immediate status
+ load_flag p2
+ pha ;use stack to load status
+ lda p1,x ;precharge accu
+ plp
+ .endmacro
+
+ .macro set_ay p1,p2 ;precharging indexed accu & immediate status
+ load_flag p2
+ pha ;use stack to load status
+ lda p1,y ;precharge accu
+ plp
+ .endmacro
+
+ .macro set_z p1,p2 ;precharging indexed zp & immediate status
+ load_flag p2
+ pha ;use stack to load status
+ lda p1,x ;load to zeropage
+ sta zpt
+ plp
+ .endmacro
+
+ .macro set_zx p1,p2 ;precharging zp,x & immediate status
+ load_flag p2
+ pha ;use stack to load status
+ lda p1,x ;load to indexed zeropage
+ sta zpt,x
+ plp
+ .endmacro
+
+ .macro set_abs p1,p2 ;precharging indexed memory & immediate status
+ load_flag p2
+ pha ;use stack to load status
+ lda p1,x ;load to memory
+ sta abst
+ plp
+ .endmacro
+
+ .macro set_absx p1,p2 ;precharging abs,x & immediate status
+ load_flag p2
+ pha ;use stack to load status
+ lda p1,x ;load to indexed memory
+ sta abst,x
+ plp
+ .endmacro
+
+;macros to test (register|memory|zeropage) & status & (mask)
+ .macro tst_stat p1 ;testing flags in the processor status register
+ php ;save status
+ pla ;use stack to retrieve status
+ pha
+ cmp_flag p1
+ trap_ne
+ plp ;restore status
+ .endmacro
+
+ .macro tst_a p1,p2 ;testing result in accu & flags
+ php ;save flags
+ cmp #p1 ;test result
+ trap_ne
+ pla ;load status
+ pha
+ cmp_flag p2
+ trap_ne
+ plp ;restore status
+ .endmacro
+
+ .macro tst_x p1,p2 ;testing result in x index & flags
+ php ;save flags
+ cpx #p1 ;test result
+ trap_ne
+ pla ;load status
+ pha
+ cmp_flag p2
+ trap_ne
+ plp ;restore status
+ .endmacro
+
+ .macro tst_y p1,p2 ;testing result in y index & flags
+ php ;save flags
+ cpy #p1 ;test result
+ trap_ne
+ pla ;load status
+ pha
+ cmp_flag p2
+ trap_ne
+ plp ;restore status
+ .endmacro
+
+ .macro tst_ax p1,p2,p3 ;indexed testing result in accu & flags
+ php ;save flags
+ cmp p1,x ;test result
+ trap_ne
+ pla ;load status
+ eor_flag p3
+ cmp p2,x ;test flags
+ trap_ne ;
+ .endmacro
+
+ .macro tst_ay p1,p2,p3 ;indexed testing result in accu & flags
+ php ;save flags
+ cmp p1,y ;test result
+ trap_ne ;
+ pla ;load status
+ eor_flag p3
+ cmp p2,y ;test flags
+ trap_ne
+ .endmacro
+
+ .macro tst_z p1,p2,p3 ;indexed testing result in zp & flags
+ php ;save flags
+ lda zpt
+ cmp p1,x ;test result
+ trap_ne
+ pla ;load status
+ eor_flag p3
+ cmp p2,x ;test flags
+ trap_ne
+ .endmacro
+
+ .macro tst_zx p1,p2,p3 ;testing result in zp,x & flags
+ php ;save flags
+ lda zpt,x
+ cmp p1,x ;test result
+ trap_ne
+ pla ;load status
+ eor_flag p3
+ cmp p2,x ;test flags
+ trap_ne
+ .endmacro
+
+ .macro tst_abs p1,p2,p3 ;indexed testing result in memory & flags
+ php ;save flags
+ lda abst
+ cmp p1,x ;test result
+ trap_ne
+ pla ;load status
+ eor_flag p3
+ cmp p2,x ;test flags
+ trap_ne
+ .endmacro
+
+ .macro tst_absx p1,p2,p3 ;testing result in abs,x & flags
+ php ;save flags
+ lda abst,x
+ cmp p1,x ;test result
+ trap_ne
+ pla ;load status
+ eor_flag p3
+ cmp p2,x ;test flags
+ trap_ne
+ .endmacro
+
+; 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
+ .if disable_selfmod = 0
+ sta range_adr ;reset self modifying code
+ .endif
+ 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(abs1) ;set high byte of indirect pointer
+ stx zpt+1
+ ldy #lo(abs1) ;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
+ .endmacro
+ .else
+ .macro check_ram
+ ;RAM check disabled - RAM size not set
+ .endmacro
+ .endif
+
+ .macro next_test ;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 .set test_num + 1
+ lda #test_num ;*** next tests' number
+ sta test_case
+ ;check_ram ;uncomment to find altered RAM after each test
+ .endmacro
+
+ .ZEROPAGE
+ .res zero_page, 0
+ .org zero_page
+
+;break test interrupt save
+irq_a: .res 1,0 ;a register
+irq_x: .res 1,0 ;x register
+ .if I_flag = 2
+;masking for I bit in status
+flag_I_on: .res 1,0 ;or mask to load flags
+flag_I_off: .res 1,0 ;and mask to load flags
+ .endif
+zpt: ;6 bytes store/modify test area
+;add/subtract operand generation and result/flag prediction
+adfc: .res 1,0 ;carry flag before op
+ad1: .res 1,0 ;operand 1 - accumulator
+ad2: .res 1,0 ;operand 2 - memory / immediate
+adrl: .res 1,0 ;expected result bits 0-7
+adrh: .res 1,0 ;expected result bit 8 (carry)
+adrf: .res 1,0 ;expected flags NV0000ZC (only binary mode)
+sb2: .res 1,0 ;operand 2 complemented for subtract
+zp_bss:
+zps: .byte $80,1 ;additional shift pattern to test zero result & flag
+zp1: .byte $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
+zp7f: .byte $7f ;test pattern for compare
+;logical zeropage operands
+zpOR: .byte 0,$1f,$71,$80 ;test pattern for OR
+zpAN: .byte $0f,$ff,$7f,$80 ;test pattern for AND
+zpEO: .byte $ff,$0f,$8f,$8f ;test pattern for EOR
+;indirect addressing pointers
+ind1: .word abs1 ;indirect pointer to pattern in absolute memory
+ .word abs1+1
+ .word abs1+2
+ .word abs1+3
+ .word abs7f
+inw1: .word abs1-$f8 ;indirect pointer for wrap-test pattern
+indt: .word abst ;indirect pointer to store area in absolute memory
+ .word abst+1
+ .word abst+2
+ .word abst+3
+inwt: .word abst-$f8 ;indirect pointer for wrap-test store
+indAN: .word absAN ;indirect pointer to AND pattern in absolute memory
+ .word absAN+1
+ .word absAN+2
+ .word absAN+3
+indEO: .word absEO ;indirect pointer to EOR pattern in absolute memory
+ .word absEO+1
+ .word absEO+2
+ .word absEO+3
+indOR: .word absOR ;indirect pointer to OR pattern in absolute memory
+ .word absOR+1
+ .word absOR+2
+ .word absOR+3
+;add/subtract indirect pointers
+adi2: .word ada2 ;indirect pointer to operand 2 in absolute memory
+sbi2: .word sba2 ;indirect pointer to complemented operand 2 (SBC)
+adiy2: .word ada2-$ff ;with offset for indirect indexed
+sbiy2: .word sba2-$ff
+zp_bss_end:
+
+ .DATA
+ .org data_segment
+
+test_case: .res 1,0 ;current test number
+ram_chksm: .res 2,0 ;checksum for RAM integrity test
+;add/subtract operand copy - abs tests write area
+abst: ;6 bytes store/modify test area
+ada2: .res 1,0 ;operand 2
+sba2: .res 1,0 ;operand 2 complemented for subtract
+ .res 4,0 ;fill remaining bytes
+data_bss:
+ .if load_data_direct = 1
+ex_andi:and #0 ;execute immediate opcodes
+ rts
+ex_eori:eor #0 ;execute immediate opcodes
+ rts
+ex_orai:ora #0 ;execute immediate opcodes
+ rts
+ex_adci:adc #0 ;execute immediate opcodes
+ rts
+ex_sbci:sbc #0 ;execute immediate opcodes
+ rts
+ .else
+ex_andi:.res 3
+ex_eori:.res 3
+ex_orai:.res 3
+ex_adci:.res 3
+ex_sbci:.res 3
+ .endif
+;zps .byte $80,1 ;additional shift patterns test zero result & flag
+abs1: .byte $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
+abs7f: .byte $7f ;test pattern for compare
+;loads
+fLDx: .byte fn,fn,0,fz ;expected flags for load
+;shifts
+rASL: ;expected result ASL & ROL -carry
+rROL: .byte 0,2,$86,$04,$82,0
+rROLc: .byte 1,3,$87,$05,$83,1 ;expected result ROL +carry
+rLSR: ;expected result LSR & ROR -carry
+rROR: .byte $40,0,$61,$41,$20,0
+rRORc: .byte $c0,$80,$e1,$c1,$a0,$80 ;expected result ROR +carry
+fASL: ;expected flags for shifts
+fROL: .byte fzc,0,fnc,fc,fn,fz ;no carry in
+fROLc: .byte fc,0,fnc,fc,fn,0 ;carry in
+fLSR:
+fROR: .byte 0,fzc,fc,0,fc,fz ;no carry in
+fRORc: .byte fn,fnc,fnc,fn,fnc,fn ;carry in
+;increments (decrements)
+rINC: .byte $7f,$80,$ff,0,1 ;expected result for INC/DEC
+fINC: .byte 0,fn,fn,fz,0 ;expected flags for INC/DEC
+;logical memory operand
+absOR: .byte 0,$1f,$71,$80 ;test pattern for OR
+absAN: .byte $0f,$ff,$7f,$80 ;test pattern for AND
+absEO: .byte $ff,$0f,$8f,$8f ;test pattern for EOR
+;logical accu operand
+absORa: .byte 0,$f1,$1f,0 ;test pattern for OR
+absANa: .byte $f0,$ff,$ff,$ff ;test pattern for AND
+absEOa: .byte $ff,$f0,$f0,$0f ;test pattern for EOR
+;logical results
+absrlo: .byte 0,$ff,$7f,$80
+absflo: .byte fz,fn,0,fn
+data_bss_end:
+
+
+ .CODE
+ .org code_segment
+ .P02 ; disable 65SC02, 65C02 and 65816 instructions
+start: cld
+ ldx #$ff
+ txs
+ lda #0 ;*** test 0 = initialize
+ sta test_case
+test_num .set 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
+
+;pretest small branch offset
+ ldx #5
+ jmp psb_test
+psb_bwok:
+ ldy #5
+ bne psb_forw
+ trap ;branch should be taken
+ dey ;forward landing zone
+ dey
+ dey
+ dey
+ dey
+psb_forw:
+ dey
+ dey
+ dey
+ dey
+ dey
+ beq psb_fwok
+ trap ;forward offset
+
+ dex ;backward landing zone
+ dex
+ dex
+ dex
+ dex
+psb_back:
+ dex
+ dex
+ dex
+ dex
+ dex
+ beq psb_bwok
+ trap ;backward offset
+psb_test:
+ bne psb_back
+ trap ;branch should be taken
+psb_fwok:
+
+;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
+ .if disable_selfmod = 0
+ sta range_adr ;reset self modifying code
+ .endif
+ 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(abs1) ;set high byte of indirect pointer
+ stx zpt+1
+ ldy #lo(abs1) ;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
+
+ .if disable_selfmod = 0
+;testing relative addressing with BEQ
+ ldy #$fe ;testing maximum range, not -1/-2 (invalid/self adr)
+range_loop:
+ dey ;next relative address
+ tya
+ tax ;precharge count to end of loop
+ bpl range_fw ;calculate relative address
+ clc ;avoid branch self or to relative address of branch
+ adc #2
+ nop ;offset landing zone - tolerate +/-5 offset to branch
+ nop
+ nop
+ nop
+ nop
+range_fw:
+ nop
+ nop
+ nop
+ nop
+ nop
+ eor #$7f ;complement except sign
+ sta range_adr ;load into test target
+ lda #0 ;should set zero flag in status register
+ jmp range_op
+
+ dex ; offset landing zone - backward branch too far
+ dex
+ dex
+ dex
+ dex
+ ;relative address target field with branch under test in the middle
+ dex ;-128 - max backward
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-120
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-110
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-100
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-90
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-80
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-70
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-60
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-50
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-40
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-30
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-20
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-10
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;-3
+range_op: ;test target with zero flag=0, z=1 if previous dex
+range_adr = *+1 ;modifiable relative address
+ beq *+64 ;+64 if called without modification
+ dex ;+0
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+10
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+20
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+30
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+40
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+50
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+60
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+70
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+80
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+90
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+100
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+110
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex ;+120
+ dex
+ dex
+ dex
+ dex
+ dex
+ dex
+ nop ;offset landing zone - forward branch too far
+ nop
+ nop
+ nop
+ nop
+ beq range_ok ;+127 - max forward
+ trap ; bad range
+ nop ;offset landing zone - tolerate +/-5 offset to branch
+ nop
+ nop
+ nop
+ nop
+range_ok:
+ nop
+ nop
+ nop
+ nop
+ nop
+ cpy #0
+ beq range_end
+ jmp range_loop
+range_end: ;range test successful
+ .endif
+ next_test
+
+;partial test BNE & CMP, CPX, CPY immediate
+ cpy #1 ;testing BNE true
+ bne test_bne
+ trap
+test_bne:
+ lda #0
+ cmp #0 ;test compare immediate
+ trap_ne
+ trap_cc
+ trap_mi
+ cmp #1
+ trap_eq
+ trap_cs
+ trap_pl
+ tax
+ cpx #0 ;test compare x immediate
+ trap_ne
+ trap_cc
+ trap_mi
+ cpx #1
+ trap_eq
+ trap_cs
+ trap_pl
+ tay
+ cpy #0 ;test compare y immediate
+ trap_ne
+ trap_cc
+ trap_mi
+ cpy #1
+ trap_eq
+ trap_cs
+ trap_pl
+ next_test
+;testing stack operations PHA PHP PLA PLP
+
+ ldx #$ff ;initialize stack
+ txs
+ lda #$55
+ pha
+ lda #$aa
+ pha
+ cmp $1fe ;on stack ?
+ trap_ne
+ tsx
+ txa ;overwrite accu
+ cmp #$fd ;sp decremented?
+ trap_ne
+ pla
+ cmp #$aa ;successful retreived from stack?
+ trap_ne
+ pla
+ cmp #$55
+ trap_ne
+ cmp $1ff ;remains on stack?
+ trap_ne
+ tsx
+ cpx #$ff ;sp incremented?
+ trap_ne
+ next_test
+
+;testing branch decisions BPL BMI BVC BVS BCC BCS BNE BEQ
+ set_stat $ff ;all on
+ bpl nbr1 ;branches should not be taken
+ bvc nbr2
+ bcc nbr3
+ bne nbr4
+ bmi br1 ;branches should be taken
+ trap
+br1: bvs br2
+ trap
+br2: bcs br3
+ trap
+br3: beq br4
+ trap
+nbr1:
+ trap ;previous bpl taken
+nbr2:
+ trap ;previous bvc taken
+nbr3:
+ trap ;previous bcc taken
+nbr4:
+ trap ;previous bne taken
+br4: php
+ tsx
+ cpx #$fe ;sp after php?
+ trap_ne
+ pla
+ cmp_flag $ff ;returned all flags on?
+ trap_ne
+ tsx
+ cpx #$ff ;sp after php?
+ trap_ne
+ set_stat 0 ;all off
+ bmi nbr11 ;branches should not be taken
+ bvs nbr12
+ bcs nbr13
+ beq nbr14
+ bpl br11 ;branches should be taken
+ trap
+br11: bvc br12
+ trap
+br12: bcc br13
+ trap
+br13: bne br14
+ trap
+nbr11:
+ trap ;previous bmi taken
+nbr12:
+ trap ;previous bvs taken
+nbr13:
+ trap ;previous bcs taken
+nbr14:
+ trap ;previous beq taken
+br14: php
+ pla
+ cmp_flag 0 ;flags off except break (pushed by sw) + reserved?
+ trap_ne
+ ;crosscheck flags
+ set_stat zero
+ bne brzs1
+ beq brzs2
+brzs1:
+ trap ;branch zero/non zero
+brzs2: bcs brzs3
+ bcc brzs4
+brzs3:
+ trap ;branch carry/no carry
+brzs4: bmi brzs5
+ bpl brzs6
+brzs5:
+ trap ;branch minus/plus
+brzs6: bvs brzs7
+ bvc brzs8
+brzs7:
+ trap ;branch overflow/no overflow
+brzs8:
+ set_stat carry
+ beq brcs1
+ bne brcs2
+brcs1:
+ trap ;branch zero/non zero
+brcs2: bcc brcs3
+ bcs brcs4
+brcs3:
+ trap ;branch carry/no carry
+brcs4: bmi brcs5
+ bpl brcs6
+brcs5:
+ trap ;branch minus/plus
+brcs6: bvs brcs7
+ bvc brcs8
+brcs7:
+ trap ;branch overflow/no overflow
+
+brcs8:
+ set_stat minus
+ beq brmi1
+ bne brmi2
+brmi1:
+ trap ;branch zero/non zero
+brmi2: bcs brmi3
+ bcc brmi4
+brmi3:
+ trap ;branch carry/no carry
+brmi4: bpl brmi5
+ bmi brmi6
+brmi5:
+ trap ;branch minus/plus
+brmi6: bvs brmi7
+ bvc brmi8
+brmi7:
+ trap ;branch overflow/no overflow
+brmi8:
+ set_stat overfl
+ beq brvs1
+ bne brvs2
+brvs1:
+ trap ;branch zero/non zero
+brvs2: bcs brvs3
+ bcc brvs4
+brvs3:
+ trap ;branch carry/no carry
+brvs4: bmi brvs5
+ bpl brvs6
+brvs5:
+ trap ;branch minus/plus
+brvs6: bvc brvs7
+ bvs brvs8
+brvs7:
+ trap ;branch overflow/no overflow
+brvs8:
+ set_stat $ff-zero
+ beq brzc1
+ bne brzc2
+brzc1:
+ trap ;branch zero/non zero
+brzc2: bcc brzc3
+ bcs brzc4
+brzc3:
+ trap ;branch carry/no carry
+brzc4: bpl brzc5
+ bmi brzc6
+brzc5:
+ trap ;branch minus/plus
+brzc6: bvc brzc7
+ bvs brzc8
+brzc7:
+ trap ;branch overflow/no overflow
+brzc8:
+ set_stat $ff-carry
+ bne brcc1
+ beq brcc2
+brcc1:
+ trap ;branch zero/non zero
+brcc2: bcs brcc3
+ bcc brcc4
+brcc3:
+ trap ;branch carry/no carry
+brcc4: bpl brcc5
+ bmi brcc6
+brcc5:
+ trap ;branch minus/plus
+brcc6: bvc brcc7
+ bvs brcc8
+brcc7:
+ trap ;branch overflow/no overflow
+brcc8:
+ set_stat $ff-minus
+ bne brpl1
+ beq brpl2
+brpl1:
+ trap ;branch zero/non zero
+brpl2: bcc brpl3
+ bcs brpl4
+brpl3:
+ trap ;branch carry/no carry
+brpl4: bmi brpl5
+ bpl brpl6
+brpl5:
+ trap ;branch minus/plus
+brpl6: bvc brpl7
+ bvs brpl8
+brpl7:
+ trap ;branch overflow/no overflow
+brpl8:
+ set_stat $ff-overfl
+ bne brvc1
+ beq brvc2
+brvc1:
+ trap ;branch zero/non zero
+brvc2: bcc brvc3
+ bcs brvc4
+brvc3:
+ trap ;branch carry/no carry
+brvc4: bpl brvc5
+ bmi brvc6
+brvc5:
+ trap ;branch minus/plus
+brvc6: bvs brvc7
+ bvc brvc8
+brvc7:
+ trap ;branch overflow/no overflow
+brvc8:
+ next_test
+
+; test PHA does not alter flags or accumulator but PLA does
+ ldx #$55 ;x & y protected
+ ldy #$aa
+ set_a 1,$ff ;push
+ pha
+ tst_a 1,$ff
+ set_a 0,0
+ pha
+ tst_a 0,0
+ set_a $ff,$ff
+ pha
+ tst_a $ff,$ff
+ set_a 1,0
+ pha
+ tst_a 1,0
+ set_a 0,$ff
+ pha
+ tst_a 0,$ff
+ set_a $ff,0
+ pha
+ tst_a $ff,0
+ set_a 0,$ff ;pull
+ pla
+ tst_a $ff,$ff-zero
+ set_a $ff,0
+ pla
+ tst_a 0,zero
+ set_a $fe,$ff
+ pla
+ tst_a 1,$ff-zero-minus
+ set_a 0,0
+ pla
+ tst_a $ff,minus
+ set_a $ff,$ff
+ pla
+ tst_a 0,$ff-minus
+ set_a $fe,0
+ pla
+ tst_a 1,0
+ cpx #$55 ;x & y unchanged?
+ trap_ne
+ cpy #$aa
+ trap_ne
+ next_test
+
+; partial pretest EOR #
+ set_a $3c,0
+ eor #$c3
+ tst_a $ff,fn
+ set_a $c3,0
+ eor #$c3
+ tst_a 0,fz
+ next_test
+
+; PC modifying instructions except branches (NOP, JMP, JSR, RTS, BRK, RTI)
+; testing NOP
+ ldx #$24
+ ldy #$42
+ set_a $18,0
+ nop
+ tst_a $18,0
+ cpx #$24
+ trap_ne
+ cpy #$42
+ trap_ne
+ ldx #$db
+ ldy #$bd
+ set_a $e7,$ff
+ nop
+ tst_a $e7,$ff
+ cpx #$db
+ trap_ne
+ cpy #$bd
+ trap_ne
+ next_test
+
+; jump absolute
+ set_stat $0
+ lda #'F'
+ ldx #'A'
+ ldy #'R' ;N=0, V=0, Z=0, C=0
+ jmp test_far
+ nop
+ nop
+ trap_ne ;runover protection
+ inx
+ inx
+far_ret:
+ trap_eq ;returned flags OK?
+ trap_pl
+ trap_cc
+ trap_vc
+ cmp #('F'^$aa) ;returned registers OK?
+ trap_ne
+ cpx #('A'+1)
+ trap_ne
+ cpy #('R'-3)
+ trap_ne
+ dex
+ iny
+ iny
+ iny
+ eor #$aa ;N=0, V=1, Z=0, C=1
+ jmp test_near
+ nop
+ nop
+ trap_ne ;runover protection
+ inx
+ inx
+test_near:
+ trap_eq ;passed flags OK?
+ trap_mi
+ trap_cc
+ trap_vc
+ cmp #'F' ;passed registers OK?
+ trap_ne
+ cpx #'A'
+ trap_ne
+ cpy #'R'
+ trap_ne
+ next_test
+
+; jump indirect
+ set_stat 0
+ lda #'I'
+ ldx #'N'
+ ldy #'D' ;N=0, V=0, Z=0, C=0
+ jmp (ptr_tst_ind)
+ nop
+ trap_ne ;runover protection
+ dey
+ dey
+ind_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 subroutine & return from subroutine
+ set_stat 0
+ lda #'J'
+ ldx #'S'
+ ldy #'R' ;N=0, V=0, Z=0, C=0
+ jsr test_jsr
+jsr_ret = *-1 ;last address of jsr = return address
+ 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 #('J'^$aa) ;returned registers OK?
+ trap_ne
+ cpx #('S'+1)
+ trap_ne
+ cpy #('R'-6)
+ trap_ne
+ tsx ;sp?
+ cpx #$ff
+ trap_ne
+ next_test
+
+; break & return from interrupt
+ .if ROM_vectors = 1
+ load_flag 0 ;with interrupts enabled if allowed!
+ pha
+ lda #'B'
+ ldx #'R'
+ ldy #'K'
+ plp ;N=0, V=0, Z=0, C=0
+ brk
+ .else
+ lda #>brk_ret0 ;emulated break
+ pha
+ lda #brk_ret1 ;emulated break
+ pha
+ lda #bin_rti_ret ;emulated interrupt for rti
+ pha
+ lda #dec_rti_ret ;emulated interrupt for rti
+ pha
+ lda #jsr_ret
+ trap_ne
+ lda $1fe
+ cmp #brk_ret0
+ trap_ne
+ lda $1fe
+ cmp #brk_ret1
+ trap_ne
+ lda $1fe
+ cmp # 1
+zp_init:
+zps_: .byte $80,1 ;additional shift pattern to test zero result & flag
+zp1_: .byte $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
+zp7f_: .byte $7f ;test pattern for compare
+;logical zeropage operands
+zpOR_: .byte 0,$1f,$71,$80 ;test pattern for OR
+zpAN_: .byte $0f,$ff,$7f,$80 ;test pattern for AND
+zpEO_: .byte $ff,$0f,$8f,$8f ;test pattern for EOR
+;indirect addressing pointers
+ind1_: .word abs1 ;indirect pointer to pattern in absolute memory
+ .word abs1+1
+ .word abs1+2
+ .word abs1+3
+ .word abs7f
+inw1_: .word abs1-$f8 ;indirect pointer for wrap-test pattern
+indt_: .word abst ;indirect pointer to store area in absolute memory
+ .word abst+1
+ .word abst+2
+ .word abst+3
+inwt_: .word abst-$f8 ;indirect pointer for wrap-test store
+indAN_: .word absAN ;indirect pointer to AND pattern in absolute memory
+ .word absAN+1
+ .word absAN+2
+ .word absAN+3
+indEO_: .word absEO ;indirect pointer to EOR pattern in absolute memory
+ .word absEO+1
+ .word absEO+2
+ .word absEO+3
+indOR_: .word absOR ;indirect pointer to OR pattern in absolute memory
+ .word absOR+1
+ .word absOR+2
+ .word absOR+3
+;add/subtract indirect pointers
+adi2_: .word ada2 ;indirect pointer to operand 2 in absolute memory
+sbi2_: .word sba2 ;indirect pointer to complemented operand 2 (SBC)
+adiy2_: .word ada2-$ff ;with offset for indirect indexed
+sbiy2_: .word sba2-$ff
+zp_end:
+ .if (zp_end - zp_init) <> (zp_bss_end - zp_bss)
+ ;force assembler error if size is different
+ .error "mismatch between bss and zeropage data"
+ .endif
+data_init:
+ex_and_:and #0 ;execute immediate opcodes
+ rts
+ex_eor_:eor #0 ;execute immediate opcodes
+ rts
+ex_ora_:ora #0 ;execute immediate opcodes
+ rts
+ex_adc_:adc #0 ;execute immediate opcodes
+ rts
+ex_sbc_:sbc #0 ;execute immediate opcodes
+ rts
+;zps: .byte $80,1 ;additional shift patterns test zero result & flag
+abs1_: .byte $c3,$82,$41,0 ;test patterns for LDx BIT ROL ROR ASL LSR
+abs7f_: .byte $7f ;test pattern for compare
+;loads
+fLDx_: .byte fn,fn,0,fz ;expected flags for load
+;shifts
+rASL_: ;expected result ASL & ROL -carry
+rROL_: .byte 0,2,$86,$04,$82,0
+rROLc_: .byte 1,3,$87,$05,$83,1 ;expected result ROL +carry
+rLSR_: ;expected result LSR & ROR -carry
+rROR_: .byte $40,0,$61,$41,$20,0
+rRORc_: .byte $c0,$80,$e1,$c1,$a0,$80 ;expected result ROR +carry
+fASL_: ;expected flags for shifts
+fROL_: .byte fzc,0,fnc,fc,fn,fz ;no carry in
+fROLc_: .byte fc,0,fnc,fc,fn,0 ;carry in
+fLSR_:
+fROR_: .byte 0,fzc,fc,0,fc,fz ;no carry in
+fRORc_: .byte fn,fnc,fnc,fn,fnc,fn ;carry in
+;increments (decrements)
+rINC_: .byte $7f,$80,$ff,0,1 ;expected result for INC/DEC
+fINC_: .byte 0,fn,fn,fz,0 ;expected flags for INC/DEC
+;logical memory operand
+absOR_: .byte 0,$1f,$71,$80 ;test pattern for OR
+absAN_: .byte $0f,$ff,$7f,$80 ;test pattern for AND
+absEO_: .byte $ff,$0f,$8f,$8f ;test pattern for EOR
+;logical accu operand
+absORa_:.byte 0,$f1,$1f,0 ;test pattern for OR
+absANa_:.byte $f0,$ff,$ff,$ff ;test pattern for AND
+absEOa_:.byte $ff,$f0,$f0,$0f ;test pattern for EOR
+;logical results
+absrlo_:.byte 0,$ff,$7f,$80
+absflo_:.byte fz,fn,0,fn
+data_end
+ .if (data_end - data_init) <> (data_bss_end - data_bss)
+ ;force assembler error if size is different
+ .error "mismatch between bss and data"
+ .endif
+
+vec_init
+ .word nmi_trap
+ .word res_trap
+ .word irq_trap
+vec_bss equ $fffa
+ .endif ;end of RAM init data
+
+ .if (load_data_direct = 1) & (ROM_vectors = 1)
+ .segment "VECTORS"
+ .org $fffa ;vectors
+ .word nmi_trap
+ .word res_trap
+ .word irq_trap
+ .endif
diff --git a/examples/asm/functional_test/Makefile b/examples/asm/functional_test/Makefile
new file mode 100644
index 0000000..ff35eea
--- /dev/null
+++ b/examples/asm/functional_test/Makefile
@@ -0,0 +1,3 @@
+build:
+ ca65 6502_functional_test.ca65
+ ld65 -C ../linker.cfg -o 6502_functional_test.bin 6502_functional_test.o
diff --git a/examples/asm/functional_test/README.md b/examples/asm/functional_test/README.md
index 8b457be..907825d 100644
--- a/examples/asm/functional_test/README.md
+++ b/examples/asm/functional_test/README.md
@@ -17,6 +17,14 @@ make build
This will create a `6502_functional_test.bin` file in the `build` directory,
which the emulator will load.
+## Running
+
+Then, from the root of the repository, run:
+
+```bash
+cargo run --release --example functional
+```
+
## Credits
Taken from