mirror of
https://github.com/olofk/serv.git
synced 2026-03-01 17:25:51 +00:00
173 lines
4.9 KiB
Verilog
173 lines
4.9 KiB
Verilog
`default_nettype none
|
|
module serv_csr
|
|
#(
|
|
parameter RESET_STRATEGY = "MINI",
|
|
parameter W = 1,
|
|
parameter B = W-1
|
|
)
|
|
(
|
|
input wire i_clk,
|
|
input wire i_rst,
|
|
//State
|
|
input wire i_trig_irq,
|
|
input wire i_en,
|
|
input wire i_cnt0to3,
|
|
input wire i_cnt3,
|
|
input wire i_cnt7,
|
|
input wire i_cnt11,
|
|
input wire i_cnt12,
|
|
input wire i_cnt_done,
|
|
input wire i_mem_op,
|
|
input wire i_mtip,
|
|
input wire i_meip,
|
|
input wire i_trap,
|
|
output reg o_new_irq,
|
|
//Control
|
|
input wire i_e_op,
|
|
input wire i_ebreak,
|
|
input wire i_mem_cmd,
|
|
input wire i_mstatus_en,
|
|
input wire i_mie_en,
|
|
input wire i_mcause_en,
|
|
input wire [1:0] i_csr_source,
|
|
input wire i_mret,
|
|
input wire i_csr_d_sel,
|
|
//Data
|
|
input wire [B:0] i_rf_csr_out,
|
|
output wire [B:0] o_csr_in,
|
|
input wire [B:0] i_csr_imm,
|
|
input wire [B:0] i_rs1,
|
|
output wire [B:0] o_q,
|
|
output wire o_meie,
|
|
output wire o_mtie);
|
|
|
|
localparam [1:0]
|
|
CSR_SOURCE_CSR = 2'b00,
|
|
CSR_SOURCE_EXT = 2'b01,
|
|
CSR_SOURCE_SET = 2'b10,
|
|
CSR_SOURCE_CLR = 2'b11;
|
|
|
|
reg mstatus_mie;
|
|
reg mstatus_mpie;
|
|
reg mie_mtie;
|
|
reg mie_meie;
|
|
|
|
assign o_meie = mie_meie;
|
|
assign o_mtie = mie_mtie;
|
|
|
|
reg mcause31;
|
|
reg [3:0] mcause3_0;
|
|
wire [B:0] mcause;
|
|
|
|
wire [B:0] csr_in;
|
|
wire [B:0] csr_out;
|
|
|
|
reg irq_r;
|
|
|
|
wire [B:0] d = i_csr_d_sel ? i_csr_imm : i_rs1;
|
|
|
|
assign csr_in = (i_csr_source == CSR_SOURCE_EXT) ? d :
|
|
(i_csr_source == CSR_SOURCE_SET) ? csr_out | d :
|
|
(i_csr_source == CSR_SOURCE_CLR) ? csr_out & ~d :
|
|
(i_csr_source == CSR_SOURCE_CSR) ? csr_out :
|
|
{W{1'bx}};
|
|
|
|
wire [B:0] mstatus;
|
|
|
|
generate
|
|
if (W==1) begin : gen_mstatus_w1
|
|
assign mstatus = ((mstatus_mie & i_cnt3) | (i_cnt11 | i_cnt12));
|
|
end else if (W==4) begin : gen_mstatus_w4
|
|
assign mstatus = {i_cnt11 | (mstatus_mie & i_cnt3), 2'b00, i_cnt12};
|
|
end
|
|
endgenerate
|
|
|
|
assign csr_out = ({W{i_mstatus_en & i_en}} & mstatus) |
|
|
i_rf_csr_out |
|
|
({W{i_mcause_en & i_en}} & mcause);
|
|
|
|
assign o_q = csr_out;
|
|
|
|
wire timer_irq = i_mtip & mie_mtie;
|
|
wire ext_irq = i_meip & mie_meie;
|
|
wire irq = (timer_irq | ext_irq) & mstatus_mie;
|
|
|
|
assign mcause = i_cnt0to3 ? mcause3_0[B:0] : //[3:0]
|
|
i_cnt_done ? {mcause31,{B{1'b0}}} //[31]
|
|
: {W{1'b0}};
|
|
|
|
assign o_csr_in = csr_in;
|
|
|
|
always @(posedge i_clk) begin
|
|
if (i_trig_irq) begin
|
|
irq_r <= irq;
|
|
o_new_irq <= (irq & !irq_r);
|
|
end
|
|
|
|
if (i_mie_en & i_cnt7)
|
|
mie_mtie <= csr_in[B];
|
|
|
|
if(i_mie_en & i_cnt11)
|
|
mie_meie <= csr_in[B];
|
|
|
|
/*
|
|
The mie bit in mstatus gets updated under three conditions
|
|
|
|
When a trap is taken, the bit is cleared
|
|
During an mret instruction, the bit is restored from mpie
|
|
During a mstatus CSR access instruction it's assigned when
|
|
bit 3 gets updated
|
|
|
|
These conditions are all mutually exclusive
|
|
*/
|
|
if ((i_trap & i_cnt_done) | i_mstatus_en & i_cnt3 & i_en | i_mret)
|
|
mstatus_mie <= !i_trap & (i_mret ? mstatus_mpie : csr_in[B]);
|
|
|
|
/*
|
|
Note: To save resources mstatus_mpie (mstatus bit 7) is not
|
|
readable or writable from sw
|
|
*/
|
|
if (i_trap & i_cnt_done)
|
|
mstatus_mpie <= mstatus_mie;
|
|
|
|
/*
|
|
The four lowest bits in mcause hold the exception code
|
|
|
|
These bits get updated under three conditions
|
|
|
|
During an mcause CSR access function, they are assigned when
|
|
bits 0 to 3 gets updated
|
|
|
|
During an interrupt, the exception code is assigned to indicate
|
|
if it was caused by a timer interrupt (7) or an external interrupt (11).
|
|
|
|
During an exception, the exception code is assigned to indicate
|
|
if it was caused by an ebreak instruction (3),
|
|
ecall instruction (11), misaligned load (4), misaligned store (6)
|
|
or misaligned jump (0)
|
|
|
|
The expressions below are derived from the following truth table
|
|
timer_irq => 0111 (timer=7)
|
|
ext_irq => 1011 (ext=11)
|
|
e_op => x011 (ebreak=3, ecall=11)
|
|
mem => 01x0 (store=6, load=4)
|
|
ctrl => 0000 (jump=0)
|
|
*/
|
|
if (i_mcause_en & i_en & i_cnt0to3 | (i_trap & i_cnt_done)) begin
|
|
mcause3_0[3] <= (o_new_irq & ext_irq) | (i_e_op & !i_ebreak) | (!i_trap & csr_in[B]);
|
|
mcause3_0[2] <= (o_new_irq & !ext_irq) | i_mem_op | (!i_trap & ((W == 1) ? mcause3_0[3] : csr_in[(W == 1) ? 0 : 2]));
|
|
mcause3_0[1] <= o_new_irq | i_e_op | (i_mem_op & i_mem_cmd) | (!i_trap & ((W == 1) ? mcause3_0[2] : csr_in[(W == 1) ? 0 : 1]));
|
|
mcause3_0[0] <= o_new_irq | i_e_op | (!i_trap & ((W == 1) ? mcause3_0[1] : csr_in[0]));
|
|
end
|
|
if (i_mcause_en & i_cnt_done | i_trap)
|
|
mcause31 <= i_trap ? o_new_irq : csr_in[B];
|
|
if (i_rst)
|
|
if (RESET_STRATEGY != "NONE") begin
|
|
o_new_irq <= 1'b0;
|
|
mie_mtie <= 1'b0;
|
|
mie_meie <= 1'b0;
|
|
end
|
|
end
|
|
|
|
endmodule
|