gateware

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit 7e261c8ca945b3c6706392300e8d8dee2aaeffd8
parent 5360e1f6387ec4dd88adafbac3a19a2cad69bb30
Author: Brian Swetland <swetland@frotz.net>
Date:   Wed, 28 Nov 2018 14:59:49 -0800

cpu16: support memory write, implement writeback stage

Writeback will stall the pipeline if execute wants to
write simultaneously with writeback.

Memory hazards are not handled yet -- if you lw Ra, [Rb]
the contents of Ra will not update until two cycles later.

Diffstat:
Mhdl/cpu16.sv | 36++++++++++++++++++++++--------------
Atests/025-mem-write_read.s | 26++++++++++++++++++++++++++
2 files changed, 48 insertions(+), 14 deletions(-)

diff --git a/hdl/cpu16.sv b/hdl/cpu16.sv @@ -46,6 +46,11 @@ wire [15:0]pc_plus_1 = pc + 16'h0001; reg do_use_ra; reg do_use_rb; +// if writeback is writing the register file and execute wants to +// stall to let writeback win +wire stall_writeback = (ex_do_wreg_alu | ex_do_wr_link) & wb_wreg; + +//TODO better name: this is a write register conflict wire stall_write = ex_do_wreg_alu & ((do_use_ra & (ir_asel == ex_wsel)) | @@ -55,7 +60,7 @@ wire stall_branch = (ir_valid & (do_branch_imm | do_branch_reg | do_branch_cond)) | ex_do_branch_imm | ex_do_branch_reg | ex_do_branch_cond; -wire stall = (ir_valid & stall_write) | stall_branch; +wire stall = (ir_valid & stall_write) | stall_branch | stall_writeback; wire do_load_ir = ins_rd_rdy & (~stall); @@ -71,9 +76,9 @@ always_comb begin end ir_next = ins_rd_data; - // for write stalls we don't want to invalidate IR, + // for non-branch stalls we don't want to invalidate IR, // just hold off from updating it - ir_valid_next = stall_write ? ir_valid : do_load_ir; + ir_valid_next = (stall_write | stall_writeback) ? ir_valid : do_load_ir; end always_ff @(posedge clk) begin @@ -114,7 +119,6 @@ wire [15:0]ir_imm_s9 = { (ir_ext_rdy ? ir_ext_imm : ir_imm_s9_raw[15:4]), ir_imm // control signals reg do_wreg_alu; // write from alu -reg do_wreg_mem; // write from memory reg do_adata_zero; // pass 0 to alu.xdata (instead of adata) reg do_bdata_imm; // pass imm to alu.ydata (instead of bdata) reg do_wr_link; // write PC + 1 to LR @@ -131,7 +135,6 @@ always_comb begin do_use_ra = 1'b0; do_use_rb = 1'b0; do_wreg_alu = 1'b0; - do_wreg_mem = 1'b0; do_adata_zero = 1'b0; do_bdata_imm = 1'b0; do_wr_link = 1'b0; @@ -205,15 +208,18 @@ wire [15:0]ex_adata; wire [15:0]ex_bdata; wire [15:0]ex_alu_rdata; +reg [2:0]wb_wsel = 3'b0; +reg wb_wreg = 1'b0; + regs16 regs( .clk(clk), .asel(ir_asel), .bsel(do_mem_write ? ir_csel : ir_bsel), - .wsel(ex_wsel), - .wreg(ex_do_wreg_alu | ex_do_wr_link), + .wsel(wb_wreg ? wb_wsel : ex_wsel), + .wreg(wb_wreg | ex_do_wreg_alu | ex_do_wr_link), .adata(ex_adata), .bdata(ex_bdata), - .wdata(ex_do_wr_link ? ex_link : ex_alu_rdata) + .wdata(wb_wreg ? dat_rd_data : (ex_do_wr_link ? ex_link : ex_alu_rdata)) ); // ---- EXECUTE ---- @@ -223,7 +229,6 @@ reg [15:0]ex_link = 16'b0; reg [2:0]ex_alu_op = 3'b0; reg [2:0]ex_wsel = 3'b0; reg ex_do_wreg_alu = 1'b0; -reg ex_do_wreg_mem = 1'b0; reg ex_do_adata_zero = 1'b0; reg ex_do_bdata_imm = 1'b0; reg ex_do_wr_link = 1'b0; @@ -250,7 +255,7 @@ assign trace = { ex_wsel, ex_do_wreg_alu, - ex_do_wreg_mem, + 1'b0, ex_do_adata_zero, ex_do_bdata_imm, ex_do_branch_imm, @@ -263,14 +268,13 @@ assign trace = { `endif always_ff @(posedge clk) begin - if (ir_valid && (~stall_write)) begin + if (ir_valid && (~(stall_write | stall_writeback))) begin ex_branch_tgt <= pc + (do_branch_imm ? ir_imm_s11 : ir_imm_s7); ex_link <= ir_link; // for mem-read or mem-write we use the ALU for Ra + imm7 ex_alu_op <= (do_adata_zero | do_mem_read | do_mem_write) ? 3'b0 : ir_alu_op; ex_wsel <= do_wr_link ? 3'd7 : ir_csel; ex_do_wreg_alu <= do_wreg_alu; - ex_do_wreg_mem <= do_wreg_mem; ex_do_adata_zero <= do_adata_zero; ex_do_bdata_imm <= do_bdata_imm; ex_do_wr_link <= do_wr_link; @@ -281,12 +285,11 @@ always_ff @(posedge clk) begin ex_do_mem_read <= do_mem_read; ex_do_mem_write <= do_mem_write; ex_imm <= (do_mem_read | do_mem_write) ? ir_imm_s6 : (do_use_imm9_or_imm6 ? ir_imm_s9 : ir_imm_s6); - end else begin + end else if (~stall_writeback) begin // if invalid, parameters are unchanged but actions // must all be disabled // TODO: better names to differentiate ex_do_wreg_alu <= 1'b0; - ex_do_wreg_mem <= 1'b0; ex_do_wr_link <= 1'b0; ex_do_branch_imm <= 1'b0; ex_do_branch_reg <= 1'b0; @@ -309,6 +312,11 @@ assign dat_wr_data = ex_bdata; assign dat_rd_req = ex_do_mem_read; assign dat_wr_req = ex_do_mem_write; +always_ff @(posedge clk) begin + wb_wreg <= ex_do_mem_read; + wb_wsel <= ex_wsel; +end + // ---- SIMULATION DEBUG ASSIST ---- `ifdef verilator diff --git a/tests/025-mem-write_read.s b/tests/025-mem-write_read.s @@ -0,0 +1,26 @@ +mov r7, 0 +mov r6, 0 +mov r5, 0 +mov r4, 0 +mov r3, 0 +mov r0, 0x1234 +mov r1, 0x80 +sw r0, [r1] +nop +nop +lw r2, [r1] +mov r7, 0x77 +mov r6, 0x66 +mov r5, 0x55 +nop +halt + +;0080 1234 +;R0 1234 +;R1 0080 +;R2 1234 +;R3 0000 +;R4 0000 +;R5 0055 +;R6 0066 +;R7 0077