diff --git a/6502_65C02_functional_tests/65C02_extended_opcodes_test.a65c b/6502_65C02_functional_tests/65C02_extended_opcodes_test.a65c deleted file mode 100644 index ea183e0..0000000 --- a/6502_65C02_functional_tests/65C02_extended_opcodes_test.a65c +++ /dev/null @@ -1,2882 +0,0 @@ -; -; 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-2017 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 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, STP & WAI are covered in the 6502_interrupt_test. -; -; version 04-dec-2017 -; 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 -; 28-aug-2015 fixed decimal adc/sbc immediate only testing carry -; 09-feb-2017 fixed RMB/SMB tested when they shouldn't be tested -; 04-dec-2017 fixed BRK not tested for actually going through the IRQ vector -; added option to skip the remainder of a failing test -; in report.i65 -; added skip override to undefined opcode as NOP test - - -; 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 - -;skip testing all undefined opcodes override -;0=test as NOP, >0=skip -skip_nop = 0 - -;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(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 - 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 -;break test interrupt save -irq_a ds 1 ;a register -irq_x ds 1 ;x register - 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(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 - -;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 - - if skip_nop = 0 - 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 - endif - -; 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 - 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 - dey ;should not be executed -brk_ret0 ;address of break return - php ;either SP or Y count will fail, if we do not hit - dey - dey - dey - cmp #'B'^$aa ;returned registers OK? - ;the IRQ vector was never executed if A & X stay unmodified - trap_ne - cpx #'R'+1 - trap_ne - cpy #'K'-6 - trap_ne - pla ;returned flags OK (unchanged)? - cmp_flag 0 - trap_ne - tsx ;sp? - cpx #$ff - trap_ne -;pass 2 - load_flag $ff ;with interrupts disabled if allowed! - pha - lda #$ff-'B' - ldx #$ff-'R' - ldy #$ff-'K' - plp ;N=1, V=1, Z=1, C=1 - brk - dey ;should not be executed -brk_ret1 ;address of break return - php ;either SP or Y count will fail, if we do not hit - dey - dey - dey - cmp #($ff-'B')^$aa ;returned registers OK? - ;the IRQ vector was never executed if A & X stay unmodified - trap_ne - cpx #$ff-'R'+1 - trap_ne - cpy #$ff-'K'-6 - trap_ne - pla ;returned flags OK (unchanged)? - cmp_flag $ff - trap_ne - tsx ;sp? - cpx #$ff - trap_ne - 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 = 1 -; 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 #$83 ;mask N-----ZC - cmp adrf - trap_ne ;bad flags - 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 #$83 ;mask N-----ZC - cmp adrf - trap_ne ;bad flags - 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 - jmp start ;catastrophic error - cannot continue - -; 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 start ;catastrophic error - cannot continue - -; JMP (abs,x) with bad x - nop - nop -trap_ind - nop - nop - trap ;near miss indexed indirect jump - jmp start ;catastrophic error - cannot continue - -;trap in case of unexpected IRQ, NMI, BRK, RESET -nmi_trap - trap ;check stack for conditions at NMI - jmp start ;catastrophic error - cannot continue -res_trap - trap ;unexpected RESET - jmp start ;catastrophic error - cannot continue - - dey - dey -irq_trap ;BRK test or unextpected BRK or IRQ - php ;either SP or Y count will fail, if we do not hit - dey - dey - dey - ;next traps could be caused by unexpected BRK or IRQ - ;check stack for BREAK and originating location - ;possible jump/branch into weeds (uninitialized space) - cmp #$ff-'B' ;BRK pass 2 registers loaded? - beq break2 - cmp #'B' ;BRK pass 1 registers loaded? - trap_ne - cpx #'R' - trap_ne - cpy #'K'-3 - trap_ne - sta irq_a ;save registers during break test - stx irq_x - tsx ;test break on stack - lda $102,x - cmp_flag 0 ;break test should have B=1 & unused=1 on stack - trap_ne ;possible no break flag on stack - pla - cmp_flag intdis ;should have added interrupt disable - trap_ne - tsx - cpx #$fc ;sp -3? (return addr, flags) - trap_ne - lda $1ff ;propper return on stack - cmp #hi(brk_ret0) - trap_ne - lda $1fe - cmp #lo(brk_ret0) - trap_ne - load_flag $ff - pha - ldx irq_x - inx ;return registers with modifications - lda irq_a - eor #$aa - plp ;N=1, V=1, Z=1, C=1 but original flags should be restored - rti - trap ;runover protection - jmp start ;catastrophic error - cannot continue - -break2 ;BRK pass 2 - cpx #$ff-'R' - trap_ne - cpy #$ff-'K'-3 - trap_ne - sta irq_a ;save registers during break test - stx irq_x - tsx ;test break on stack - lda $102,x - cmp_flag $ff ;break test should have B=1 - trap_ne ;possibly no break flag on stack - pla - cmp_flag $ff-decmode ;actual passed flags should have decmode cleared - trap_ne - tsx - cpx #$fc ;sp -3? (return addr, flags) - trap_ne - lda $1ff ;propper return on stack - cmp #hi(brk_ret1) - trap_ne - lda $1fe - cmp #lo(brk_ret1) - trap_ne - load_flag intdis - pha - ldx irq_x - inx ;return registers with modifications - lda irq_a - eor #$aa - plp ;N=0, V=0, Z=0, C=0 but original flags should be restored - rti - trap ;runover protection - jmp start ;catastrophic error - cannot continue - - 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 diff --git a/examples/1DLIFE.BAS b/examples/1DLIFE.BAS new file mode 100644 index 0000000..bafb83c --- /dev/null +++ b/examples/1DLIFE.BAS @@ -0,0 +1,24 @@ +10 REM ENDLESS RULE 30 +20 W=78 +30 DIM A(79),B(79) +40 FOR I=1 TO W +50 A(I)=INT(RND(1)*2) +60 NEXT I +70 E$=CHR$(27) +80 PRINT E$;"[2J";E$;"[H"; + +90 A(0)=A(W) +100 A(W+1)=A(1) + +110 FOR I=1 TO W +120 POKE 48128,32+10*A(I) +130 B(I)=ABS(A(I-1)-(A(I) OR A(I+1))) +140 NEXT I + +150 POKE 48128,10 + +160 FOR I=1 TO W +170 A(I)=B(I) +180 NEXT I + +190 GOTO 90 \ No newline at end of file diff --git a/msbasic/.gitignore b/msbasic/.gitignore deleted file mode 100644 index ff67fb5..0000000 --- a/msbasic/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tmp/ diff --git a/rom/init.s b/rom/init.s index b3a66b4..583737e 100644 --- a/rom/init.s +++ b/rom/init.s @@ -9,6 +9,7 @@ PR_WRITTEN_BY: COLD_START: lda #$00 sta CURDVC + sta LOAD_ACTIVE ldx #$FF stx CURLIN+1 ldx #$FB diff --git a/rom/loadsave.s b/rom/loadsave.s index 2ea209c..0d0c0b7 100644 --- a/rom/loadsave.s +++ b/rom/loadsave.s @@ -1,3 +1,320 @@ .segment "CODE" -; None yet \ No newline at end of file +LOADSAVE_LFN = $FF + +; ============================================================================ +; COPY STRING EXPRESSION TO FILE_NAME_BUFFER +; +; Entry: +; TXTPTR points at string expression +; +; Exit: +; FILE_NAME_BUFFER contains NUL-terminated filename +; +; Clobbers: +; A,X,Y,INDEX,STRNG2 +; ============================================================================ +PARSE_LOADSAVE_FILENAME: + jsr FRMEVL + jsr CHKSTR + jsr FREFAC + ; FREFAC: + ; A = length + ; INDEX = string address + sta STRNG2 + ldy #$00 +@copy: + cpy STRNG2 + beq @done + lda (INDEX),y + sta FILE_NAME_BUFFER,y + iny + bne @copy +@done: + lda #$00 + sta FILE_NAME_BUFFER,y + rts + +; ============================================================================ +; SET UP THE COMMON FILE ARGUMENTS +; ============================================================================ +LOADSAVE_SET_FILE: + lda #LOADSAVE_LFN + sta IO_FILE_DESCRIPTOR + lda #FILE_NAME_BUFFER + sta IO_FILE_DATA+1 + rts + +; ============================================================================ +; WAIT FOR FILE COMMAND COMPLETION +; +; Jumps to IQERR on host-side failure. +; ============================================================================ +LOADSAVE_WAIT: + lda IO_FILE_STATUS + and #FILE_STATUS_READY + beq LOADSAVE_WAIT + lda IO_FILE_STATUS + and #FILE_STATUS_ERROR + beq @ok + jmp IQERR +@ok: + rts + + +; ============================================================================ +; OPEN FOR READING +; ============================================================================ +LOADSAVE_OPEN_R: + jsr LOADSAVE_SET_FILE + lda #IO_COMMAND_OPEN_R + sta IO_FILE_COMMAND + jmp LOADSAVE_WAIT + +; ============================================================================ +; OPEN FOR WRITING / TRUNCATE +; ============================================================================ +LOADSAVE_OPEN_W: + jsr LOADSAVE_SET_FILE + lda #IO_COMMAND_OPEN_W + sta IO_FILE_COMMAND + jmp LOADSAVE_WAIT + +; ============================================================================ +; CLOSE INTERNAL LOAD/SAVE FILE +; ============================================================================ +LOADSAVE_CLOSE: + lda #LOADSAVE_LFN + sta IO_FILE_DESCRIPTOR + lda #IO_COMMAND_CLOSE + sta IO_FILE_COMMAND + jsr LOADSAVE_WAIT + jsr CLRCH + rts + +; ============================================================================ +; SAVE "filename" +; +; Saves plain ASCII BASIC source, equivalent to LIST output. +; ============================================================================ +SAVE: + jsr PARSE_LOADSAVE_FILENAME + jsr LOADSAVE_OPEN_W + ; Route OUTDO/CHROUT to our internal file. + ldx #LOADSAVE_LFN + jsr CHKOUT + stx CURDVC + ; Start with first BASIC line. + lda TXTTAB + sta LOWTRX + lda TXTTAB+1 + sta LOWTRX+1 +SAVE_NEXT_LINE: + ; The high byte of the forward link is zero at end of program. + ldy #$01 + lda (LOWTRX),y + beq SAVE_DONE + ; ------------------------------------------------------------ + ; Print line number. + ; + ; record: + ; +0/+1 = next line + ; +2/+3 = line number + ; +4... = tokenized body + ; ------------------------------------------------------------ + iny ; Y=2 + lda (LOWTRX),y + tax + iny ; Y=3 + lda (LOWTRX),y + jsr LINPRT + lda #' ' + jsr OUTDO + ; DATAFLG follows LIST's quoting/token rules. + lda #$01 + sta DATAFLG + ldy #$04 +SAVE_LINE_CHAR: + lda (LOWTRX),y + beq SAVE_LINE_DONE + ; Test whether it's plain ASCII/token BEFORE doing CMPs + bpl SAVE_PLAIN_CHAR + cmp #$FF + beq SAVE_PLAIN_CHAR + bit DATAFLG + bmi SAVE_PLAIN_CHAR + ; Token + sec + sbc #$7F + tax + sty FORPNT + ldy #$FF +SAVE_FIND_TOKEN: + dex + beq SAVE_TOKEN_FOUND +SAVE_SKIP_TOKEN: + iny + lda TOKEN_NAME_TABLE,y + bpl SAVE_SKIP_TOKEN + bmi SAVE_FIND_TOKEN +SAVE_TOKEN_FOUND: + iny + lda TOKEN_NAME_TABLE,y + bmi SAVE_TOKEN_LAST + jsr OUTDO + bne SAVE_TOKEN_FOUND +SAVE_TOKEN_LAST: + and #$7F + jsr OUTDO + ldy FORPNT + iny + jmp SAVE_LINE_CHAR +SAVE_PLAIN_CHAR: + and #$7F + jsr OUTDO + ; Quote state must be updated AFTER output/test. + cmp #$22 + bne SAVE_PLAIN_DONE + lda DATAFLG + eor #$FF + sta DATAFLG +SAVE_PLAIN_DONE: + iny + jmp SAVE_LINE_CHAR +SAVE_LINE_DONE: + ; Every saved source line ends in LF. + jsr LFDO + ; Follow next-line pointer. + ldy #$00 + lda (LOWTRX),y + tax + iny + lda (LOWTRX),y + stx LOWTRX + sta LOWTRX+1 + jmp SAVE_NEXT_LINE +SAVE_DONE: + jsr LOADSAVE_CLOSE + rts + +; ============================================================================ +; LOAD "filename" +; +; Replaces current program. +; Reads ASCII source one line at a time, tokenizes through the normal +; BASIC parser, and inserts using NUMBERED_LINE. +; +; IMPORTANT: +; NUMBERED_LINE eventually reaches FIX_LINKS -> SETPTRS -> STKINI, which +; resets the hardware stack. Therefore LOAD cannot expect NUMBERED_LINE to +; return with RTS. FIX_LINKS jumps back to LOAD_NEXT_LINE while LOAD_ACTIVE +; is set. +; ============================================================================ + +LOAD: + ; Copy the filename before SCRTCH destroys temporary strings. + jsr PARSE_LOADSAVE_FILENAME + jsr LOADSAVE_OPEN_R + ; Delete current program. + jsr SCRTCH + ; Route CHRIN to the file. + ldx #LOADSAVE_LFN + jsr CHKIN + stx CURDVC + ; Tell FIX_LINKS that program insertion belongs to LOAD. + lda #$01 + sta LOAD_ACTIVE +; ---------------------------------------------------------------------------- +; Entry point used both initially and by FIX_LINKS after inserting each line. +; Must be a globally visible label if FIX_LINKS lives in another source file. +; ---------------------------------------------------------------------------- +LOAD_NEXT_LINE: + ldx #$00 +; ---------------------------------------------------------------------------- +; Read one physical source line into INPUTBUFFER. +; +; "10 PRINT 1\n" -> normal line +; "10 PRINT 1" -> final line still accepted +; EOF with X=0 -> done loading +; ---------------------------------------------------------------------------- +@read_char: + jsr CHRIN + ; If host says EOF, A is not considered valid data. + pha + lda IO_FILE_STATUS + and #FILE_STATUS_EOF + bne @eof + pla + ; LF terminates a source line. + cmp #LF + beq @line_complete + ; Accept CRLF files too. + cmp #$0D + beq @read_char + ; Same practical line limit as interactive INLIN. + cpx #$47 + bcs @line_too_long + sta INPUTBUFFER,x + inx + jmp @read_char +@eof: + pla + ; EOF with no accumulated characters means real end of file. + cpx #$00 + beq @load_done + ; Otherwise process the unterminated final line. +@line_complete: + lda #$00 + sta INPUTBUFFER,x + ; Point CHRGET at INPUTBUFFER-1, exactly like INLIN returns. + lda #<(INPUTBUFFER-1) + sta TXTPTR + lda #>(INPUTBUFFER-1) + sta TXTPTR+1 + jsr CHRGET + ; Ignore empty physical lines. + beq LOAD_NEXT_LINE + ; A source file must consist of numbered program lines. + ; + ; CHRGET leaves carry clear for a leading decimal digit, + ; exactly like the normal RESTART path. + bcc @numbered + jmp @syntax_error +@numbered: + ; NUMBERED_LINE performs: + ; + ; LINGET + ; PARSE_INPUT_LINE + ; FNDLIN + ; PUT_NEW_LINE + ; FIX_LINKS + ; + ; DO NOT JSR here. + ; + ; FIX_LINKS eventually calls SETPTRS/STKINI, which resets the + ; hardware stack. FIX_LINKS will detect LOAD_ACTIVE and jump back + ; to LOAD_NEXT_LINE. + jmp NUMBERED_LINE +@line_too_long: +@syntax_error: + lda #$00 + sta LOAD_ACTIVE + + jsr CLRCH + jsr LOADSAVE_CLOSE + jmp SYNERR +@load_done: + lda #$00 + sta LOAD_ACTIVE + jsr CLRCH + jsr LOADSAVE_CLOSE + ; Do NOT JSR SETPTRS here. + ; + ; Every successfully inserted line already passed through + ; FIX_LINKS -> SETPTRS -> LE33D. + ; + ; Also do not RTS: SETPTRS/STKINI during loading may have destroyed + ; the original LOAD command's return frame. + jmp RESTART \ No newline at end of file diff --git a/rom/msbasic.s b/rom/msbasic.s index 9d3718c..133ccae 100644 --- a/rom/msbasic.s +++ b/rom/msbasic.s @@ -6,7 +6,6 @@ .include "defines.s" .include "macros.s" .include "zeropage.s" - .include "header.s" .include "token.s" .include "error.s" diff --git a/rom/program.s b/rom/program.s index 4f7e99e..47c1209 100644 --- a/rom/program.s +++ b/rom/program.s @@ -168,6 +168,10 @@ L23E6: FIX_LINKS: jsr SETPTRS jsr LE33D + lda LOAD_ACTIVE + beq :+ + jmp LOAD_NEXT_LINE +: jmp L2351 LE33D: lda TXTTAB @@ -201,7 +205,7 @@ L2405: ; !!! kbd_loadsave.s requires an RTS here! RET3: - rts + rts .include "inline.s" diff --git a/rom/token.s b/rom/token.s index a9c3c4b..f0acfd4 100644 --- a/rom/token.s +++ b/rom/token.s @@ -1,6 +1,6 @@ init_token_tables - keyword_rts "WOZMON", RESET + keyword_rts "WOZ", RESET keyword_rts "END", END keyword_rts "FOR", FOR @@ -21,6 +21,8 @@ keyword_rts "STOP", STOP keyword_rts "ON", ON keyword_rts "WAIT", WAIT + keyword_rts "LOAD", LOAD + keyword_rts "SAVE", SAVE keyword_rts "DEF", DEF keyword_rts "POKE", POKE keyword_rts "PRINT#", PRINTH diff --git a/rom/zeropage.s b/rom/zeropage.s index 13ebf11..eb93d80 100644 --- a/rom/zeropage.s +++ b/rom/zeropage.s @@ -151,6 +151,8 @@ STRNG2: .res 2 CURDVC: .res 1 +LOAD_ACTIVE: + .res 1 FILE_NAME_BUFFER = $0300 CHRGET: TXTPTR = <(GENERIC_TXTPTR-GENERIC_CHRGET + CHRGET)