From dfc2c473272c078d849d200192dddc0b9dd1a55f Mon Sep 17 00:00:00 2001 From: "colin.liang" Date: Tue, 17 Jan 2023 16:09:28 +0800 Subject: [PATCH] Refine memory interface. --- picorv32.v | 403 ++++++++++++++++++++++++++++--------------------- testbench.cc | 8 +- testbench_wb.v | 30 ++-- 3 files changed, 242 insertions(+), 199 deletions(-) diff --git a/picorv32.v b/picorv32.v index 6acc639..d074c4f 100644 --- a/picorv32.v +++ b/picorv32.v @@ -33,7 +33,6 @@ `endif `define assert(assert_expr) empty_statement -`define FORMAL_KEEP /*************************************************************** * picorv32 @@ -44,22 +43,21 @@ module picorv32 #( parameter [31:0] STACKADDR = 32'hffff_ffff ) ( input clk, - resetn, + input resetn, output reg trap, output reg mem_valid, - output reg mem_instr, input mem_ready, - output reg [31:0] mem_addr, - output reg [31:0] mem_wdata, - output reg [ 3:0] mem_wstrb, - input [31:0] mem_rdata, + output [31:0] mem_addr, + output [31:0] mem_wdata, + output [ 3:0] mem_wstrb, + input [31:0] mem_rdata, // Look-Ahead Interface output mem_la_read, output mem_la_write, - output [31:0] mem_la_addr, + output reg [31:0] mem_la_addr, output reg [31:0] mem_la_wdata, output reg [ 3:0] mem_la_wstrb, @@ -85,21 +83,90 @@ module picorv32 #( reg [63:0] count_cycle, count_instr; reg [31:0] reg_pc, reg_next_pc, reg_op1, reg_op2, reg_out; - reg [4:0] reg_sh; - - reg [31:0] next_insn_opcode; + wire [31:0] next_pc; + reg [ 4:0] reg_sh; assign pcpi_rs1 = reg_op1; assign pcpi_rs2 = reg_op2; - wire [31:0] next_pc; + wire mem_xfer; + reg [31:0] mem_rdata_q; - task empty_statement; - // This task is used by the `assert directive in non-formal mode to - // avoid empty statement (which are unsupported by plain Verilog syntax). - begin + reg [1:0] mem_wordsize; + reg [31:0] mem_rdata_word; + + assign mem_la_addr = (mem_do_prefetch || mem_do_r_inst) ? {next_pc[31:2], 2'b00} : {reg_op1[31:2], 2'b00}; + + wire [31:0] mem_rdata_latched; + assign mem_rdata_latched = mem_xfer ? mem_rdata : mem_rdata_q; + + always @(posedge clk) begin + if (mem_xfer) begin + mem_rdata_q <= mem_rdata; end - endtask + end + + always @* begin + (* full_case *) + case (mem_wordsize) + 0: begin + mem_la_wdata = reg_op2; + mem_la_wstrb = 4'b1111; + mem_rdata_word = mem_rdata; + end + 1: begin + mem_la_wdata = {2{reg_op2[15:0]}}; + mem_la_wstrb = reg_op1[1] ? 4'b1100 : 4'b0011; + case (reg_op1[1]) + 1'b0: mem_rdata_word = {16'b0, mem_rdata[15:0]}; + 1'b1: mem_rdata_word = {16'b0, mem_rdata[31:16]}; + endcase + end + 2: begin + mem_la_wdata = {4{reg_op2[7:0]}}; + mem_la_wstrb = 4'b0001 << reg_op1[1:0]; + case (reg_op1[1:0]) + 2'b00: mem_rdata_word = {24'b0, mem_rdata[7:0]}; + 2'b01: mem_rdata_word = {24'b0, mem_rdata[15:8]}; + 2'b10: mem_rdata_word = {24'b0, mem_rdata[23:16]}; + 2'b11: mem_rdata_word = {24'b0, mem_rdata[31:24]}; + endcase + end + endcase + end + + reg mem_do_prefetch; + reg mem_do_r_inst; + reg mem_do_rdata; + reg mem_do_wdata; + wire mem_done; + + picorv32_memory memory ( + .clk(clk), + .resetn(resetn), + .trap(trap), + + .mem_valid(mem_valid), + .mem_ready(mem_ready), + .mem_xfer (mem_xfer), + + .mem_addr (mem_addr), + .mem_wdata(mem_wdata), + .mem_wstrb(mem_wstrb), + .mem_rdata(mem_rdata), + + .mem_la_read (mem_la_read), + .mem_la_write(mem_la_write), + .mem_la_addr (mem_la_addr), + .mem_la_wdata(mem_la_wdata), + .mem_la_wstrb(mem_la_wstrb), + + .mem_do_prefetch(mem_do_prefetch), + .mem_do_r_inst(mem_do_r_inst), + .mem_do_rdata(mem_do_rdata), + .mem_do_wdata(mem_do_wdata), + .mem_done(mem_done) + ); // Internal PCPI Cores @@ -164,160 +231,6 @@ module picorv32 #( endcase end - - // Memory Interface - - reg [1:0] mem_state; - reg [1:0] mem_wordsize; - reg [31:0] mem_rdata_word; - reg [31:0] mem_rdata_q; - reg mem_do_prefetch; - reg mem_do_r_inst; - reg mem_do_rdata; - reg mem_do_wdata; - - wire mem_xfer; - reg last_mem_valid; - - reg [15:0] mem_16bit_buffer; - - wire [31:0] mem_rdata_latched_noshuffle; - wire [31:0] mem_rdata_latched; - - assign mem_xfer = mem_valid && mem_ready; - - wire mem_busy = |{mem_do_prefetch, mem_do_r_inst, mem_do_rdata, mem_do_wdata}; - wire mem_done = resetn && ((mem_xfer && |mem_state && (mem_do_r_inst || mem_do_rdata || mem_do_wdata)) || (&mem_state && mem_do_r_inst)); - - assign mem_la_write = resetn && !mem_state && mem_do_wdata; - assign mem_la_read = resetn && ((!mem_state && (mem_do_r_inst || mem_do_prefetch || mem_do_rdata))); - assign mem_la_addr = (mem_do_prefetch || mem_do_r_inst) ? {next_pc[31:2], 2'b00} : {reg_op1[31:2], 2'b00}; - - assign mem_rdata_latched_noshuffle = mem_xfer ? mem_rdata : mem_rdata_q; - - assign mem_rdata_latched = mem_rdata_latched_noshuffle; - - always @(posedge clk) begin - if (!resetn) begin - last_mem_valid <= 0; - end else begin - if (!last_mem_valid) last_mem_valid <= mem_valid && !mem_ready; - end - end - - always @* begin - (* full_case *) - case (mem_wordsize) - 0: begin - mem_la_wdata = reg_op2; - mem_la_wstrb = 4'b1111; - mem_rdata_word = mem_rdata; - end - 1: begin - mem_la_wdata = {2{reg_op2[15:0]}}; - mem_la_wstrb = reg_op1[1] ? 4'b1100 : 4'b0011; - case (reg_op1[1]) - 1'b0: mem_rdata_word = {16'b0, mem_rdata[15:0]}; - 1'b1: mem_rdata_word = {16'b0, mem_rdata[31:16]}; - endcase - end - 2: begin - mem_la_wdata = {4{reg_op2[7:0]}}; - mem_la_wstrb = 4'b0001 << reg_op1[1:0]; - case (reg_op1[1:0]) - 2'b00: mem_rdata_word = {24'b0, mem_rdata[7:0]}; - 2'b01: mem_rdata_word = {24'b0, mem_rdata[15:8]}; - 2'b10: mem_rdata_word = {24'b0, mem_rdata[23:16]}; - 2'b11: mem_rdata_word = {24'b0, mem_rdata[31:24]}; - endcase - end - endcase - end - - always @(posedge clk) begin - if (mem_xfer) begin - mem_rdata_q <= mem_rdata; - next_insn_opcode <= mem_rdata; - end - end - - always @(posedge clk) begin - if (resetn && !trap) begin - if (mem_do_prefetch || mem_do_r_inst || mem_do_rdata) - `assert(!mem_do_wdata); - - if (mem_do_prefetch || mem_do_r_inst) - `assert(!mem_do_rdata); - - if (mem_do_rdata) - `assert(!mem_do_prefetch && !mem_do_r_inst); - - if (mem_do_wdata) - `assert(!(mem_do_prefetch || mem_do_r_inst || mem_do_rdata)); - - if (mem_state == 2 || mem_state == 3) - `assert(mem_valid || mem_do_prefetch); - end - end - - always @(posedge clk) begin - if (!resetn || trap) begin - if (!resetn) mem_state <= 0; - if (!resetn || mem_ready) mem_valid <= 0; - end else begin - if (mem_la_read || mem_la_write) begin - mem_addr <= mem_la_addr; - mem_wstrb <= mem_la_wstrb & {4{mem_la_write}}; - end - if (mem_la_write) begin - mem_wdata <= mem_la_wdata; - end - case (mem_state) - 0: begin - if (mem_do_prefetch || mem_do_r_inst || mem_do_rdata) begin - mem_valid <= 1; - mem_instr <= mem_do_prefetch || mem_do_r_inst; - mem_wstrb <= 0; - mem_state <= 1; - end - if (mem_do_wdata) begin - mem_valid <= 1; - mem_instr <= 0; - mem_state <= 2; - end - end - 1: begin - `assert(mem_wstrb == 0); - `assert(mem_do_prefetch || mem_do_r_inst || mem_do_rdata); - `assert(mem_valid == 1); - `assert(mem_instr == (mem_do_prefetch || mem_do_r_inst)); - if (mem_xfer) begin - mem_valid <= 0; - mem_state <= mem_do_r_inst || mem_do_rdata ? 0 : 3; - end - end - 2: begin - `assert(mem_wstrb != 0); - `assert(mem_do_wdata); - if (mem_xfer) begin - mem_valid <= 0; - mem_state <= 0; - end - end - 3: begin - `assert(mem_wstrb == 0); - `assert(mem_do_prefetch); - if (mem_do_r_inst) begin - mem_state <= 0; - end - end - endcase - end - end - - // Memory Interface End - - // Instruction Decoder reg instr_lui, instr_auipc, instr_jal, instr_jalr; @@ -459,8 +372,8 @@ module picorv32 #( if (decoder_trigger_q) begin cached_ascii_instr <= new_ascii_instr; cached_insn_imm <= decoded_imm; - if (&next_insn_opcode[1:0]) cached_insn_opcode <= next_insn_opcode; - else cached_insn_opcode <= {16'b0, next_insn_opcode[15:0]}; + if (&mem_rdata_q[1:0]) cached_insn_opcode <= mem_rdata_q; + else cached_insn_opcode <= {16'b0, mem_rdata_q[15:0]}; cached_insn_rs1 <= decoded_rs1; cached_insn_rs2 <= decoded_rs2; cached_insn_rd <= decoded_rd; @@ -489,8 +402,8 @@ module picorv32 #( dbg_insn_rd = cached_insn_rd; end else begin dbg_ascii_instr = new_ascii_instr; - if (&next_insn_opcode[1:0]) dbg_insn_opcode = next_insn_opcode; - else dbg_insn_opcode = {16'b0, next_insn_opcode[15:0]}; + if (&mem_rdata_q[1:0]) dbg_insn_opcode = mem_rdata_q; + else dbg_insn_opcode = {16'b0, mem_rdata_q[15:0]}; dbg_insn_imm = decoded_imm; dbg_insn_rs1 = decoded_rs1; dbg_insn_rs2 = decoded_rs2; @@ -789,7 +702,7 @@ module picorv32 #( set_mem_do_rdata = 0; set_mem_do_wdata = 0; - alu_out_q <= alu_out; + alu_out_q <= alu_out; if (launch_next_insn) begin dbg_rs1val <= 'bx; @@ -1359,3 +1272,141 @@ module picorv32_pcpi_div ( end end endmodule + +/*************************************************************** + * picorv32_memory + ***************************************************************/ + +module picorv32_memory ( + input clk, + input resetn, + input trap, + + output reg mem_valid, + input mem_ready, + output reg mem_xfer, + + output reg [31:0] mem_addr, + output reg [31:0] mem_wdata, + output reg [ 3:0] mem_wstrb, + input [31:0] mem_rdata, + + // Look-Ahead Interface + output mem_la_read, + output mem_la_write, + input [31:0] mem_la_addr, + input [31:0] mem_la_wdata, + input [ 3:0] mem_la_wstrb, + + + input mem_do_prefetch, + input mem_do_r_inst, + input mem_do_rdata, + input mem_do_wdata, + output mem_done +); + + task empty_statement; + // This task is used by the `assert directive in non-formal mode to + // avoid empty statement (which are unsupported by plain Verilog syntax). + begin + end + endtask + + reg [1:0] mem_state; + reg last_mem_valid; + reg [15:0] mem_16bit_buffer; + + reg mem_instr; + + assign mem_xfer = mem_valid && mem_ready; + + wire mem_busy = |{mem_do_prefetch, mem_do_r_inst, mem_do_rdata, mem_do_wdata}; + assign mem_done = resetn && ((mem_xfer && |mem_state && (mem_do_r_inst || mem_do_rdata || mem_do_wdata)) || (&mem_state && mem_do_r_inst)); + + assign mem_la_write = resetn && !mem_state && mem_do_wdata; + assign mem_la_read = resetn && ((!mem_state && (mem_do_r_inst || mem_do_prefetch || mem_do_rdata))); + + always @(posedge clk) begin + if (!resetn) begin + last_mem_valid <= 0; + end else begin + if (!last_mem_valid) last_mem_valid <= mem_valid && !mem_ready; + end + end + + always @(posedge clk) begin + if (resetn && !trap) begin + if (mem_do_prefetch || mem_do_r_inst || mem_do_rdata) + `assert(!mem_do_wdata); + + if (mem_do_prefetch || mem_do_r_inst) + `assert(!mem_do_rdata); + + if (mem_do_rdata) + `assert(!mem_do_prefetch && !mem_do_r_inst); + + if (mem_do_wdata) + `assert(!(mem_do_prefetch || mem_do_r_inst || mem_do_rdata)); + + if (mem_state == 2 || mem_state == 3) + `assert(mem_valid || mem_do_prefetch); + end + end + + always @(posedge clk) begin + if (!resetn || trap) begin + if (!resetn) mem_state <= 0; + if (!resetn || mem_ready) mem_valid <= 0; + end else begin + if (mem_la_read || mem_la_write) begin + mem_addr <= mem_la_addr; + mem_wstrb <= mem_la_wstrb & {4{mem_la_write}}; + end + if (mem_la_write) begin + mem_wdata <= mem_la_wdata; + end + case (mem_state) + 0: begin + if (mem_do_prefetch || mem_do_r_inst || mem_do_rdata) begin + mem_valid <= 1; + mem_instr <= mem_do_prefetch || mem_do_r_inst; + mem_wstrb <= 0; + mem_state <= 1; + end + if (mem_do_wdata) begin + mem_valid <= 1; + mem_instr <= 0; + mem_state <= 2; + end + end + 1: begin + `assert(mem_wstrb == 0); + `assert(mem_do_prefetch || mem_do_r_inst || mem_do_rdata); + `assert(mem_valid == 1); + `assert(mem_instr == (mem_do_prefetch || mem_do_r_inst)); + if (mem_xfer) begin + mem_valid <= 0; + mem_state <= mem_do_r_inst || mem_do_rdata ? 0 : 3; + end + end + 2: begin + `assert(mem_wstrb != 0); + `assert(mem_do_wdata); + if (mem_xfer) begin + mem_valid <= 0; + mem_state <= 0; + end + end + 3: begin + `assert(mem_wstrb == 0); + `assert(mem_do_prefetch); + if (mem_do_r_inst) begin + mem_state <= 0; + end + end + endcase + end + end + +endmodule diff --git a/testbench.cc b/testbench.cc index 6567167..66ffe99 100644 --- a/testbench.cc +++ b/testbench.cc @@ -40,13 +40,13 @@ int main(int argc, char** argv, char** env) { trace_fd = fopen("testbench.trace", "w"); } - top->wb_clk = 0; - top->wb_rst = 1; + top->clk = 0; + top->rst = 1; int t = 0; while (!Verilated::gotFinish()) { - if (t > 200) top->wb_rst = 0; - top->wb_clk = !top->wb_clk; + if (t > 200) top->rst = 0; + top->clk = !top->clk; top->eval(); if (tfp) tfp->dump(t); t += 5; diff --git a/testbench_wb.v b/testbench_wb.v index d1aa41d..351b458 100644 --- a/testbench_wb.v +++ b/testbench_wb.v @@ -3,16 +3,15 @@ module picorv32_wrapper #( parameter VERBOSE = 0 ) ( - input wb_clk, - input wb_rst, + input clk, + input rst, output trap, input [1024:0] hex_file ); wire exit; - wire mem_instr; reg [15:0] count_cycle = 0; - always @(posedge wb_clk) count_cycle <= !wb_rst ? count_cycle + 1 : 0; + always @(posedge clk) count_cycle <= !rst ? count_cycle + 1 : 0; wire [31:0] wb_m2s_adr; wire [31:0] wb_m2s_dat; @@ -26,10 +25,9 @@ module picorv32_wrapper #( picorv32_wb #() uut ( .trap(trap), .exit(exit), - .mem_instr(mem_instr), - .wb_clk_i(wb_clk), - .wb_rst_i(wb_rst) + .clk(clk), + .rst(rst) ); initial begin @@ -38,9 +36,9 @@ module picorv32_wrapper #( end integer cycle_counter; - always @(posedge wb_clk) begin - cycle_counter <= !wb_rst ? cycle_counter + 1 : 0; - if (!wb_rst && trap) begin + always @(posedge clk) begin + cycle_counter <= !rst ? cycle_counter + 1 : 0; + if (!rst && trap) begin $display("TRAP after %1d clock cycles", cycle_counter); if (exit) begin $display("ALL TESTS PASSED."); @@ -59,11 +57,8 @@ module picorv32_wb #( output trap, output reg exit, - // Wishbone interfaces - input wb_rst_i, - input wb_clk_i, - - output mem_instr + input rst, + input clk ); wire mem_valid; wire [31:0] mem_addr; @@ -84,12 +79,10 @@ module picorv32_wb #( wire [31:0] dbg_insn_addr; wire [63:0] dbg_ascii_instr; - wire clk; wire resetn; initial exit = 0; - assign clk = wb_clk_i; - assign resetn = ~wb_rst_i; + assign resetn = ~rst; picorv32 #( .PROGADDR_RESET(32'h0001_0000), @@ -100,7 +93,6 @@ module picorv32_wb #( .trap (trap), .mem_valid (mem_valid), - .mem_instr (mem_instr), .mem_ready (mem_ready), .mem_addr (mem_addr), .mem_wdata (mem_wdata),