From dfe27d4ec783cbc8e3f03a18853f24042a6a0c89 Mon Sep 17 00:00:00 2001 From: Byron Lathi Date: Mon, 27 Apr 2026 21:59:30 -0700 Subject: [PATCH] Add indexed indirect --- sim/verilog6502_32bit_test.py | 64 +++++++++++++++++++++++++++++++++++ src/cpu_65c02.v | 47 ++++++++++++++++++------- 2 files changed, 99 insertions(+), 12 deletions(-) diff --git a/sim/verilog6502_32bit_test.py b/sim/verilog6502_32bit_test.py index 575c7df..21d084d 100644 --- a/sim/verilog6502_32bit_test.py +++ b/sim/verilog6502_32bit_test.py @@ -339,3 +339,67 @@ async def test_indirect(dut): ] await check_instruction_sequence(dut, expected_cpu_outputs) + +@cocotb.test +async def test_indexed_indirect(dut): + cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start()) + cocotb.start_soon(handle_memory(dut)) + + write_dword(0xfffffff4, 0x200) + + # ldy #1 + # lda ($04),y + # iny + # inc + # sta ($04),y + write_bytes(0x200, [0xa0, 0x02]) + write_bytes(0x202, [0xb1, 0x04]) + write_bytes(0x204, [0xc8]) + write_bytes(0x205, [0x1a]) + write_bytes(0x206, [0x91, 0x04]) + write_byte(0x208, 0xcb) + + write_dword(0x04, 0xabcdbeef) + write_dword(0xabcdbeef+2, 0xaa) + + dut.RDY.value = Immediate(1) + + dut.reset.value = Immediate(1) + for _ in range(10): + await RisingEdge(dut.clk) + dut.reset.value = 0 + + expected_cpu_outputs = [ + None, # ignore reset sequence + None, + None, + None, + None, + None, + None, + None, + None, + (0x00000200, False, None), # ldy #0 + (0x00000201, False, None), # Immediate + (0x00000202, False, None), # lda ($04),y + (0x00000203, False, None), # ZP index + (0x00000004, False, None), # zp addr 0 + (0x00000005, False, None), # zp addr 1 + (0x00000006, False, None), # zp addr 2 + (0x00000007, False, None), # zp addr 3 + (0xabcdbef1, False, None), # fetch data + (0x00000204, False, None), # iny + (0x00000205, False, None), # iny + (0x00000205, False, None), # inc + (0x00000206, False, None), # inc + (0x00000206, False, None), # sta ($04),y + (0x00000207, False, None), # ZP index + (0x00000004, False, None), # zp addr 0 + (0x00000005, False, None), # zp addr 1 + (0x00000006, False, None), # zp addr 2 + (0x00000007, False, None), # zp addr 3 + (0xabcdbef2, False, None), # store takes extra cycle + (0xabcdbef2, True, 0xAB), # write data + ] + + await check_instruction_sequence(dut, expected_cpu_outputs) \ No newline at end of file diff --git a/src/cpu_65c02.v b/src/cpu_65c02.v index de8b6bd..76e8eef 100644 --- a/src/cpu_65c02.v +++ b/src/cpu_65c02.v @@ -67,6 +67,7 @@ output reg SYNC; // AB is first cycle of the intruction */ reg [31:0] PC; // Program Counter +reg abr_inc; // should increase address bus register reg [31:0] ABR; // Address Bus Register wire [7:0] ADD; // Adder Hold Register (registered in ALU) reg [7:0] alu_sr_0; // ALU output shift register 0 @@ -226,10 +227,10 @@ parameter INDX1 = 7'd15, // (ZP,X) - fetch LSB at ZP+X, calculate ZP+X+1 INDX2 = 7'd16, // (ZP,X) - fetch MSB at ZP+X+1 INDX3 = 7'd17, // (ZP,X) - fetch data - INDY0 = 7'd18, // (ZP),Y - fetch ZP address, and send ZP to ALU (+1) - INDY1 = 7'd19, // (ZP),Y - fetch at ZP+1, and send LSB to ALU (+Y) - INDY2 = 7'd20, // (ZP),Y - fetch data, and send MSB to ALU (+Carry) - INDY3 = 7'd21, // (ZP),Y) - fetch data (if page boundary crossed) + INDY0 = 7'd18, // (ZP),Y - fetch ZP address + INDY1 = 7'd19, // (ZP),Y - fetch at ZP+1, and send byte 0 to ALU (+Y) + INDY2 = 7'd20, // (ZP),Y - fetch at ZP+2, and send byte 1 to ALU (+Carry) + INDY5 = 7'd21, // (ZP),Y) - fetch data (if page boundary crossed) JMP0 = 7'd22, // JMP - fetch PCL and hold JMP1 = 7'd23, // JMP - fetch PCH JMPI0 = 7'd24, // JMP IND - fetch LSB and send to ALU for delay (+0) @@ -274,7 +275,9 @@ parameter JMPIX3 = 7'd63, // TODO JMPIX4 = 7'd64, // TODO JMPI2 = 7'd65, // TODO - JMPI3 = 7'd66; // TODO + JMPI3 = 7'd66, // TODO + INDY3 = 7'd67, // (ZP),Y - fetch at ZP+3, and send byte 2 to ALU (+Carry) + INDY4 = 7'd68; // (ZP),Y - fetch data, and send byte 3 to ALU (+Carry) `ifdef SIM @@ -308,6 +311,8 @@ always @* INDY1: statename = "INDY1"; INDY2: statename = "INDY2"; INDY3: statename = "INDY3"; + INDY4: statename = "INDY4"; + INDY5: statename = "INDY5"; READ: statename = "READ"; WRITE: statename = "WRITE"; FETCH: statename = "FETCH"; @@ -454,14 +459,12 @@ always @* JMPIX3, ABSX3, INDX3, - INDY2, JMP3, JMPI3, RTI4, ABS3: AB = { DIMUX, ADD, alu_sr_0, alu_sr_1}; BRA2, - INDY3, JMPIX4, ABSX4: AB = { ADD, ABR[23:0] }; // TODO @@ -485,7 +488,6 @@ always @* BRK3, BRK4: AB = { 16'h0, STACKPAGE, ADD }; - INDY1, INDX1, ZPX1, INDX2: AB = { ZEROPAGE, ADD }; @@ -495,8 +497,14 @@ always @* REG, READ, + INDY1, + INDY2, + INDY3, WRITE: AB = ABR; + INDY4: AB = {DIMUX, ADD, alu_sr_0, alu_sr_1}; + INDY5: AB = {ADD, ABR[23:0]}; + default: AB = PC; endcase @@ -509,9 +517,22 @@ always @(posedge clk) if( state != PUSH0 && state != PUSH1 && RDY && state != PULL0 && state != PULL1 && state != PULL2 ) begin - ABR <= AB; + if (abr_inc) begin + ABR <= AB + 1; + end else begin + ABR <= AB; + end end +always @* begin + case( state ) + INDY0, + INDY1, + INDY2: abr_inc = 1; + default: abr_inc = 0; + endcase +end + /* * Data Out MUX */ @@ -558,7 +579,7 @@ always @* WRITE: WE = 1; INDX3, // only if doing a STA, STX or STY - INDY3, + INDY5, ABSX4, ABS3, ZPX1, @@ -1088,8 +1109,10 @@ always @(posedge clk or posedge reset) INDY0 : state <= INDY1; INDY1 : state <= INDY2; - INDY2 : state <= (CO | store) ? INDY3 : FETCH; - INDY3 : state <= FETCH; + INDY2 : state <= INDY3; + INDY3 : state <= INDY4; + INDY4 : state <= (CO | store) ? INDY5 : FETCH; + INDY5 : state <= FETCH; READ : state <= WRITE; WRITE : state <= FETCH;