`default_nettype none module serv_csr #(parameter RESET_STRATEGY = "MINI") ( 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_cnt_done, input wire i_mem_op, input wire i_mtip, 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 i_rf_csr_out, output wire o_csr_in, input wire i_csr_imm, input wire i_rs1, output wire o_q); 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 mcause31; reg [3:0] mcause3_0; wire mcause; wire csr_in; wire csr_out; reg timer_irq_r; wire 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 : 1'bx; assign csr_out = (i_mstatus_en & mstatus_mie & i_cnt3) | i_rf_csr_out | (i_mcause_en & i_en & mcause); assign o_q = csr_out; wire timer_irq = i_mtip & mstatus_mie & mie_mtie; assign mcause = i_cnt0to3 ? mcause3_0[0] : //[3:0] i_cnt_done ? mcause31 //[31] : 1'b0; assign o_csr_in = csr_in; always @(posedge i_clk) begin if (i_trig_irq) begin timer_irq_r <= timer_irq; o_new_irq <= timer_irq & !timer_irq_r; end if (i_mie_en & i_cnt7) mie_mtie <= csr_in; /* 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 exclusibe */ if ((i_trap & i_cnt_done) | i_mstatus_en & i_cnt3 | i_mret) mstatus_mie <= !i_trap & (i_mret ? mstatus_mpie : csr_in); /* 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 external interrupt the exception code is set to 7, since SERV only support timer interrupts 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 irq => 0111 (timer=7) 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] <= (i_e_op & !i_ebreak) | (!i_trap & csr_in); mcause3_0[2] <= o_new_irq | i_mem_op | (!i_trap & mcause3_0[3]); mcause3_0[1] <= o_new_irq | i_e_op | (i_mem_op & i_mem_cmd) | (!i_trap & mcause3_0[2]); mcause3_0[0] <= o_new_irq | i_e_op | (!i_trap & mcause3_0[1]); end if (i_mcause_en & i_cnt_done | i_trap) mcause31 <= i_trap ? o_new_irq : csr_in; if (i_rst) if (RESET_STRATEGY != "NONE") begin o_new_irq <= 1'b0; mie_mtie <= 1'b0; end end endmodule