serv/rtl/serv_decode.v
2022-01-14 23:36:20 +01:00

144 lines
4.4 KiB
Verilog

`default_nettype none
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,
input wire i_wb_en,
//To state
output reg o_e_op,//xx
output reg o_ebreak,//xx
//To ctrl
output reg o_ctrl_mret,//xx
//To CSR
output reg o_csr_en,//xx
output reg [1:0] o_csr_addr,//xx
output reg o_csr_mstatus_en,//xx
output reg o_csr_mie_en,//xx
output reg o_csr_mcause_en,//xx
output reg [1:0] o_csr_source,//xx
output reg o_csr_d_sel,//xx
output reg o_csr_imm_en,//xx
//To RF IF
output reg o_rd_csr_en);//xx
reg [4:0] opcode;
reg [2:0] funct3;
reg op20;
reg op21;
reg op22;
reg op26;
reg imm25;
reg imm30;
//op20
wire co_ebreak = op20;
//csr_op matches system ops except eceall/ebreak/mret
//e_op matches system opcodes except CSR accesses (funct3 == 0) and mret (!op21)
wire co_rd_csr_en = opcode[4] & opcode[2] & (|funct3);
wire co_ctrl_mret = opcode[4] & opcode[2] & !(|funct3) & op21;
wire co_e_op = opcode[4] & opcode[2] & !(|funct3) & !op21;
/*
Bits 26, 22, 21 and 20 are enough to uniquely identify the eight supported CSR regs
mtvec, mscratch, mepc and mtval are stored externally (normally in the RF) and are
treated differently from mstatus, mie and mcause which are stored in serv_csr.
The former get a 2-bit address as seen below while the latter get a
one-hot enable signal each.
Hex|2 222|Reg |csr
adr|6 210|name |addr
---|-----|--------|----
300|0_000|mstatus | xx
304|0_100|mie | xx
305|0_101|mtvec | 01
340|1_000|mscratch| 00
341|1_001|mepc | 10
342|1_010|mcause | xx
343|1_011|mtval | 11
*/
//true for mtvec,mscratch,mepc and mtval
//false for mstatus, mie, mcause
wire co_csr_en = op20 | (op26 & !op21);
wire co_csr_mstatus_en = !op26 & !op22;
wire co_csr_mie_en = !op26 & op22 & !op20;
wire co_csr_mcause_en = op21 & !op20;
wire [1:0] co_csr_source = funct3[1:0];
wire co_csr_d_sel = funct3[2];
wire co_csr_imm_en = opcode[4] & opcode[2] & funct3[2];
wire [1:0] co_csr_addr = {op26 & op20, !op26 | op21};
generate
if (PRE_REGISTER) begin
always @(posedge clk) begin
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];
op22 <= i_wb_rdt[22];
op26 <= i_wb_rdt[26];
end
end
always @(*) begin
o_e_op = co_e_op;
o_ebreak = co_ebreak;
o_ctrl_mret = co_ctrl_mret;
o_csr_en = co_csr_en;
o_csr_addr = co_csr_addr;
o_csr_mstatus_en = co_csr_mstatus_en;
o_csr_mie_en = co_csr_mie_en;
o_csr_mcause_en = co_csr_mcause_en;
o_csr_source = co_csr_source;
o_csr_d_sel = co_csr_d_sel;
o_csr_imm_en = co_csr_imm_en;
o_rd_csr_en = co_rd_csr_en;
end
end else begin
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];
op22 = i_wb_rdt[22];
op26 = i_wb_rdt[26];
end
always @(posedge clk) begin
if (i_wb_en) begin
o_e_op <= co_e_op;
o_ebreak <= co_ebreak;
o_ctrl_mret <= co_ctrl_mret;
o_csr_en <= co_csr_en;
o_csr_addr <= co_csr_addr;
o_csr_mstatus_en <= co_csr_mstatus_en;
o_csr_mie_en <= co_csr_mie_en;
o_csr_mcause_en <= co_csr_mcause_en;
o_csr_source <= co_csr_source;
o_csr_d_sel <= co_csr_d_sel;
o_csr_imm_en <= co_csr_imm_en;
o_rd_csr_en <= co_rd_csr_en;
end
end
end
endgenerate
endmodule