From af6386a7cb0eb3b58cd754956dca300d416cbcde Mon Sep 17 00:00:00 2001 From: Rutherther Date: Sat, 23 Dec 2023 23:40:20 +0100 Subject: [PATCH] fix: jumping should flush two registers --- src/cpu.sv | 86 ++++++++++++++++++++------------------------ src/stages/decode.sv | 4 +-- src/stages/fetch.sv | 3 +- 3 files changed, 43 insertions(+), 50 deletions(-) diff --git a/src/cpu.sv b/src/cpu.sv index d32b092b1cf14b524c7844cb479d3c805fe8c035..b9a3dc603d6a35754193dec074efa59dd3eae6e1 100755 --- a/src/cpu.sv +++ b/src/cpu.sv @@ -6,7 +6,7 @@ module cpu( // program memory input [31:0] instruction, - output reg [31:0] pc, + output [31:0] pc, // ram output [31:0] memory_address, @@ -26,60 +26,51 @@ module cpu( reg [31:0] reg_write; wire reg_we; - reg [2:0] last_non_ready_stage; reg all_stages_ready; wire jump; wire [31:0] jumping_pc_next; - stage_status_t stages_in[1:4]; + stage_status_t fetch_out; + stage_status_t decode_out; + stage_status_t execute_out; + stage_status_t memory_access_out; - /// verilator doesn't like that data taken from stages_out[i] - // are used in stages_out[i + 1]. But that shouldn't really matter - // as there is not really a cyclic dependency. - // It just seems that verilator is not very good at "separating" - // array elements -/* verilator lint_off UNOPTFLAT */ - stage_status_t stages_out[0:3]; -/* verilator lint_on UNOPTFLAT */ + stage_status_t decode_in; + stage_status_t execute_in; + stage_status_t memory_access_in; + stage_status_t writeback_in; - assign ebreak = stages_out[ACCESS].instruction.ebreak; + assign ebreak = memory_access_out.instruction.ebreak; // stage registers always_ff @(posedge clk) begin if (rst_n == 0) begin - for (int i = 0; i < $size(stages_in); i++) begin - stages_in[i].data.address = 0; - end + decode_in.data.address = 0; + execute_in.data.address = 0; + memory_access_in.data.address = 0; + writeback_in.data.address = 0; end else begin - for (int i = 0; i < $size(stages_in); i++) begin - if (all_stages_ready || i >= last_non_ready_stage) begin - stages_in[i + 1] = stages_out[i]; - end - end + if (decode_out.ready && execute_out.ready && memory_access_out.ready) + decode_in = fetch_out; + if (execute_out.ready && memory_access_out.ready) + execute_in = decode_out; + if (memory_access_out.ready) + memory_access_in = execute_out; + writeback_in = memory_access_out; end end - // find first non ready stage. Stages before that will be stalled - always_comb begin - last_non_ready_stage = 0; - all_stages_ready = 1'b1; - for (int i = 0; i < $size(stages_out); i++) begin - if (!stages_out[i].ready) begin - last_non_ready_stage = i[2:0]; - all_stages_ready = 1'b0; - end - end - end + assign all_stages_ready = fetch_out.ready && decode_out.ready && execute_out.ready && memory_access_out.ready; always_comb begin - if (jump) + if (!all_stages_ready) + pc_next = pc; + else if (jump) pc_next = jumping_pc_next; - else if (all_stages_ready) // assume no jump. If jump, if result will be thrown out + else // assume no jump. If jump, if result will be thrown out pc_next = pc + 4; - else // stalling (in any stage, meaning not fetching new instructions) - pc_next = pc; end // data for forwarding from the stages @@ -87,35 +78,36 @@ module cpu( // just because verilator didn't like it as an array // consider switching back to array. forwarding_data_status_t data_in_pipeline; - assign data_in_pipeline.execute_out = stages_out[EXECUTE].data; - assign data_in_pipeline.access_out = stages_out[ACCESS].data; - assign data_in_pipeline.writeback_in = stages_in[WRITEBACK].data; + assign data_in_pipeline.execute_out = execute_out.data; + assign data_in_pipeline.access_out = memory_access_out.data; + assign data_in_pipeline.writeback_in = writeback_in.data; fetch fetch_inst( .clk(clk), .pc(pc), + .flush(jump), .mem_instruction(instruction), - .stage_out(stages_out[FETCH]) + .stage_out(fetch_out) ); decode decode_inst( .clk(clk), - .jump(jump), + .flush(jump), .data_in_pipeline(data_in_pipeline), .reg_a_1(reg_a_1), .reg_a_2(reg_a_2), .reg_rd1(reg_rd1), .reg_rd2(reg_rd2), - .stage_in(stages_in[DECODE]), - .stage_out(stages_out[DECODE]) + .stage_in(decode_in), + .stage_out(decode_out) ); execute execute_inst( .clk(clk), .jump(jump), .jump_pc(jumping_pc_next), - .stage_in(stages_in[EXECUTE]), - .stage_out(stages_out[EXECUTE]) + .stage_in(execute_in), + .stage_out(execute_out) ); memory_access memory_access_inst( @@ -125,8 +117,8 @@ module cpu( .memory_write(memory_write), .memory_we(memory_we), .memory_address(memory_address), - .stage_in(stages_in[ACCESS]), - .stage_out(stages_out[ACCESS]) + .stage_in(memory_access_in), + .stage_out(memory_access_out) ); writeback writeback_inst( @@ -134,7 +126,7 @@ module cpu( .reg_a_write(reg_a_w), .reg_we(reg_we), .reg_write(reg_write), - .stage_in(stages_in[WRITEBACK]) + .stage_in(writeback_in) ); register_file #(.WIDTH(WIDTH), .ADDRESS_LENGTH(5)) register_file_inst( diff --git a/src/stages/decode.sv b/src/stages/decode.sv index 1433d2a87f06ba5b728bbce59f1cd77ddc775ef9..9e34b8cac20c2e64139c6a7c388a712e6187f008 100644 --- a/src/stages/decode.sv +++ b/src/stages/decode.sv @@ -10,7 +10,7 @@ module decode( input [31:0] reg_rd1, input [31:0] reg_rd2, - input jump, + input flush, input stage_status_t stage_in, output stage_status_t stage_out @@ -104,7 +104,7 @@ module decode( wire stalling; assign stalling = (uses_reg_rd1 && stall_1) || (uses_reg_rd2 && stall_2); - assign stage_out.valid = !jump && !stalling && stage_in.valid; + assign stage_out.valid = !flush && !stalling && stage_in.valid; assign stage_out.ready = !stalling || !stage_in.valid; // if input is not valid, do not care about stalling... endmodule diff --git a/src/stages/fetch.sv b/src/stages/fetch.sv index 505f31452327ec1c609e6f241ac863b8dd404e83..f7fef3564db1492990f56625a033010e585ec635 100644 --- a/src/stages/fetch.sv +++ b/src/stages/fetch.sv @@ -2,6 +2,7 @@ import cpu_types::*; module fetch( input clk, + input flush, input [31:0] pc, input [31:0] mem_instruction, @@ -10,6 +11,6 @@ module fetch( assign stage_out.instruction.instruction = mem_instruction; assign stage_out.pc = pc; - assign stage_out.valid = 1; + assign stage_out.valid = !flush; assign stage_out.ready = 1; endmodule