From 3c8df897699e613330c52c43909792770c46df7d Mon Sep 17 00:00:00 2001 From: Byron Lathi Date: Mon, 4 May 2026 23:00:32 -0700 Subject: [PATCH] Add branches --- sim/verilog6502_32bit_test.py | 83 +++++++++++++++++++++++++++++++++++ src/cpu_65c02.v | 60 ++++++++++++++++++------- 2 files changed, 128 insertions(+), 15 deletions(-) diff --git a/sim/verilog6502_32bit_test.py b/sim/verilog6502_32bit_test.py index ee06ad9..95f73c7 100644 --- a/sim/verilog6502_32bit_test.py +++ b/sim/verilog6502_32bit_test.py @@ -646,6 +646,89 @@ async def test_irq(dut): assert int(dut.RDY_O.value) == 0 +@cocotb.test +async def test_bra_always(dut): + cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start()) + cocotb.start_soon(handle_memory(dut)) + + write_dword(0xfffffff4, 0xfffffd) + + # L1: bra L1 0x80 0x03 + # nop + # nop + # L2: bra L2 + + write_bytes(0xfffffd, [0x80, 0x3, 0x00, 0x00, 0x00, 0x80, 0xfe]) + + dut.RDY.value = Immediate(1) + + dut.reset.value = Immediate(1) + for _ in range(10): + await RisingEdge(dut.clk) + dut.reset.value = 0 + + count = 0 + + async def count_address(): + nonlocal count + while True: + await RisingEdge(dut.clk) + if int(dut.AB.value) == 0x01000004: + count+=1 + + cocotb.start_soon(count_address()) + + await Timer(1, "us") + + assert count > 0 + +@cocotb.test +async def test_bra_never(dut): + cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start()) + cocotb.start_soon(handle_memory(dut)) + + write_dword(0xfffffff4, 0xfffffd) + + # lda #$00 + # bne + # wai + + write_bytes(0xfffffd, [0xa9, 0x00, 0xd0, 0x7f, 0xd0, 0x80, 0xd0, 0xfe, 0xcb]) + + + 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, + (0x00fffffd, False, None), + (0x00fffffe, False, None), + (0x00ffffff, False, None), + (0x01000000, False, None), + (0x01000001, False, None), + (0x01000002, False, None), + (0x01000003, False, None), + (0x01000004, False, None), + (0x01000005, False, None), + (0x01000006, False, None), + (0x01000006, False, None), + (0x01000006, False, None), + ] + + await check_instruction_sequence(dut, expected_cpu_outputs) + @cocotb.test async def test_adc(dut): cocotb.start_soon(Clock(dut.clk, CLK_PERIOD, unit="ns").start()) diff --git a/src/cpu_65c02.v b/src/cpu_65c02.v index 7816a93..b9886d3 100644 --- a/src/cpu_65c02.v +++ b/src/cpu_65c02.v @@ -72,6 +72,7 @@ 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 reg [7:0] alu_sr_1; // ALU output shift register 1 +reg [7:0] alu_sr_2; // ALU output shift register 2 reg [7:0] DIHOLD; // Hold for Data In reg DIHOLD_valid; // @@ -294,7 +295,10 @@ parameter RTS3 = 7'd76, RTS4 = 7'd77, RTI4 = 7'd78, - RTI5 = 7'd79; + RTI5 = 7'd79, + BRA3 = 7'd80, + BRA4 = 7'd81, + BRA5 = 7'd82; `ifdef SIM @@ -371,6 +375,9 @@ always @* BRA0: statename = "BRA0"; BRA1: statename = "BRA1"; BRA2: statename = "BRA2"; + BRA3: statename = "BRA3"; + BRA4: statename = "BRA4"; + BRA5: statename = "BRA5"; JMP0: statename = "JMP0"; JMP1: statename = "JMP1"; JMP2: statename = "JMP2"; @@ -415,11 +422,12 @@ always @* RTS5: PC_temp = { DIMUX, ADD, alu_sr_0, alu_sr_1} + 2; - - BRA1: PC_temp = { ABR[15:8], ADD }; + BRA1: PC_temp = AB; + BRA2: PC_temp = AB; + BRA3: PC_temp = AB; + BRA4: PC_temp = AB; JMPIX4, - BRA2: PC_temp = { ADD, PC[7:0] }; // TODO BRK4: PC_temp = res ? 32'hFFFFFFF4 : NMI_edge ? 32'hFFFFFFF8 : 32'hFFFFFFFC; @@ -452,7 +460,11 @@ always @* ABSX2, FETCH, BRA0, + BRA1, BRA2, + BRA3, + BRA4, + BRA5, BRK5, JMPI0, JMPI1, @@ -502,11 +514,13 @@ always @* RTI6, ABS3: AB = { DIMUX, ADD, alu_sr_0, alu_sr_1}; - BRA2, JMPIX4, ABSX4: AB = { ADD, ABR[23:0] }; // TODO - BRA1: AB = { ABR[15:8], ADD }; // TODO + BRA1: AB = { ABR[31:8], ADD }; + BRA2: AB = { ABR[31:16], ADD, alu_sr_0 }; + BRA3: AB = { ABR[31:24], ADD, alu_sr_0, alu_sr_1 }; + BRA4: AB = { ADD, alu_sr_0, alu_sr_1, alu_sr_2 }; JSR0, PUSH1, @@ -782,6 +796,7 @@ always @(posedge clk) begin alu_sr_0 <= DIMUX; end alu_sr_1 <= alu_sr_0; + alu_sr_2 <= alu_sr_1; end end @@ -812,7 +827,10 @@ always @* case( state ) READ: alu_op = op; - BRA1: alu_op = backwards ? OP_SUB : OP_ADD; + BRA1, + BRA2, + BRA3, + BRA4: alu_op = OP_ADD; FETCH, REG : alu_op = op; @@ -849,7 +867,7 @@ always @* */ always @(posedge clk) - if( RDY ) + if( RDY && state == BRA0) backwards <= DIMUX[7]; /* @@ -893,7 +911,10 @@ always @* BRA0, READ: AI = DIMUX; - BRA1: AI = ABR[15:8]; // don't use PCH in case we're TODO + BRA1, + BRA2, + BRA3, + BRA4: AI = backwards ? 8'hff : 0; FETCH: AI = load_only ? 8'b0 : regfile; @@ -910,7 +931,6 @@ always @* always @* case( state ) - BRA1, RTS1, RTS2, RTS3, @@ -937,7 +957,10 @@ always @* READ: BI = txb_ins ? (trb_ins ? ~regfile : regfile) : 8'h00; - BRA0: BI = PC[7:0]; // TODO + BRA0: BI = ABR[7:0]; + BRA1: BI = ABR[15:8]; + BRA2: BI = ABR[23:16]; + BRA3: BI = ABR[31:24]; DECODE, ABS3: BI = 8'hxx; @@ -953,6 +976,8 @@ always @* case( state ) INDY2, BRA1, + BRA2, + BRA3, JMPIX1, ABSX1, ABSX2, @@ -1250,8 +1275,11 @@ always @(posedge clk or posedge reset) RTS5 : state <= FETCH; BRA0 : state <= cond_true ? BRA1 : DECODE; - BRA1 : state <= (CO ^ backwards) ? BRA2 : DECODE; - BRA2 : state <= DECODE; + BRA1 : state <= (CO ^ backwards) ? BRA2 : BRA5; + BRA2 : state <= (CO ^ backwards) ? BRA3 : BRA5; + BRA3 : state <= (CO ^ backwards) ? BRA4 : BRA5; + BRA4 : state <= BRA5; + BRA5 : state <= DECODE; JMP0 : state <= JMP1; JMP1 : state <= JMP2; @@ -1284,14 +1312,16 @@ always @(posedge clk or posedge reset) else if( RDY ) case( state ) BRA0 : SYNC <= !cond_true; BRA1 : SYNC <= !(CO ^ backwards); - BRA2, + BRA2 : SYNC <= !(CO ^ backwards); + BRA3 : SYNC <= !(CO ^ backwards); + BRA4 : SYNC <= !(CO ^ backwards); FETCH, REG, PUSH1, PULL2, RTI6, JMP3, - BRA2 : SYNC <= 1'b1; + BRA5 : SYNC <= 1'b1; default: SYNC <= 1'b0; endcase