; All read-modify-write-instructions on 6502 have a particular glitch: ; They first write back the unmodified value; then, the modified value. ; ; This test requires that the PPU open bus behavior is accurately emulated. ; Cycle accuracy will not be tested. ; ; ; Expected output: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; TEST: cpu_dummy_writes_ppumem ; This program verifies that the ; CPU does 2x writes properly. ; Any read-modify-write opcode ; should first write the origi- ; nal value; then the calculated ; value exactly 1 cycle later. ; ; Verifying open bus behavior. ; W- W- WR W- W- W- W- WR ; 2000+ 0 1 2 3 4 5 6 7 ; R0: 0- 0- 00 0- 0- 0- 0- 00 ; R1: 0- 0- 00 0- 0- 0- 0- 00 ; R3: 0- 0- 00 0- 0- 0- 0- 00 ; R5: 0- 0- 00 0- 0- 0- 0- 00 ; R6: 0- 0- 00 0- 0- 0- 0- 00 ; OK; Verifying opcodes... ; 0E2E4E6ECEEE 1E3E5E7EDEFE ; 0F2F4F6FCFEF 1F3F5F7FDFFF ; 03234363C3E3 13335373D3F3 ; 1B3B5B7BDBFB ; ; Passed ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Written by Joel Yliluoma - http://iki.fi/bisqwit/ .segment "LIB" .include "shell.inc" .include "colors.inc" .include "crc_fast.s" .segment "CODE" ;OFFICIAL_ONLY = 0 zp_res num_fails zp_res num_fails_2, 2 zp_res open_bus_test_failed zp_res opcode_ptr, 2 zp_res opcode_buffer, 8 zp_res temp_read_result zp_res temp_ppu_ptr, 2 zp_res temp_open_bus zp_res temp_x zp_res x_position zp_res ptr_2006, 2 .macro fail_if_y_not n, fail_label cpy #n bne fail_label .endmacro ; Test open bus feature ; puts A into $2000+X ; reads from $2000+Y ; expects A open_bus_test: sta $2000,x cmp $2000,y bne test_failed_finish rts .macro do_open_bus_test test_no,name,poke_value,a_index,b_index set_test test_no,name lda #poke_value ldx #a_index ldy #b_index jsr open_bus_test .endmacro .macro do_open_bus_test1 poke_value,a_index,b_index lda #poke_value ldx #a_index ldy #b_index jsr open_bus_test .endmacro ; Set PPU addr to A*0x100+X ; Preserved: A,X; gobbled: Y set_vram_pos: ldy PPUSTATUS sta PPUADDR ; poke high 6 bits stx PPUADDR ; poke low 8 bits rts test_failed_finish: ; Re-enable screen jsr clear_vram_garbage jsr console_show jmp test_failed main: ; Operations we will be doing are: ; ; $2400->$27FF is nicely usable (secondary name table). ; ; INC ->$2526 ; DEC ->$2524 ; ; ASL ->$254A ; LSR ->$2512 ; ROR ->$2512 or $2592 ; ROL ->$254A or $254B ; ; SLO ->$252A ; SRE ->$2512 ; RRA ->$2512 or $2592 ; RLA ->$254A or $254B ; lda #0 sta open_bus_test_failed jsr intro jsr init_random jsr populate_vram_slow ; leaves display hidden ; First, verify that PPU memory I/O works as expected ; jsr test_one_byte_buffer jsr test_2005_writes jsr test_sequential_memory_read jsr test_sequential_memory_write jsr console_show jsr test_rom_write jsr test_open_bus_behavior ; Then do the actual test! ; jsr populate_vram_slow lda #$00 sta $2000 jsr test_dummy_writes ; lda num_fails_2 ora num_fails_2+1 beq :+ jsr wait_vbl text_color1 ldx num_fails_2 lda num_fails_2+1 jsr print_dec16 print_str " OPCODES FAILED THE TEST" text_white jmp test_failed_finish : ; Now, when the dummy-write tests have been done (and passed), ; verify whether we failed the open bus test earlier. ; If it failed, do not give a clean exit status. lda open_bus_test_failed beq end_tests jsr wait_vbl print_str "Opcodes worked fine, but..." set_test 10,"Open bus behavior is wrong." jmp test_failed_finish end_tests: jsr clear_vram_garbage jsr console_show jsr wait_vbl jmp tests_passed .pushseg .segment "RODATA" Opcodes: ; Opcodes to test: ; * 0E (RMW) ASL abs U 0F (RMW) SLO abs (ASL+ORA) ; * 2E (RMW) ROL abs U 2F (RMW) RLA abs (ROL+AND) ; * 4E (RMW) LSR abs U 4F (RMW) SRE abs (LSR+EOR) ; * 6E (RMW) ROR abs U 6F (RMW) RRA abs (ROR+ADC) ; * CE (RMW) DEC abs U CF (RMW) DCP abs (DEC+CMP) ; * EE (RMW) INC abs U EF (RMW) ISB abs (INC+SBC) ; ; * 1E (RMW) ASL absx U 1F (RMW) SLO absx (ASL+ORA) U 1B (RMW) SLO absy (ASL+ORA) ; * 3E (RMW) ROL absx U 3F (RMW) RLA absx (ROL+AND) U 3B (RMW) RLA absy (ROL+AND) ; * 5E (RMW) LSR absx U 5F (RMW) SRE absx (LSR+EOR) U 5B (RMW) SRE absy (LSR+EOR) ; * 7E (RMW) ROR absx U 7F (RMW) RRA absx (ROR+ADC) U 7B (RMW) RRA absy (ROR+ADC) ; * DE (RMW) DEC absx U DF (RMW) DCP absx (DEC+CMP) U DB (RMW) DCP absy (DEC+CMP) ; * FE (RMW) INC absx U FF (RMW) ISB absx (INC+SBC) U FB (RMW) ISB absy (INC+SBC) ; ; K 12 (RMW) ASL ix U 03 (RMW) SLO ix (ASL+ORA) U 13 (RMW) SLO iy (ASL+ORA) ; K 32 (RMW) ROL ix U 23 (RMW) RLA ix (ROL+AND) U 33 (RMW) RLA iy (ROL+AND) ; K 52 (RMW) LSR ix U 43 (RMW) SRE ix (LSR+EOR) U 53 (RMW) SRE iy (LSR+EOR) ; K 72 (RMW) ROR ix U 63 (RMW) RRA ix (ROR+ADC) U 73 (RMW) RRA iy (ROR+ADC) ; K D2 (RMW) DEC ix U C3 (RMW) DCP ix (DEC+CMP) U D3 (RMW) DCP iy (DEC+CMP) ; K F2 (RMW) INC ix U E3 (RMW) ISB ix (INC+SBC) U F3 (RMW) ISB iy (INC+SBC) ; ; Format: Opcode number ($00 for end, $01 for newline, $02 for space) ; Value for absolute address (appended to opcode) (BIG-ENDIAN) ; Value for X ; Value for PPU address (BIG_ENDIAN) -- this is used in order to avoid false positives. ; Value for open bus ($2005) -- this is the expected first byte ; Expected 2nd reads from $2007 with Carry Set, Carry Clear (two bytes) ; Each opcode will be tried twice. Once with carry clear, once with carry set ; opcode ABS X PPUADDR OpenBus READ1 READ2 ; OFFICIAL OPCODES .byte $0E, $20,$06, $00, $25,$FA, $25, $CA, $CA ; ASL,254A .byte $2E, $20,$06, $00, $25,$FA, $25, $CA, $CB ; ROL,254A or 254B .byte $4E, $20,$06, $00, $25,$FA, $25, $92, $92 ; LSR,2512 .byte $6E, $20,$06, $00, $25,$FA, $25, $92, $12 ; ROR,2512 or $2592 .byte $CE, $20,$06, $00, $25,$FA, $25, $A4, $A4 ; DEC,2524 .byte $EE, $20,$06, $00, $25,$FA, $25, $A6, $A6 ; INC,2526 ---Expect: reads open bus, gets $25 (Vaddr = $25FA) ; writes $2006 <- $25 (taddr = $2525) ; writes $2006 <- $26 (Vaddr = $2526) ; 2*read $2007 -> $A6 .byte $02 ; .byte $1E, $20,$05, $01, $25,$FA, $26, $0C, $0C ; ASL,$264C .byte $3E, $20,$01, $05, $25,$FA, $26, $0C, $0D ; ROL,$264C or $264D .byte $5E, $20,$04, $02, $25,$FA, $26, $D3, $D3 ; LSR,$2613 .byte $7E, $20,$02, $04, $25,$FA, $26, $D3, $53 ; ROR,$2613 or $2693 .byte $DE, $20,$04, $02, $25,$FA, $26, $E5, $E5 ; DEC,$2625 .byte $FE, $20,$03, $03, $25,$FA, $26, $E7, $E7 ; INC,$2627 ; .byte $01 ; ; UNOFFICIAL OPCODES ; .byte $0F, $20,$06, $00, $25,$FA, $25, $CA, $CA ; SLO,254A .byte $2F, $20,$06, $00, $25,$FA, $25, $CA, $CB ; RLA,254A or 254B .byte $4F, $20,$06, $00, $25,$FA, $25, $92, $92 ; SRE,2512 .byte $6F, $20,$06, $00, $25,$FA, $25, $92, $12 ; RRA,2512 or $2592 .byte $CF, $20,$06, $00, $25,$FA, $25, $A4, $A4 ; DCP,2524 .byte $EF, $20,$06, $00, $25,$FA, $25, $A6, $A6 ; ISB,2526 ; .byte $02 ; .byte $1F, $20,$05, $01, $25,$FA, $26, $0C, $0C ; SLO,$264C .byte $3F, $20,$01, $05, $25,$FA, $26, $0C, $0D ; RLA,$264C or $264D .byte $5F, $20,$04, $02, $25,$FA, $26, $D3, $D3 ; SRE,$2613 .byte $7F, $20,$02, $04, $25,$FA, $26, $D3, $53 ; RRA,$2613 or $2693 .byte $DF, $20,$04, $02, $25,$FA, $26, $E5, $E5 ; DCP,$2625 .byte $FF, $20,$03, $03, $25,$FA, $26, $E7, $E7 ; ISB,$2627 ; .byte $01 ; ; UNOFFICIAL OPCODES ; .byte $03, $EA,