1
0
mirror of https://github.com/olofk/serv.git synced 2026-01-11 23:42:50 +00:00

M-extension support for SERV

* modified serv(ant) for MDU
* added dependency for mdu
* M-extension for SERV
* Updated README for running RV32IM compliance tests
* waive some lint warnings related to mdu
* added mdu param for arty_a7_35t
This commit is contained in:
Zeeshan Rafique 2021-08-21 02:31:42 +05:00 committed by Olof Kindgren
parent dbe5236b4c
commit 6e802cb9bc
11 changed files with 246 additions and 52 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;
/*

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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