diff --git a/README.md b/README.md index 186a1db..8845db7 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ Run the compliance tests cd riscv-compliance && make TARGETDIR=$SERV/riscv-target RISCV_TARGET=serv RISCV_DEVICE=rv32i RISCV_ISA=rv32i TARGET_SIM=$WORKSPACE/build/servant_1.1.0/verilator_tb-verilator/Vservant_sim -The above will run all tests in the rv32i test suite. Since SERV also implement the `rv32Zicsr` and `rv32Zifencei` extensions, these can also be tested by choosing any of them instead of rv32i as the `RISCV_ISA` variable. +The above will run all tests in the rv32i test suite. Since SERV also implement the `rv32im`, `rv32Zicsr` and `rv32Zifencei` extensions, these can also be tested by choosing any of them instead of rv32i as the `RISCV_ISA` variable. ## Run on hardware diff --git a/data/verilator_waiver.vlt b/data/verilator_waiver.vlt index 218fd16..b3a94e7 100644 --- a/data/verilator_waiver.vlt +++ b/data/verilator_waiver.vlt @@ -1,7 +1,17 @@ `verilator_config // Bits [1:0] in i_ibus_rdt are not used at all -lint_off -rule UNUSED -file "*/serv_top.v" -lines 52 +lint_off -rule UNUSED -file "*/serv_top.v" -lines 53 //Some bits in the instruction word are not used in serv_decode but it's easier //to just send in the whole word than picking out bits lint_off -rule UNUSED -file "*/serv_decode.v" -lines 7 + +//Some variables are only used when we connect an Extension with serv_decode +lint_off -rule UNUSED -file "*/serv_top.v" -lines 65 +lint_off -rule UNUSED -file "*/serv_bufreg.v" -lines 10 +lint_off -rule UNUSED -file "*/serv_decode.v" -lines 8 +lint_off -rule UNUSED -file "*/serv_decode.v" -lines 69 +lint_off -rule UNUSED -file "*/serv_mem_if.v" -lines 23 +lint_off -rule UNUSED -file "*/serv_mem_if.v" -lines 71 +lint_off -rule UNUSED -file "*/serv_state.v" -lines 47 +lint_off -rule UNUSED -file "*/serv_state.v" -lines 49 diff --git a/rtl/serv_bufreg.v b/rtl/serv_bufreg.v index 7d32b42..dcf2354 100644 --- a/rtl/serv_bufreg.v +++ b/rtl/serv_bufreg.v @@ -1,12 +1,14 @@ -module serv_bufreg - ( +module serv_bufreg #( + parameter [0:0] MDU = 0 +)( input wire i_clk, //State input wire i_cnt0, input wire i_cnt1, input wire i_en, input wire i_init, - output reg [1:0] o_lsb, + input wire i_mdu_op, + output wire [1:0] o_lsb, //Control input wire i_rs1_en, input wire i_imm_en, @@ -17,11 +19,14 @@ module serv_bufreg input wire i_imm, output wire o_q, //External - output wire [31:0] o_dbus_adr); + output wire [31:0] o_dbus_adr, + //Extension + output wire [31:0] o_ext_rs1); wire c, q; reg c_r; reg [31:2] data; + reg [1:0] lsb; wire clr_lsb = i_cnt0 & i_clr_lsb; @@ -35,11 +40,16 @@ module serv_bufreg data <= {i_init ? q : (data[31] & i_sh_signed), data[31:3]}; if (i_init ? (i_cnt0 | i_cnt1) : i_en) - o_lsb <= {i_init ? q : data[2],o_lsb[1]}; - + lsb <= {i_init ? q : data[2],lsb[1]}; end - assign o_q = o_lsb[0] & i_en; + assign o_q = lsb[0] & i_en; assign o_dbus_adr = {data, 2'b00}; + assign o_ext_rs1 = {o_dbus_adr[31:2],lsb}; + + generate + if (MDU) assign o_lsb = i_mdu_op ? 2'b00 : lsb; + else assign o_lsb = lsb; + endgenerate endmodule diff --git a/rtl/serv_decode.v b/rtl/serv_decode.v index b675901..f4eb7cf 100644 --- a/rtl/serv_decode.v +++ b/rtl/serv_decode.v @@ -1,7 +1,8 @@ `default_nettype none -module serv_decode #( - parameter [0:0] PRE_REGISTER = 1 -)( +module serv_decode + #(parameter [0:0] PRE_REGISTER = 1, + parameter [0:0] MDU = 0) + ( input wire clk, //Input input wire [31:2] i_wb_rdt, @@ -17,6 +18,10 @@ module serv_decode #( output reg o_shift_op, output reg o_slt_op, output reg o_rd_op, + //MDU + output reg o_mdu_op, + //Extension + output reg [2:0] o_ext_funct3, //To bufreg output reg o_bufreg_rs1_en, output reg o_bufreg_imm_en, @@ -61,8 +66,33 @@ module serv_decode #( reg op22; reg op26; + reg imm25; reg imm30; +generate + wire co_mdu_op; + wire [2:0]co_ext_funct3; + wire co_shift_op; + wire co_slt_op; + wire co_mem_word; + wire co_rd_alu_en; + + if (MDU) begin + assign co_mdu_op = ((opcode == 5'b01100) & imm25); + assign co_shift_op = op_or_opimm & (funct3[1:0] == 2'b01) & !co_mdu_op; + assign co_slt_op = op_or_opimm & (funct3[2:1] == 2'b01) & !co_mdu_op; + assign co_mem_word = co_mdu_op ? co_mdu_op :funct3[1]; + assign co_rd_alu_en = !opcode[0] & opcode[2] & !opcode[4] & !co_mdu_op; + end else begin + assign co_mdu_op = 1'b0; + assign co_shift_op = op_or_opimm & (funct3[1:0] == 2'b01); + assign co_slt_op = op_or_opimm & (funct3[2:1] == 2'b01); + assign co_mem_word = funct3[1]; + assign co_rd_alu_en = !opcode[0] & opcode[2] & !opcode[4]; + end + assign co_ext_funct3 = funct3; +endgenerate + //opcode wire op_or_opimm = (!opcode[4] & opcode[2] & !opcode[0]); @@ -109,13 +139,6 @@ module serv_decode #( wire co_sh_right = funct3[2]; wire co_bne_or_bge = funct3[0]; - // - // opcode & funct3 - // - - wire co_shift_op = op_or_opimm & (funct3[1:0] == 2'b01); - wire co_slt_op = op_or_opimm & (funct3[2:1] == 2'b01); - //Matches system ops except eceall/ebreak/mret wire csr_op = opcode[4] & opcode[2] & (|funct3); @@ -190,7 +213,6 @@ module serv_decode #( wire co_mem_cmd = opcode[3]; wire co_mem_signed = ~funct3[2]; - wire co_mem_word = funct3[1]; wire co_mem_half = funct3[0]; wire [1:0] co_alu_bool_op = funct3[1:0]; @@ -220,8 +242,6 @@ module serv_decode #( //1 (OP_B_SOURCE_RS2) when BRANCH or OP wire co_op_b_source = opcode[3]; - wire co_rd_alu_en = !opcode[0] & opcode[2] & !opcode[4]; - generate if (PRE_REGISTER) begin @@ -229,6 +249,7 @@ module serv_decode #( if (i_wb_en) begin funct3 <= i_wb_rdt[14:12]; imm30 <= i_wb_rdt[30]; + imm25 <= i_wb_rdt[25]; opcode <= i_wb_rdt[6:2]; op20 <= i_wb_rdt[20]; op21 <= i_wb_rdt[21]; @@ -248,6 +269,8 @@ module serv_decode #( o_shift_op = co_shift_op; o_slt_op = co_slt_op; o_rd_op = co_rd_op; + o_mdu_op = co_mdu_op; + o_ext_funct3 = co_ext_funct3; o_bufreg_rs1_en = co_bufreg_rs1_en; o_bufreg_imm_en = co_bufreg_imm_en; o_bufreg_clr_lsb = co_bufreg_clr_lsb; @@ -285,6 +308,7 @@ module serv_decode #( always @(*) begin funct3 = i_wb_rdt[14:12]; imm30 = i_wb_rdt[30]; + imm25 = i_wb_rdt[25]; opcode = i_wb_rdt[6:2]; op20 = i_wb_rdt[20]; op21 = i_wb_rdt[21]; @@ -304,6 +328,8 @@ module serv_decode #( o_shift_op <= co_shift_op; o_slt_op <= co_slt_op; o_rd_op <= co_rd_op; + o_mdu_op <= co_mdu_op; + o_ext_funct3 <= co_ext_funct3; o_bufreg_rs1_en <= co_bufreg_rs1_en; o_bufreg_imm_en <= co_bufreg_imm_en; o_bufreg_clr_lsb <= co_bufreg_clr_lsb; diff --git a/rtl/serv_mem_if.v b/rtl/serv_mem_if.v index fbdc3c4..ee688ac 100644 --- a/rtl/serv_mem_if.v +++ b/rtl/serv_mem_if.v @@ -1,6 +1,7 @@ `default_nettype none module serv_mem_if - #(parameter WITH_CSR = 1) + #(parameter WITH_CSR = 1, + parameter [0:0] MDU = 0) ( input wire i_clk, //State @@ -18,6 +19,8 @@ module serv_mem_if input wire i_signed, input wire i_word, input wire i_half, + //MDU + input wire i_mdu_op, //Data input wire i_op_b, output wire o_rd, @@ -58,7 +61,17 @@ module serv_mem_if (i_bytecnt == 2'b00) | (i_half & !i_bytecnt[1]); - assign o_rd = i_mem_op & (dat_valid ? dat_cur : signbit & i_signed); + wire mem_rd = i_mem_op & (dat_valid ? dat_cur : signbit & i_signed); + + generate + if(MDU) begin + wire mdu_rd = i_mdu_op & dat_cur; + assign o_rd = mem_rd | mdu_rd; + end else begin + wire mdu_rd = 1'b0; + assign o_rd = mem_rd; + end + endgenerate assign o_wb_sel[3] = (i_lsb == 2'b11) | i_word | (i_half & i_lsb[1]); assign o_wb_sel[2] = (i_lsb == 2'b10) | i_word; diff --git a/rtl/serv_rf_top.v b/rtl/serv_rf_top.v index 3f41373..6dab9f7 100644 --- a/rtl/serv_rf_top.v +++ b/rtl/serv_rf_top.v @@ -2,7 +2,10 @@ module serv_rf_top #(parameter RESET_PC = 32'd0, - + /* Multiplication and Division Unit + This parameter enables the interface for connecting SERV and MDU + */ + parameter [0:0] MDU = 0, /* Register signals before or after the decoder 0 : Register after the decoder. Faster but uses more resources 1 : (default) Register before the decoder. Slower but uses less resources @@ -55,8 +58,17 @@ module serv_rf_top output wire o_dbus_we , output wire o_dbus_cyc, input wire [31:0] i_dbus_rdt, - input wire i_dbus_ack); - + input wire i_dbus_ack, + + // Extension + output wire [31:0] o_ext_rs1, + output wire [31:0] o_ext_rs2, + output wire [ 2:0] o_ext_funct3, + input wire [31:0] i_ext_rd, + input wire i_ext_ready, + // MDU + output wire o_mdu_valid); + localparam CSR_REGS = WITH_CSR*4; wire rf_wreq; @@ -120,7 +132,8 @@ module serv_rf_top #(.RESET_PC (RESET_PC), .PRE_REGISTER (PRE_REGISTER), .RESET_STRATEGY (RESET_STRATEGY), - .WITH_CSR (WITH_CSR)) + .WITH_CSR (WITH_CSR), + .MDU(MDU)) cpu ( .clk (clk), @@ -174,7 +187,16 @@ module serv_rf_top .o_dbus_we (o_dbus_we), .o_dbus_cyc (o_dbus_cyc), .i_dbus_rdt (i_dbus_rdt), - .i_dbus_ack (i_dbus_ack)); + .i_dbus_ack (i_dbus_ack), + + //Extension + .o_ext_funct3 (o_ext_funct3), + .i_ext_ready (i_ext_ready), + .i_ext_rd (i_ext_rd), + .o_ext_rs1 (o_ext_rs1), + .o_ext_rs2 (o_ext_rs2), + //MDU + .o_mdu_valid (o_mdu_valid)); endmodule `default_nettype wire diff --git a/rtl/serv_state.v b/rtl/serv_state.v index 7fa088a..dfe2ff8 100644 --- a/rtl/serv_state.v +++ b/rtl/serv_state.v @@ -1,6 +1,7 @@ module serv_state #(parameter RESET_STRATEGY = "MINI", - parameter [0:0] WITH_CSR = 1) + parameter [0:0] WITH_CSR = 1, + parameter [0:0] MDU = 0) ( input wire i_clk, input wire i_rst, @@ -41,11 +42,16 @@ module serv_state output wire [1:0] o_mem_bytecnt, input wire i_mem_misalign, output reg o_cnt_done, - output wire o_bufreg_en); + output wire o_bufreg_en, + //MDU + input wire i_mdu_op, + output wire o_mdu_valid, + input wire i_mdu_ready); reg stage_two_req; reg init_done; wire misalign_trap_sync; + wire two_stage_op; reg [4:2] o_cnt; reg [3:0] o_cnt_r; @@ -74,8 +80,34 @@ module serv_state //been calculated. wire take_branch = i_branch_op & (!i_cond_branch | (i_alu_cmp^i_bne_or_bge)); - //slt*, branch/jump, shift, load/store - wire two_stage_op = i_slt_op | i_mem_op | i_branch_op | i_shift_op; +generate + if (MDU) begin + //slt*, branch/jump, shift, load/store + assign two_stage_op = i_slt_op | i_mem_op | i_branch_op | i_shift_op | i_mdu_op; + + //valid signal for mdu + assign o_mdu_valid = !o_cnt_en & init_done & i_mdu_op; + + //Prepare RF for writes when everything is ready to enter stage two + // and the first stage didn't cause a misalign exception + assign o_rf_wreq = !misalign_trap_sync & + ((i_shift_op & (i_sh_done | !i_sh_right) & !o_cnt_en & init_done) | + (i_mem_op & i_dbus_ack) | i_mdu_ready | + (stage_two_req & (i_slt_op | i_branch_op))); + end else begin + //slt*, branch/jump, shift, load/store + assign two_stage_op = i_slt_op | i_mem_op | i_branch_op | i_shift_op; + + //valid signal for mdu turned-off + assign o_mdu_valid = 1'b0; + + //Prepare RF for writes when everything is ready to enter stage two + // and the first stage didn't cause a misalign exception + assign o_rf_wreq = !misalign_trap_sync & + ((i_shift_op & (i_sh_done | !i_sh_right) & !o_cnt_en & init_done) | + (i_mem_op & i_dbus_ack) | (stage_two_req & (i_slt_op | i_branch_op))); + end +endgenerate assign o_dbus_cyc = !o_cnt_en & init_done & i_mem_op & !i_mem_misalign; @@ -83,13 +115,6 @@ module serv_state // or when stage one caused an exception (rreq implies a write request too) assign o_rf_rreq = i_ibus_ack | (stage_two_req & misalign_trap_sync); - //Prepare RF for writes when everything is ready to enter stage two - // and the first stage didn't cause a misalign exception - assign o_rf_wreq = !misalign_trap_sync & - ((i_shift_op & (i_sh_done | !i_sh_right) & !o_cnt_en & init_done) | - (i_mem_op & i_dbus_ack) | - (stage_two_req & (i_slt_op | i_branch_op))); - assign o_rf_rd_en = i_rd_op & !o_init; /* diff --git a/rtl/serv_top.v b/rtl/serv_top.v index c465ae4..b517b2e 100644 --- a/rtl/serv_top.v +++ b/rtl/serv_top.v @@ -4,7 +4,8 @@ module serv_top #(parameter WITH_CSR = 1, parameter PRE_REGISTER = 1, parameter RESET_STRATEGY = "MINI", - parameter RESET_PC = 32'd0) + parameter RESET_PC = 32'd0, + parameter [0:0] MDU = 1'b0) ( input wire clk, input wire i_rst, @@ -57,7 +58,15 @@ module serv_top output wire o_dbus_we , output wire o_dbus_cyc, input wire [31:0] i_dbus_rdt, - input wire i_dbus_ack); + input wire i_dbus_ack, + //Extension + output wire [ 2:0] o_ext_funct3, + input wire i_ext_ready, + input wire [31:0] i_ext_rd, + output wire [31:0] o_ext_rs1, + output wire [31:0] o_ext_rs2, + //MDU + output wire o_mdu_valid); wire [4:0] rd_addr; wire [4:0] rs1_addr; @@ -76,6 +85,7 @@ module serv_top wire shift_op; wire slt_op; wire rd_op; + wire mdu_op; wire rd_alu_en; wire rd_csr_en; @@ -157,7 +167,8 @@ module serv_top serv_state #(.RESET_STRATEGY (RESET_STRATEGY), - .WITH_CSR (WITH_CSR)) + .WITH_CSR (WITH_CSR), + .MDU(MDU)) state ( .i_clk (clk), @@ -194,6 +205,11 @@ module serv_top .i_slt_op (slt_op), .i_e_op (e_op), .i_rd_op (rd_op), + //MDU + .i_mdu_op (mdu_op), + .o_mdu_valid (o_mdu_valid), + //Extension + .i_mdu_ready (i_ext_ready), //External .o_dbus_cyc (o_dbus_cyc), .i_dbus_ack (i_dbus_ack), @@ -206,7 +222,8 @@ module serv_top .o_rf_rd_en (rd_en)); serv_decode - #(.PRE_REGISTER (PRE_REGISTER)) + #(.PRE_REGISTER (PRE_REGISTER), + .MDU(MDU)) decode ( .clk (clk), @@ -224,6 +241,10 @@ module serv_top .o_slt_op (slt_op), .o_rd_op (rd_op), .o_sh_right (sh_right), + .o_mdu_op (mdu_op), + //Extension + .o_ext_funct3 (o_ext_funct3), + //To bufreg .o_bufreg_rs1_en (bufreg_rs1_en), .o_bufreg_imm_en (bufreg_imm_en), @@ -281,7 +302,9 @@ module serv_top .i_wb_en (i_ibus_ack), .i_wb_rdt (i_ibus_rdt[31:7])); - serv_bufreg bufreg + serv_bufreg + #(.MDU(MDU)) + bufreg ( .i_clk (clk), //State @@ -289,6 +312,7 @@ module serv_top .i_cnt1 (cnt1), .i_en (bufreg_en), .i_init (init), + .i_mdu_op (mdu_op), .o_lsb (lsb), //Control .i_sh_signed (bufreg_sh_signed), @@ -300,7 +324,8 @@ module serv_top .i_imm (imm), .o_q (bufreg_q), //External - .o_dbus_adr (o_dbus_adr)); + .o_dbus_adr (o_dbus_adr), + .o_ext_rs1 (o_ext_rs1)); serv_ctrl #(.RESET_PC (RESET_PC), @@ -398,7 +423,8 @@ module serv_top .o_csr (rf_csr_out)); serv_mem_if - #(.WITH_CSR (WITH_CSR)) + #(.WITH_CSR (WITH_CSR), + .MDU(MDU)) mem_if ( .i_clk (clk), @@ -412,6 +438,7 @@ module serv_top .o_sh_done (mem_sh_done), .o_sh_done_r (mem_sh_done_r), //Control + .i_mdu_op (mdu_op), .i_mem_op (mem_op), .i_shift_op (shift_op), .i_signed (mem_signed), @@ -423,8 +450,8 @@ module serv_top //External interface .o_wb_dat (o_dbus_dat), .o_wb_sel (o_dbus_sel), - .i_wb_rdt (i_dbus_rdt), - .i_wb_ack (i_dbus_ack)); + .i_wb_rdt (dbus_rdt), + .i_wb_ack (dbus_ack)); generate if (WITH_CSR) begin @@ -525,5 +552,18 @@ module serv_top `endif +generate + wire [31:0] dbus_rdt; + wire dbus_ack; + if (MDU) begin + assign dbus_rdt = i_ext_ready ? i_ext_rd:i_dbus_rdt; + assign dbus_ack = i_dbus_ack | i_ext_ready; + end else begin + assign dbus_rdt = i_dbus_rdt; + assign dbus_ack = i_dbus_ack; + end + assign o_ext_rs2 = o_dbus_dat; +endgenerate + endmodule `default_nettype wire diff --git a/serv.core b/serv.core index 7163ebc..a0cbe14 100644 --- a/serv.core +++ b/serv.core @@ -25,6 +25,7 @@ targets: default: filesets : [core] parameters : + - "is_toplevel? (MDU)" - "is_toplevel? (PRE_REGISTER)" - "is_toplevel? (RESET_STRATEGY)" - RISCV_FORMAL @@ -43,6 +44,11 @@ targets: toplevel : serv_rf_top parameters: + MDU: + datatype : int + description: Enables interface for RISC-V standard M-extension + paramtype : vlogparam + PRE_REGISTER: datatype : int description : Register signals before or after the decoder diff --git a/servant.core b/servant.core index 938b2df..1884773 100644 --- a/servant.core +++ b/servant.core @@ -39,7 +39,7 @@ filesets: - "!tool_quartus? (servant/servant_ram.v)" - servant/servant.v file_type : verilogSource - depend : [serv] + depend : [serv, "mdu? (mdu)"] cyc1000: files: @@ -297,7 +297,7 @@ targets: arty_a7_35t: default_tool: vivado filesets : [mem_files, soc, arty_a7_35t] - parameters : [memfile, memsize, frequency=16] + parameters : [memfile, memsize, frequency=16, "mdu? (MDU=1)"] tools: vivado: {part : xc7a35ticsg324-1L} toplevel : servix @@ -347,6 +347,7 @@ targets: filesets : [soc, servant_tb] parameters : - RISCV_FORMAL + - "mdu? (MDU=1)" - SERV_CLEAR_RAM=true - firmware - memsize @@ -379,6 +380,7 @@ targets: filesets : [soc, verilator_tb] parameters : - RISCV_FORMAL + - "mdu? (MDU=1)" - firmware - memsize - signature @@ -429,6 +431,11 @@ parameters: RISCV_FORMAL: datatype : bool paramtype : vlogdefine + + MDU: + datatype : int + description : Enables RISC-V standard M-extension + paramtype : vlogdefine SERV_CLEAR_RAM: datatype : bool diff --git a/servant/servant.v b/servant/servant.v index f300a9a..cae391e 100644 --- a/servant/servant.v +++ b/servant/servant.v @@ -52,6 +52,13 @@ module servant wire wb_timer_cyc; wire [31:0] wb_timer_rdt; + wire [31:0] mdu_rs1; + wire [31:0] mdu_rs2; + wire [ 2:0] mdu_op; + wire mdu_valid; + wire [31:0] mdu_rd; + wire mdu_ready; + servant_arbiter arbiter (.i_wb_cpu_dbus_adr (wb_dmem_adr), .i_wb_cpu_dbus_dat (wb_dmem_dat), @@ -149,6 +156,9 @@ module servant serv_rf_top #(.RESET_PC (32'h0000_0000), .RESET_STRATEGY (reset_strategy), + `ifdef MDU + .MDU(1), + `endif .WITH_CSR (with_csr)) cpu ( @@ -190,6 +200,31 @@ module servant .o_dbus_we (wb_dbus_we), .o_dbus_cyc (wb_dbus_cyc), .i_dbus_rdt (wb_dbus_rdt), - .i_dbus_ack (wb_dbus_ack)); + .i_dbus_ack (wb_dbus_ack), + + //Extension + .o_ext_rs1 (mdu_rs1), + .o_ext_rs2 (mdu_rs2), + .o_ext_funct3 (mdu_op), + .i_ext_rd (mdu_rd), + .i_ext_ready (mdu_ready), + //MDU + .o_mdu_valid (mdu_valid)); + +`ifdef MDU + mdu_top mdu_serv + ( + .i_clk(wb_clk), + .i_rst(wb_rst), + .i_mdu_rs1(mdu_rs1), + .i_mdu_rs2(mdu_rs2), + .i_mdu_op(mdu_op), + .i_mdu_valid(mdu_valid), + .o_mdu_ready(mdu_ready), + .o_mdu_rd(mdu_rd)); +`else + assign mdu_ready = 1'b0; + assign mdu_rd = 32'b0; +`endif endmodule