mirror of
https://github.com/olofk/serv.git
synced 2025-04-22 21:07:12 -04:00
144 lines
4.4 KiB
Verilog
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
|