| /// Copyright by Syntacore LLC © 2016-2020. See LICENSE for details |
| /// @file <scr1_pipe_csr.sv> |
| /// @brief Control Status Registers (CSR) |
| /// |
| |
| //------------------------------------------------------------------------------ |
| // |
| // Functionality: |
| // - Provides access to RISC-V CSR Machine registers |
| // - Handles events (EXC, IRQ and MRET): |
| // - Setups handling configuration |
| // - Displays events statuses and information |
| // - Generates new PC |
| // - Provides information about the number of executed instructions and elapsed |
| // cycles |
| // - Provides interfaces for IPIC, HDU and TDU registers access |
| // |
| // Structure: |
| // - Events (EXC, IRQ, MRET) logic |
| // - CSR read/write interface |
| // - CSR registers: |
| // - Machine Trap Setup registers |
| // - Machine Trap Handling registers |
| // - Machine Counters/Timers registers |
| // - Non-standard CSRs (MCOUNTEN) |
| // - CSR <-> EXU i/f |
| // - CSR <-> IPIC i/f |
| // - CSR <-> HDU i/f |
| // - CSR <-> TDU i/f |
| // |
| //------------------------------------------------------------------------------ |
| |
| `include "scr1_arch_description.svh" |
| `include "scr1_csr.svh" |
| `include "scr1_arch_types.svh" |
| `include "scr1_riscv_isa_decoding.svh" |
| `ifdef SCR1_IPIC_EN |
| `include "scr1_ipic.svh" |
| `endif // SCR1_IPIC_EN |
| `ifdef SCR1_DBG_EN |
| `include "scr1_hdu.svh" |
| `endif // SCR1_DBG_EN |
| `ifdef SCR1_TDU_EN |
| `include "scr1_tdu.svh" |
| `endif // SCR1_TDU_EN |
| |
| module scr1_pipe_csr ( |
| // Common |
| input logic rst_n, // CSR reset |
| input logic clk, // Gated CSR clock |
| `ifdef SCR1_CLKCTRL_EN |
| input logic clk_alw_on, // Not-gated CSR clock |
| `endif // SCR1_CLKCTRL_EN |
| |
| // SOC signals |
| // IRQ |
| input logic soc2csr_irq_ext_i, // External interrupt request |
| input logic soc2csr_irq_soft_i, // Software interrupt request |
| input logic soc2csr_irq_mtimer_i, // External timer interrupt request |
| |
| // Memory-mapped external timer |
| input logic [63:0] soc2csr_mtimer_val_i, // External timer value |
| |
| // MHARTID fuse |
| input logic [`SCR1_XLEN-1:0] soc2csr_fuse_mhartid_i, // MHARTID fuse |
| |
| // CSR <-> EXU read/write interface |
| input logic exu2csr_r_req_i, // CSR read/write address |
| input logic [SCR1_CSR_ADDR_WIDTH-1:0] exu2csr_rw_addr_i, // CSR read request |
| output logic [`SCR1_XLEN-1:0] csr2exu_r_data_o, // CSR read data |
| input logic exu2csr_w_req_i, // CSR write request |
| input type_scr1_csr_cmd_sel_e exu2csr_w_cmd_i, // CSR write command |
| input logic [`SCR1_XLEN-1:0] exu2csr_w_data_i, // CSR write data |
| output logic csr2exu_rw_exc_o, // CSR read/write access exception |
| |
| // CSR <-> EXU event interface |
| input logic exu2csr_take_irq_i, // Take IRQ trap |
| input logic exu2csr_take_exc_i, // Take exception trap |
| input logic exu2csr_mret_update_i, // MRET update CSR |
| input logic exu2csr_mret_instr_i, // MRET instruction |
| input logic [SCR1_EXC_CODE_WIDTH_E-1:0] exu2csr_exc_code_i, // Exception code (see scr1_arch_types.svh) - cp.7 |
| input logic [`SCR1_XLEN-1:0] exu2csr_trap_val_i, // Trap value |
| output logic csr2exu_irq_o, // IRQ request |
| output logic csr2exu_ip_ie_o, // Some IRQ pending and locally enabled |
| output logic csr2exu_mstatus_mie_up_o, // MSTATUS or MIE update in the current cycle |
| |
| `ifdef SCR1_IPIC_EN |
| // CSR <-> IPIC interface |
| output logic csr2ipic_r_req_o, // IPIC read request |
| output logic csr2ipic_w_req_o, // IPIC write request |
| output logic [2:0] csr2ipic_addr_o, // IPIC address |
| output logic [`SCR1_XLEN-1:0] csr2ipic_wdata_o, // IPIC write data |
| input logic [`SCR1_XLEN-1:0] ipic2csr_rdata_i, // IPIC read data |
| `endif // SCR1_IPIC_EN |
| |
| `ifdef SCR1_DBG_EN |
| // CSR <-> HDU interface |
| output logic csr2hdu_req_o, // Request to HDU |
| output type_scr1_csr_cmd_sel_e csr2hdu_cmd_o, // HDU command |
| output logic [SCR1_HDU_DEBUGCSR_ADDR_WIDTH-1:0] csr2hdu_addr_o, // HDU address |
| output logic [`SCR1_XLEN-1:0] csr2hdu_wdata_o, // HDU write data |
| input logic [`SCR1_XLEN-1:0] hdu2csr_rdata_i, // HDU read data |
| input type_scr1_csr_resp_e hdu2csr_resp_i, // HDU response |
| input logic hdu2csr_no_commit_i, // Forbid instruction commitment |
| `endif // SCR1_DBG_EN |
| |
| `ifdef SCR1_TDU_EN |
| // CSR <-> TDU interface |
| output logic csr2tdu_req_o, // Request to TDU |
| output type_scr1_csr_cmd_sel_e csr2tdu_cmd_o, // TDU command |
| output logic [SCR1_CSR_ADDR_TDU_OFFS_W-1:0] csr2tdu_addr_o, // TDU address |
| output logic [`SCR1_XLEN-1:0] csr2tdu_wdata_o, // TDU write data |
| input logic [`SCR1_XLEN-1:0] tdu2csr_rdata_i, // TDU read data |
| input type_scr1_csr_resp_e tdu2csr_resp_i, // TDU response |
| `endif // SCR1_TDU_EN |
| |
| // CSR <-> EXU PC interface |
| `ifndef SCR1_CSR_REDUCED_CNT |
| input logic exu2csr_instret_no_exc_i, // Instruction retired (without exception) |
| `endif // SCR1_CSR_REDUCED_CNT |
| input logic [`SCR1_XLEN-1:0] exu2csr_pc_curr_i, // Current PC |
| input logic [`SCR1_XLEN-1:0] exu2csr_pc_next_i, // Next PC |
| output logic [`SCR1_XLEN-1:0] csr2exu_new_pc_o // Exception/IRQ/MRET new PC |
| ); |
| |
| //------------------------------------------------------------------------------ |
| // Local parameters |
| //------------------------------------------------------------------------------ |
| |
| `ifdef SCR1_RVC_EXT |
| localparam PC_LSB = 1; |
| `else |
| localparam PC_LSB = 2; |
| `endif |
| |
| //------------------------------------------------------------------------------ |
| // Local signals declaration |
| //------------------------------------------------------------------------------ |
| |
| // Machine Trap Setup registers |
| //------------------------------------------------------------------------------ |
| |
| // MSTATUS register |
| logic csr_mstatus_upd; // MSTATUS update enable |
| logic [`SCR1_XLEN-1:0] csr_mstatus; // Aggregated MSTATUS |
| logic csr_mstatus_mie_ff; // MSTATUS: Global interrupt enable |
| logic csr_mstatus_mie_next; // MSTATUS: Global interrupt enable next value |
| logic csr_mstatus_mpie_ff; // MSTATUS: Global interrupt enable prior to the trap |
| logic csr_mstatus_mpie_next; // MSTATUS: Global interrupt enable prior to the trap next value |
| |
| // MIE register |
| logic csr_mie_upd; // MIE update enable |
| logic [`SCR1_XLEN-1:0] csr_mie; // Aggregated MIE |
| logic csr_mie_mtie_ff; // MIE: Machine timer interrupt enable |
| logic csr_mie_meie_ff; // MIE: Machine external interrupt enable |
| logic csr_mie_msie_ff; // MIE: Machine software interrupt enable |
| |
| // MTVEC register |
| logic csr_mtvec_upd; // MTVEC update enable |
| logic [`SCR1_XLEN-1:SCR1_CSR_MTVEC_BASE_ZERO_BITS] csr_mtvec_base; // MTVEC: Base (upper 26 bits) |
| logic csr_mtvec_mode; // MTVEC: Mode (0-direct, 1-vectored) (wired) |
| `ifdef SCR1_MTVEC_MODE_EN |
| logic csr_mtvec_mode_ff; // MTVEC: Mode (0-direct, 1-vectored) (registered) |
| logic csr_mtvec_mode_vect; |
| `endif |
| |
| // Machine Trap Handling registers |
| //------------------------------------------------------------------------------ |
| |
| // MSCRATCH register |
| logic csr_mscratch_upd; // MSCRATCH update enable |
| logic [`SCR1_XLEN-1:0] csr_mscratch_ff; // MSCRATCH |
| |
| // MEPC register |
| logic csr_mepc_upd; // MEPC update enable |
| logic [`SCR1_XLEN-1:PC_LSB] csr_mepc_ff; // MEPC registered value |
| logic [`SCR1_XLEN-1:PC_LSB] csr_mepc_next; // MEPC next value |
| logic [`SCR1_XLEN-1:0] csr_mepc; // MEPC registered value extended to XLEN |
| |
| // MCAUSE register |
| logic csr_mcause_upd; // MCAUSE update enable |
| logic csr_mcause_i_ff; // MCAUSE: Interrupt |
| logic csr_mcause_i_next; // MCAUSE: Interrupt next value |
| logic [SCR1_EXC_CODE_WIDTH_E-1:0] csr_mcause_ec_ff; // MCAUSE: Exception code - cp.7 |
| logic [SCR1_EXC_CODE_WIDTH_E-1:0] csr_mcause_ec_next; // MCAUSE: Exception code next value - cp.7 |
| logic [SCR1_EXC_CODE_WIDTH_E-1:0] csr_mcause_ec_new; // MCAUSE: Exception code new value (IRQs) - cp.7 |
| |
| // MTVAL register |
| logic csr_mtval_upd; // MTVAL update enable |
| logic [`SCR1_XLEN-1:0] csr_mtval_ff; // MTVAL registered value |
| logic [`SCR1_XLEN-1:0] csr_mtval_next; // MTVAL next value |
| |
| // MIP register |
| logic [`SCR1_XLEN-1:0] csr_mip; // Aggregated MIP |
| logic csr_mip_mtip; // MIP: Machine timer interrupt pending |
| logic csr_mip_meip; // MIP: Machine external interrupt pending |
| logic csr_mip_msip; // MIP: Machine software interrupt pending |
| |
| // Machine Counters/Timers registers |
| //------------------------------------------------------------------------------ |
| |
| `ifndef SCR1_CSR_REDUCED_CNT |
| // MINSTRET register |
| logic [1:0] csr_minstret_upd; |
| logic [SCR1_CSR_COUNTERS_WIDTH-1:0] csr_minstret; |
| logic csr_minstret_lo_inc; |
| logic csr_minstret_lo_upd; |
| logic [7:0] csr_minstret_lo_ff; |
| logic [7:0] csr_minstret_lo_next; |
| logic csr_minstret_hi_inc; |
| logic csr_minstret_hi_upd; |
| logic [SCR1_CSR_COUNTERS_WIDTH-1:8] csr_minstret_hi_ff; |
| logic [SCR1_CSR_COUNTERS_WIDTH-1:8] csr_minstret_hi_next; |
| logic [SCR1_CSR_COUNTERS_WIDTH-1:8] csr_minstret_hi_new; |
| |
| // MCYCLE register |
| logic [1:0] csr_mcycle_upd; |
| logic [SCR1_CSR_COUNTERS_WIDTH-1:0] csr_mcycle; |
| logic csr_mcycle_lo_inc; |
| logic csr_mcycle_lo_upd; |
| logic [7:0] csr_mcycle_lo_ff; |
| logic [7:0] csr_mcycle_lo_next; |
| logic csr_mcycle_hi_inc; |
| logic csr_mcycle_hi_upd; |
| logic [SCR1_CSR_COUNTERS_WIDTH-1:8] csr_mcycle_hi_ff; |
| logic [SCR1_CSR_COUNTERS_WIDTH-1:8] csr_mcycle_hi_next; |
| logic [SCR1_CSR_COUNTERS_WIDTH-1:8] csr_mcycle_hi_new; |
| `endif // ~SCR1_CSR_REDUCED_CNT |
| |
| // Non-standard CSRs |
| //------------------------------------------------------------------------------ |
| |
| // MCOUNTEN register |
| `ifdef SCR1_MCOUNTEN_EN |
| logic csr_mcounten_upd; // MCOUNTEN update enable |
| logic [`SCR1_XLEN-1:0] csr_mcounten; // Aggregated MCOUNTEN |
| logic csr_mcounten_cy_ff; // Cycle count enable |
| logic csr_mcounten_ir_ff; // Instret count enable |
| `endif // SCR1_MCOUNTEN_EN |
| |
| // CSR read/write i/f |
| //------------------------------------------------------------------------------ |
| |
| logic [`SCR1_XLEN-1:0] csr_r_data; |
| logic [`SCR1_XLEN-1:0] csr_w_data; |
| |
| // Events (exceptions, interrupts, mret) signals |
| //------------------------------------------------------------------------------ |
| |
| // Event flags |
| logic e_exc; // Successful exception trap |
| logic e_irq; // Successful IRQ trap |
| logic e_mret; // MRET instruction |
| logic e_irq_nmret; // IRQ trap without MRET instruction |
| |
| // Interrupt pending & enable signals |
| logic csr_eirq_pnd_en; // External IRQ pending and locally enabled |
| logic csr_sirq_pnd_en; // Software IRQ pending and locally enabled |
| logic csr_tirq_pnd_en; // Timer IRQ pending and locally enabled |
| |
| // Exception flags |
| logic csr_w_exc; |
| logic csr_r_exc; |
| logic exu_req_no_exc; |
| |
| // Requests to other modules |
| logic csr_ipic_req; |
| `ifdef SCR1_DBG_EN |
| logic csr_hdu_req; |
| `endif // SCR1_DBG_EN |
| `ifdef SCR1_TDU_EN |
| logic csr_brkm_req; |
| `endif // SCR1_TDU_EN |
| |
| //------------------------------------------------------------------------------ |
| // Events (IRQ, EXC, MRET) |
| //------------------------------------------------------------------------------ |
| |
| // Events priority |
| assign e_exc = exu2csr_take_exc_i |
| `ifdef SCR1_DBG_EN |
| & ~hdu2csr_no_commit_i |
| `endif // SCR1_DBG_EN |
| ; |
| assign e_irq = exu2csr_take_irq_i & ~exu2csr_take_exc_i |
| `ifdef SCR1_DBG_EN |
| & ~hdu2csr_no_commit_i |
| `endif // SCR1_DBG_EN |
| ; |
| assign e_mret = exu2csr_mret_update_i |
| `ifdef SCR1_DBG_EN |
| & ~hdu2csr_no_commit_i |
| `endif // SCR1_DBG_EN |
| ; |
| assign e_irq_nmret = e_irq & ~exu2csr_mret_instr_i; |
| |
| // IRQ pending & enable signals |
| assign csr_eirq_pnd_en = csr_mip_meip & csr_mie_meie_ff; |
| assign csr_sirq_pnd_en = csr_mip_msip & csr_mie_msie_ff; |
| assign csr_tirq_pnd_en = csr_mip_mtip & csr_mie_mtie_ff; |
| |
| // IRQ exception codes priority |
| always_comb begin |
| case (1'b1) |
| csr_eirq_pnd_en: csr_mcause_ec_new = SCR1_EXC_CODE_IRQ_M_EXTERNAL; // cp.7 |
| csr_sirq_pnd_en: csr_mcause_ec_new = SCR1_EXC_CODE_IRQ_M_SOFTWARE; // cp.7 |
| csr_tirq_pnd_en: csr_mcause_ec_new = SCR1_EXC_CODE_IRQ_M_TIMER; // cp.7 |
| default : csr_mcause_ec_new = SCR1_EXC_CODE_IRQ_M_EXTERNAL; // cp.7 |
| endcase |
| end |
| |
| assign exu_req_no_exc = ((exu2csr_r_req_i & ~csr_r_exc) |
| | (exu2csr_w_req_i & ~csr_w_exc)); |
| |
| //------------------------------------------------------------------------------ |
| // CSR read/write interface |
| //------------------------------------------------------------------------------ |
| |
| // CSR read logic |
| //------------------------------------------------------------------------------ |
| |
| always_comb begin |
| csr_r_data = '0; |
| csr_r_exc = 1'b0; |
| `ifdef SCR1_DBG_EN |
| csr_hdu_req = 1'b0; |
| `endif // SCR1_DBG_EN |
| `ifdef SCR1_TDU_EN |
| csr_brkm_req = 1'b0; |
| `endif // SCR1_TDU_EN |
| `ifdef SCR1_IPIC_EN |
| csr2ipic_r_req_o = 1'b0; |
| `endif // SCR1_IPIC_EN |
| |
| casez (exu2csr_rw_addr_i) |
| // Machine Information Registers (read-only) |
| SCR1_CSR_ADDR_MVENDORID : csr_r_data = SCR1_CSR_MVENDORID; |
| SCR1_CSR_ADDR_MARCHID : csr_r_data = SCR1_CSR_MARCHID; |
| SCR1_CSR_ADDR_MIMPID : csr_r_data = SCR1_CSR_MIMPID; |
| SCR1_CSR_ADDR_MHARTID : csr_r_data = soc2csr_fuse_mhartid_i; |
| |
| // Machine Trap Setup (read-write) |
| SCR1_CSR_ADDR_MSTATUS : csr_r_data = csr_mstatus; |
| SCR1_CSR_ADDR_MISA : csr_r_data = SCR1_CSR_MISA; |
| SCR1_CSR_ADDR_MIE : csr_r_data = csr_mie; |
| SCR1_CSR_ADDR_MTVEC : csr_r_data = {csr_mtvec_base, 4'd0, 2'(csr_mtvec_mode)}; |
| |
| // Machine Trap Handling (read-write) |
| SCR1_CSR_ADDR_MSCRATCH : csr_r_data = csr_mscratch_ff; |
| SCR1_CSR_ADDR_MEPC : csr_r_data = csr_mepc; |
| SCR1_CSR_ADDR_MCAUSE : csr_r_data = {csr_mcause_i_ff, (`SCR1_XLEN-1)'(csr_mcause_ec_ff)}; |
| SCR1_CSR_ADDR_MTVAL : csr_r_data = csr_mtval_ff; |
| SCR1_CSR_ADDR_MIP : csr_r_data = csr_mip; |
| |
| // User Counters/Timers (read-only) |
| {SCR1_CSR_ADDR_HPMCOUNTER_MASK, 5'b?????} : begin |
| case (exu2csr_rw_addr_i[4:0]) |
| 5'd1 : csr_r_data = soc2csr_mtimer_val_i[31:0]; |
| `ifndef SCR1_CSR_REDUCED_CNT |
| 5'd0 : csr_r_data = csr_mcycle[31:0]; |
| 5'd2 : csr_r_data = csr_minstret[31:0]; |
| `endif // SCR1_CSR_REDUCED_CNT |
| default : begin |
| // return 0 |
| end |
| endcase |
| end |
| |
| {SCR1_CSR_ADDR_HPMCOUNTERH_MASK, 5'b?????} : begin |
| case (exu2csr_rw_addr_i[4:0]) |
| 5'd1 : csr_r_data = soc2csr_mtimer_val_i[63:32]; |
| `ifndef SCR1_CSR_REDUCED_CNT |
| 5'd0 : csr_r_data = csr_mcycle[63:32]; |
| 5'd2 : csr_r_data = csr_minstret[63:32]; |
| `endif // SCR1_CSR_REDUCED_CNT |
| default : begin |
| // return 0 |
| end |
| endcase |
| end |
| |
| // Machine Counters/Timers (read-write) |
| {SCR1_CSR_ADDR_MHPMCOUNTER_MASK, 5'b?????} : begin |
| case (exu2csr_rw_addr_i[4:0]) |
| 5'd1 : csr_r_exc = exu2csr_r_req_i; |
| `ifndef SCR1_CSR_REDUCED_CNT |
| 5'd0 : csr_r_data = csr_mcycle[31:0]; |
| 5'd2 : csr_r_data = csr_minstret[31:0]; |
| `endif // SCR1_CSR_REDUCED_CNT |
| default : begin |
| // return 0 |
| end |
| endcase |
| end |
| |
| {SCR1_CSR_ADDR_MHPMCOUNTERH_MASK, 5'b?????} : begin |
| case (exu2csr_rw_addr_i[4:0]) |
| 5'd1 : csr_r_exc = exu2csr_r_req_i; |
| `ifndef SCR1_CSR_REDUCED_CNT |
| 5'd0 : csr_r_data = csr_mcycle[63:32]; |
| 5'd2 : csr_r_data = csr_minstret[63:32]; |
| `endif // SCR1_CSR_REDUCED_CNT |
| default : begin |
| // return 0 |
| end |
| endcase |
| end |
| |
| {SCR1_CSR_ADDR_MHPMEVENT_MASK, 5'b?????} : begin |
| case (exu2csr_rw_addr_i[4:0]) |
| 5'd0, |
| 5'd1, |
| 5'd2 : csr_r_exc = exu2csr_r_req_i; |
| default : begin |
| // return 0 |
| end |
| endcase |
| end |
| |
| `ifdef SCR1_MCOUNTEN_EN |
| SCR1_CSR_ADDR_MCOUNTEN : csr_r_data = csr_mcounten; |
| `endif // SCR1_MCOUNTEN_EN |
| |
| `ifdef SCR1_IPIC_EN |
| // IPIC registers |
| SCR1_CSR_ADDR_IPIC_CISV, |
| SCR1_CSR_ADDR_IPIC_CICSR, |
| SCR1_CSR_ADDR_IPIC_IPR, |
| SCR1_CSR_ADDR_IPIC_ISVR, |
| SCR1_CSR_ADDR_IPIC_EOI, |
| SCR1_CSR_ADDR_IPIC_SOI, |
| SCR1_CSR_ADDR_IPIC_IDX, |
| SCR1_CSR_ADDR_IPIC_ICSR : begin |
| csr_r_data = ipic2csr_rdata_i; |
| csr2ipic_r_req_o = exu2csr_r_req_i; |
| end |
| `endif // SCR1_IPIC_EN |
| |
| `ifdef SCR1_DBG_EN |
| // HDU registers |
| SCR1_HDU_DBGCSR_ADDR_DCSR, |
| SCR1_HDU_DBGCSR_ADDR_DPC, |
| SCR1_HDU_DBGCSR_ADDR_DSCRATCH0, |
| SCR1_HDU_DBGCSR_ADDR_DSCRATCH1 : begin |
| csr_hdu_req = 1'b1; |
| csr_r_data = hdu2csr_rdata_i; |
| end |
| `endif // SCR1_DBG_EN |
| |
| `ifdef SCR1_TDU_EN |
| // TDU registers |
| SCR1_CSR_ADDR_TDU_TSELECT, |
| SCR1_CSR_ADDR_TDU_TDATA1, |
| SCR1_CSR_ADDR_TDU_TDATA2, |
| SCR1_CSR_ADDR_TDU_TINFO: begin |
| csr_brkm_req = 1'b1; |
| csr_r_data = tdu2csr_rdata_i; |
| end |
| `endif // SCR1_TDU_EN |
| |
| default : begin |
| csr_r_exc = exu2csr_r_req_i; |
| end |
| endcase // exu2csr_rw_addr_i |
| end |
| |
| assign csr2exu_r_data_o = csr_r_data; |
| |
| // CSR write logic |
| //------------------------------------------------------------------------------ |
| |
| always_comb begin |
| case (exu2csr_w_cmd_i) |
| SCR1_CSR_CMD_WRITE : csr_w_data = exu2csr_w_data_i; |
| SCR1_CSR_CMD_SET : csr_w_data = exu2csr_w_data_i | csr_r_data; |
| SCR1_CSR_CMD_CLEAR : csr_w_data = ~exu2csr_w_data_i & csr_r_data; |
| default : csr_w_data = '0; |
| endcase |
| end |
| |
| always_comb begin |
| csr_mstatus_upd = 1'b0; |
| csr_mie_upd = 1'b0; |
| csr_mscratch_upd = 1'b0; |
| csr_mepc_upd = 1'b0; |
| csr_mcause_upd = 1'b0; |
| csr_mtval_upd = 1'b0; |
| csr_mtvec_upd = 1'b0; |
| |
| `ifndef SCR1_CSR_REDUCED_CNT |
| csr_mcycle_upd = 2'b00; |
| csr_minstret_upd = 2'b00; |
| `endif // SCR1_CSR_REDUCED_CNT |
| |
| `ifdef SCR1_MCOUNTEN_EN |
| csr_mcounten_upd = 1'b0; |
| `endif // SCR1_MCOUNTEN_EN |
| csr_w_exc = 1'b0; |
| `ifdef SCR1_IPIC_EN |
| csr2ipic_w_req_o = 1'b0; |
| `endif // SCR1_IPIC_EN |
| |
| if (exu2csr_w_req_i) begin |
| casez (exu2csr_rw_addr_i) |
| // Machine Trap Setup (read-write) |
| SCR1_CSR_ADDR_MSTATUS : csr_mstatus_upd = 1'b1; |
| SCR1_CSR_ADDR_MISA : begin end |
| SCR1_CSR_ADDR_MIE : csr_mie_upd = 1'b1; |
| SCR1_CSR_ADDR_MTVEC : csr_mtvec_upd = 1'b1; |
| |
| // Machine Trap Handling (read-write) |
| SCR1_CSR_ADDR_MSCRATCH : csr_mscratch_upd = 1'b1; |
| SCR1_CSR_ADDR_MEPC : csr_mepc_upd = 1'b1; |
| SCR1_CSR_ADDR_MCAUSE : csr_mcause_upd = 1'b1; |
| SCR1_CSR_ADDR_MTVAL : csr_mtval_upd = 1'b1; |
| SCR1_CSR_ADDR_MIP : begin end |
| |
| // Machine Counters/Timers (read-write) |
| {SCR1_CSR_ADDR_MHPMCOUNTER_MASK, 5'b?????} : begin |
| case (exu2csr_rw_addr_i[4:0]) |
| 5'd1 : csr_w_exc = 1'b1; |
| `ifndef SCR1_CSR_REDUCED_CNT |
| 5'd0 : csr_mcycle_upd[0] = 1'b1; |
| 5'd2 : csr_minstret_upd[0] = 1'b1; |
| `endif // SCR1_CSR_REDUCED_CNT |
| default : begin |
| // no exception |
| end |
| endcase |
| end |
| |
| {SCR1_CSR_ADDR_MHPMCOUNTERH_MASK, 5'b?????} : begin |
| case (exu2csr_rw_addr_i[4:0]) |
| 5'd1 : csr_w_exc = 1'b1; |
| `ifndef SCR1_CSR_REDUCED_CNT |
| 5'd0 : csr_mcycle_upd[1] = 1'b1; |
| 5'd2 : csr_minstret_upd[1] = 1'b1; |
| `endif // SCR1_CSR_REDUCED_CNT |
| default : begin |
| // no exception |
| end |
| endcase |
| end |
| |
| {SCR1_CSR_ADDR_MHPMEVENT_MASK, 5'b?????} : begin |
| case (exu2csr_rw_addr_i[4:0]) |
| 5'd0, |
| 5'd1, |
| 5'd2 : csr_w_exc = 1'b1; |
| default : begin |
| // no exception |
| end |
| endcase |
| end |
| |
| `ifdef SCR1_MCOUNTEN_EN |
| SCR1_CSR_ADDR_MCOUNTEN : csr_mcounten_upd = 1'b1; |
| `endif // SCR1_MCOUNTEN_EN |
| |
| `ifdef SCR1_IPIC_EN |
| // IPIC registers |
| SCR1_CSR_ADDR_IPIC_CICSR, |
| SCR1_CSR_ADDR_IPIC_IPR, |
| SCR1_CSR_ADDR_IPIC_EOI, |
| SCR1_CSR_ADDR_IPIC_SOI, |
| SCR1_CSR_ADDR_IPIC_IDX, |
| SCR1_CSR_ADDR_IPIC_ICSR : begin |
| csr2ipic_w_req_o = 1'b1; |
| end |
| SCR1_CSR_ADDR_IPIC_CISV, |
| SCR1_CSR_ADDR_IPIC_ISVR : begin |
| // no exception on write |
| end |
| `endif // SCR1_IPIC_EN |
| |
| `ifdef SCR1_DBG_EN |
| SCR1_HDU_DBGCSR_ADDR_DCSR, |
| SCR1_HDU_DBGCSR_ADDR_DPC, |
| SCR1_HDU_DBGCSR_ADDR_DSCRATCH0, |
| SCR1_HDU_DBGCSR_ADDR_DSCRATCH1 : begin |
| end |
| `endif // SCR1_DBG_EN |
| |
| `ifdef SCR1_TDU_EN |
| // TDU registers |
| SCR1_CSR_ADDR_TDU_TSELECT, |
| SCR1_CSR_ADDR_TDU_TDATA1, |
| SCR1_CSR_ADDR_TDU_TDATA2, |
| SCR1_CSR_ADDR_TDU_TINFO: begin |
| end |
| `endif // SCR1_TDU_EN |
| |
| default : begin |
| csr_w_exc = 1'b1; |
| end |
| endcase |
| end |
| end |
| |
| //------------------------------------------------------------------------------ |
| // Machine Trap Setup registers |
| //------------------------------------------------------------------------------ |
| // |
| // Registers: |
| // - MSTATUS |
| // - MIE |
| // - MTVEC |
| // |
| |
| // MSTATUS register |
| //------------------------------------------------------------------------------ |
| // Consists of 2 bits - current and previous (before trap) global interrupt |
| // enable bits (MIE & MPIE) |
| |
| always_ff @(negedge rst_n, posedge clk) begin |
| if (~rst_n) begin |
| csr_mstatus_mie_ff <= SCR1_CSR_MSTATUS_MIE_RST_VAL; |
| csr_mstatus_mpie_ff <= SCR1_CSR_MSTATUS_MPIE_RST_VAL; |
| end else begin |
| csr_mstatus_mie_ff <= csr_mstatus_mie_next; |
| csr_mstatus_mpie_ff <= csr_mstatus_mpie_next; |
| end |
| end |
| |
| always_comb begin |
| case (1'b1) |
| e_exc, e_irq : begin |
| csr_mstatus_mie_next = 1'b0; |
| csr_mstatus_mpie_next = csr_mstatus_mie_ff; |
| end |
| e_mret : begin |
| csr_mstatus_mie_next = csr_mstatus_mpie_ff; |
| csr_mstatus_mpie_next = 1'b1; |
| end |
| csr_mstatus_upd: begin |
| csr_mstatus_mie_next = csr_w_data[SCR1_CSR_MSTATUS_MIE_OFFSET]; |
| csr_mstatus_mpie_next = csr_w_data[SCR1_CSR_MSTATUS_MPIE_OFFSET]; |
| end |
| default : begin |
| csr_mstatus_mie_next = csr_mstatus_mie_ff; |
| csr_mstatus_mpie_next = csr_mstatus_mpie_ff; |
| end |
| endcase |
| end |
| |
| always_comb begin |
| csr_mstatus = '0; |
| csr_mstatus[SCR1_CSR_MSTATUS_MIE_OFFSET] = csr_mstatus_mie_ff; |
| csr_mstatus[SCR1_CSR_MSTATUS_MPIE_OFFSET] = csr_mstatus_mpie_ff; |
| csr_mstatus[SCR1_CSR_MSTATUS_MPP_OFFSET+1:SCR1_CSR_MSTATUS_MPP_OFFSET] = SCR1_CSR_MSTATUS_MPP; |
| end |
| |
| // MIE register |
| //------------------------------------------------------------------------------ |
| // Contains interrupt enable bits (external, software, timer IRQs) |
| |
| always_ff @(negedge rst_n, posedge clk) begin |
| if (~rst_n) begin |
| csr_mie_mtie_ff <= SCR1_CSR_MIE_MTIE_RST_VAL; |
| csr_mie_meie_ff <= SCR1_CSR_MIE_MEIE_RST_VAL; |
| csr_mie_msie_ff <= SCR1_CSR_MIE_MSIE_RST_VAL; |
| end else if (csr_mie_upd) begin |
| csr_mie_mtie_ff <= csr_w_data[SCR1_CSR_MIE_MTIE_OFFSET]; |
| csr_mie_meie_ff <= csr_w_data[SCR1_CSR_MIE_MEIE_OFFSET]; |
| csr_mie_msie_ff <= csr_w_data[SCR1_CSR_MIE_MSIE_OFFSET]; |
| end |
| end |
| |
| always_comb begin |
| csr_mie = '0; |
| csr_mie[SCR1_CSR_MIE_MSIE_OFFSET] = csr_mie_msie_ff; |
| csr_mie[SCR1_CSR_MIE_MTIE_OFFSET] = csr_mie_mtie_ff; |
| csr_mie[SCR1_CSR_MIE_MEIE_OFFSET] = csr_mie_meie_ff; |
| end |
| |
| // MTVEC register |
| //------------------------------------------------------------------------------ |
| // Holds trap vector configuation. Consists of base and mode parts |
| |
| // MTVEC BASE part |
| //------------------------------------------------------------------------------ |
| // Holds trap vector base address |
| generate |
| // All bits of MTVEC base are Read-Only and hardwired to 0's |
| if (SCR1_MTVEC_BASE_WR_BITS == 0) begin : mtvec_base_ro |
| |
| assign csr_mtvec_base = SCR1_CSR_MTVEC_BASE_RST_VAL; |
| |
| // All bits of MTVEC base are RW |
| end else if (SCR1_MTVEC_BASE_WR_BITS == SCR1_CSR_MTVEC_BASE_VAL_BITS) begin : mtvec_base_rw |
| |
| always_ff @(negedge rst_n, posedge clk) begin |
| if (~rst_n) begin |
| csr_mtvec_base <= SCR1_CSR_MTVEC_BASE_RST_VAL; |
| end else if (csr_mtvec_upd) begin |
| csr_mtvec_base <= csr_w_data[`SCR1_XLEN-1:SCR1_CSR_MTVEC_BASE_ZERO_BITS]; |
| end |
| end |
| |
| // Lower bits of MTVEC base are RO, higher - RW |
| end else begin : mtvec_base_ro_rw |
| |
| logic [(`SCR1_XLEN-1):(`SCR1_XLEN-SCR1_MTVEC_BASE_WR_BITS)] csr_mtvec_base_reg; |
| |
| always_ff @(negedge rst_n, posedge clk) begin |
| if (~rst_n) begin |
| csr_mtvec_base_reg <= SCR1_CSR_MTVEC_BASE_RST_VAL[(`SCR1_XLEN-1)-:SCR1_MTVEC_BASE_WR_BITS] ; |
| end else if (csr_mtvec_upd) begin |
| csr_mtvec_base_reg <= csr_w_data[(`SCR1_XLEN-1)-:SCR1_MTVEC_BASE_WR_BITS]; |
| end |
| end |
| |
| assign csr_mtvec_base = {csr_mtvec_base_reg, SCR1_CSR_MTVEC_BASE_RST_VAL[SCR1_CSR_MTVEC_BASE_ZERO_BITS+:SCR1_CSR_MTVEC_BASE_RO_BITS]}; |
| end |
| endgenerate |
| |
| // MTVEC MODE part |
| //------------------------------------------------------------------------------ |
| // Chooses between direct (all exceptions set PC to BASE) or vectored |
| // (asynchronous interrupts set PC to BASE+4xcause) interrupt modes |
| |
| `ifdef SCR1_MTVEC_MODE_EN |
| always_ff @(negedge rst_n, posedge clk) begin |
| if (~rst_n) begin |
| csr_mtvec_mode_ff <= SCR1_CSR_MTVEC_MODE_DIRECT; |
| end else if (csr_mtvec_upd) begin |
| csr_mtvec_mode_ff <= csr_w_data[0]; |
| end |
| end |
| |
| assign csr_mtvec_mode = csr_mtvec_mode_ff; |
| assign csr_mtvec_mode_vect = (csr_mtvec_mode_ff == SCR1_CSR_MTVEC_MODE_VECTORED); |
| `else // SCR1_MTVEC_MODE_EN |
| assign csr_mtvec_mode = SCR1_CSR_MTVEC_MODE_DIRECT; |
| `endif // SCR1_MTVEC_MODE_EN |
| |
| //------------------------------------------------------------------------------ |
| // Machine Trap Handling registers |
| //------------------------------------------------------------------------------ |
| // |
| // Registers: |
| // - MSCRATCH |
| // - MEPC |
| // - MCAUSE |
| // - MTVAL |
| // - MIP |
| // |
| |
| // MSCRATCH register |
| //------------------------------------------------------------------------------ |
| // Holds a pointer to a machine-mode hart-local context space |
| |
| always_ff @(negedge rst_n, posedge clk) begin |
| if (~rst_n) begin |
| csr_mscratch_ff <= '0; |
| end else if (csr_mscratch_upd) begin |
| csr_mscratch_ff <= csr_w_data; |
| end |
| end |
| |
| // MEPC register |
| //------------------------------------------------------------------------------ |
| // When a trap is taken into M-mode saves the virtual address of instruction that |
| // was interrupted or that encountered the exception |
| |
| always_ff @(negedge rst_n, posedge clk) begin |
| if (~rst_n) begin |
| csr_mepc_ff <= '0; |
| end else begin |
| csr_mepc_ff <= csr_mepc_next; |
| end |
| end |
| |
| always_comb begin |
| case (1'b1) |
| e_exc : csr_mepc_next = exu2csr_pc_curr_i[`SCR1_XLEN-1:PC_LSB]; |
| e_irq_nmret : csr_mepc_next = exu2csr_pc_next_i[`SCR1_XLEN-1:PC_LSB]; |
| csr_mepc_upd: csr_mepc_next = csr_w_data[`SCR1_XLEN-1:PC_LSB]; |
| default : csr_mepc_next = csr_mepc_ff; |
| endcase |
| end |
| |
| `ifdef SCR1_RVC_EXT |
| assign csr_mepc = {csr_mepc_ff, 1'b0}; |
| `else |
| assign csr_mepc = {csr_mepc_ff, 2'b00}; |
| `endif |
| |
| // MCAUSE register |
| //------------------------------------------------------------------------------ |
| // When a trap is taken into M-mode saves a code indicating the event that caused |
| // the trap |
| |
| always_ff @(negedge rst_n, posedge clk) begin |
| if (~rst_n) begin |
| csr_mcause_i_ff <= 1'b0; |
| csr_mcause_ec_ff <= SCR1_EXC_CODE_RESET; // cp.7 |
| end else begin |
| csr_mcause_i_ff <= csr_mcause_i_next; |
| csr_mcause_ec_ff <= csr_mcause_ec_next; |
| end |
| end |
| |
| always_comb begin |
| case (1'b1) |
| e_exc : begin |
| csr_mcause_i_next = 1'b0; |
| csr_mcause_ec_next = exu2csr_exc_code_i; |
| end |
| e_irq : begin |
| csr_mcause_i_next = 1'b1; |
| csr_mcause_ec_next = csr_mcause_ec_new; |
| end |
| csr_mcause_upd: begin |
| csr_mcause_i_next = csr_w_data[`SCR1_XLEN-1]; |
| csr_mcause_ec_next = csr_w_data[SCR1_EXC_CODE_WIDTH_E-1:0]; // cp.7 |
| end |
| default : begin |
| csr_mcause_i_next = csr_mcause_i_ff; |
| csr_mcause_ec_next = csr_mcause_ec_ff; |
| end |
| endcase |
| end |
| |
| // MTVAL register |
| //------------------------------------------------------------------------------ |
| // When a trap is taken into M-mode is either set to zero or written with exception- |
| // specific information |
| |
| always_ff @(negedge rst_n, posedge clk) begin |
| if (~rst_n) begin |
| csr_mtval_ff <= '0; |
| end else begin |
| csr_mtval_ff <= csr_mtval_next; |
| end |
| end |
| |
| always_comb begin |
| case (1'b1) |
| e_exc : csr_mtval_next = exu2csr_trap_val_i; |
| e_irq : csr_mtval_next = '0; |
| csr_mtval_upd: csr_mtval_next = csr_w_data; |
| default : csr_mtval_next = csr_mtval_ff; |
| endcase |
| end |
| |
| // MIP register |
| //------------------------------------------------------------------------------ |
| // Contains information on pending interrupts (external, software, timer IRQs) |
| |
| assign csr_mip_mtip = soc2csr_irq_mtimer_i; |
| assign csr_mip_meip = soc2csr_irq_ext_i; |
| assign csr_mip_msip = soc2csr_irq_soft_i; |
| |
| always_comb begin |
| csr_mip = '0; |
| csr_mip[SCR1_CSR_MIE_MSIE_OFFSET] = csr_mip_msip; |
| csr_mip[SCR1_CSR_MIE_MTIE_OFFSET] = csr_mip_mtip; |
| csr_mip[SCR1_CSR_MIE_MEIE_OFFSET] = csr_mip_meip; |
| end |
| |
| //------------------------------------------------------------------------------ |
| // Machine Counters/Timers registers |
| //------------------------------------------------------------------------------ |
| // |
| // Registers: |
| // - MCYCLE |
| // - MINSTRET |
| // |
| |
| `ifndef SCR1_CSR_REDUCED_CNT |
| // MCYCLE register |
| //------------------------------------------------------------------------------ |
| // Holds the number of clock cycles since some arbitrary point of time in the |
| // past at which MCYCLE was zero |
| |
| assign csr_mcycle_lo_inc = 1'b1 |
| `ifdef SCR1_MCOUNTEN_EN |
| & csr_mcounten_cy_ff |
| `endif // SCR1_MCOUNTEN_EN |
| ; |
| assign csr_mcycle_hi_inc = csr_mcycle_lo_inc & (&csr_mcycle_lo_ff); |
| |
| assign csr_mcycle_lo_upd = csr_mcycle_lo_inc | csr_mcycle_upd[0]; |
| assign csr_mcycle_hi_upd = csr_mcycle_hi_inc | (|csr_mcycle_upd); |
| |
| `ifndef SCR1_CLKCTRL_EN |
| always_ff @(negedge rst_n, posedge clk) begin |
| `else // SCR1_CLKCTRL_EN |
| always_ff @(negedge rst_n, posedge clk_alw_on) begin |
| `endif // SCR1_CLKCTRL_EN |
| if (~rst_n) begin |
| csr_mcycle_lo_ff <= '0; |
| csr_mcycle_hi_ff <= '0; |
| end else begin |
| if (csr_mcycle_lo_upd) csr_mcycle_lo_ff <= csr_mcycle_lo_next; |
| if (csr_mcycle_hi_upd) csr_mcycle_hi_ff <= csr_mcycle_hi_next; |
| end |
| end |
| |
| assign csr_mcycle_hi_new = csr_mcycle_hi_ff + 1'b1; |
| |
| assign csr_mcycle_lo_next = csr_mcycle_upd[0] ? csr_w_data[7:0] |
| : csr_mcycle_lo_inc ? csr_mcycle_lo_ff + 1'b1 |
| : csr_mcycle_lo_ff; |
| assign csr_mcycle_hi_next = csr_mcycle_upd[0] ? {csr_mcycle_hi_new[63:32], csr_w_data[31:8]} |
| : csr_mcycle_upd[1] ? {csr_w_data, csr_mcycle_hi_new[31:8]} |
| : csr_mcycle_hi_inc ? csr_mcycle_hi_new |
| : csr_mcycle_hi_ff; |
| |
| assign csr_mcycle = {csr_mcycle_hi_ff, csr_mcycle_lo_ff}; |
| |
| // MINSTRET register |
| //------------------------------------------------------------------------------ |
| // Holds the number of instructions executed by the core from some arbitrary time |
| // in the past at which MINSTRET was equal to zero |
| |
| assign csr_minstret_lo_inc = exu2csr_instret_no_exc_i |
| `ifdef SCR1_MCOUNTEN_EN |
| & csr_mcounten_ir_ff |
| `endif // SCR1_MCOUNTEN_EN |
| ; |
| assign csr_minstret_hi_inc = csr_minstret_lo_inc & (&csr_minstret_lo_ff); |
| |
| assign csr_minstret_lo_upd = csr_minstret_lo_inc | csr_minstret_upd[0]; |
| assign csr_minstret_hi_upd = csr_minstret_hi_inc | (|csr_minstret_upd); |
| |
| always_ff @(negedge rst_n, posedge clk) begin |
| if (~rst_n) begin |
| csr_minstret_lo_ff <= '0; |
| csr_minstret_hi_ff <= '0; |
| end else begin |
| if (csr_minstret_lo_upd) csr_minstret_lo_ff <= csr_minstret_lo_next; |
| if (csr_minstret_hi_upd) csr_minstret_hi_ff <= csr_minstret_hi_next; |
| end |
| end |
| |
| assign csr_minstret_hi_new = csr_minstret_hi_ff + 1'b1; |
| |
| assign csr_minstret_lo_next = csr_minstret_upd[0] ? csr_w_data[7:0] |
| : csr_minstret_lo_inc ? csr_minstret_lo_ff + 1'b1 |
| : csr_minstret_lo_ff; |
| assign csr_minstret_hi_next = csr_minstret_upd[0] ? {csr_minstret_hi_new[63:32], csr_w_data[31:8]} |
| : csr_minstret_upd[1] ? {csr_w_data, csr_minstret_hi_new[31:8]} |
| : csr_minstret_hi_inc ? csr_minstret_hi_new |
| : csr_minstret_hi_ff; |
| |
| assign csr_minstret = {csr_minstret_hi_ff, csr_minstret_lo_ff}; |
| `endif // SCR1_CSR_REDUCED_CNT |
| |
| //------------------------------------------------------------------------------ |
| // Non-standard CSR |
| //------------------------------------------------------------------------------ |
| |
| `ifdef SCR1_MCOUNTEN_EN |
| // MCOUNTEN register |
| //------------------------------------------------------------------------------ |
| // Holds Counters enable bits (CY - MCYCLE counter; IR - MINSTRET counter) |
| |
| always_ff @(negedge rst_n, posedge clk) begin |
| if (~rst_n) begin |
| csr_mcounten_cy_ff <= 1'b1; |
| csr_mcounten_ir_ff <= 1'b1; |
| end else if (csr_mcounten_upd) begin |
| csr_mcounten_cy_ff <= csr_w_data[SCR1_CSR_MCOUNTEN_CY_OFFSET]; |
| csr_mcounten_ir_ff <= csr_w_data[SCR1_CSR_MCOUNTEN_IR_OFFSET]; |
| end |
| end |
| |
| always_comb begin |
| csr_mcounten = '0; |
| csr_mcounten[SCR1_CSR_MCOUNTEN_CY_OFFSET] = csr_mcounten_cy_ff; |
| csr_mcounten[SCR1_CSR_MCOUNTEN_IR_OFFSET] = csr_mcounten_ir_ff; |
| end |
| `endif // SCR1_MCOUNTEN_EN |
| |
| //------------------------------------------------------------------------------ |
| // CSR <-> EXU interface |
| //------------------------------------------------------------------------------ |
| |
| // CSR exception |
| assign csr2exu_rw_exc_o = csr_r_exc | csr_w_exc |
| `ifdef SCR1_DBG_EN |
| | (csr2hdu_req_o & (hdu2csr_resp_i != SCR1_CSR_RESP_OK)) |
| `endif // SCR1_DBG_EN |
| `ifdef SCR1_TDU_EN |
| | (csr2tdu_req_o & (tdu2csr_resp_i != SCR1_CSR_RESP_OK)) |
| `endif // SCR1_TDU_EN |
| ; |
| assign csr2exu_ip_ie_o = csr_eirq_pnd_en | csr_sirq_pnd_en | csr_tirq_pnd_en; |
| assign csr2exu_irq_o = csr2exu_ip_ie_o & csr_mstatus_mie_ff; |
| |
| assign csr2exu_mstatus_mie_up_o = csr_mstatus_upd | csr_mie_upd | e_mret; |
| |
| // New PC multiplexer |
| `ifndef SCR1_MTVEC_MODE_EN |
| assign csr2exu_new_pc_o = (exu2csr_mret_instr_i & ~exu2csr_take_irq_i) |
| ? csr_mepc |
| : {csr_mtvec_base, SCR1_CSR_MTVEC_BASE_ZERO_BITS'(0)}; |
| `else // SCR1_MTVEC_MODE_EN |
| always_comb begin |
| if (exu2csr_mret_instr_i & ~exu2csr_take_irq_i) begin |
| csr2exu_new_pc_o = csr_mepc; |
| end else begin |
| if (csr_mtvec_mode_vect) begin |
| case (1'b1) |
| exu2csr_take_exc_i: csr2exu_new_pc_o = {csr_mtvec_base, SCR1_CSR_MTVEC_BASE_ZERO_BITS'(0)}; |
| csr_eirq_pnd_en : csr2exu_new_pc_o = {csr_mtvec_base, SCR1_EXC_CODE_IRQ_M_EXTERNAL, 2'd0}; |
| csr_sirq_pnd_en : csr2exu_new_pc_o = {csr_mtvec_base, SCR1_EXC_CODE_IRQ_M_SOFTWARE, 2'd0}; |
| csr_tirq_pnd_en : csr2exu_new_pc_o = {csr_mtvec_base, SCR1_EXC_CODE_IRQ_M_TIMER, 2'd0}; |
| default : csr2exu_new_pc_o = {csr_mtvec_base, SCR1_CSR_MTVEC_BASE_ZERO_BITS'(0)}; |
| endcase |
| end else begin // direct mode |
| csr2exu_new_pc_o = {csr_mtvec_base, SCR1_CSR_MTVEC_BASE_ZERO_BITS'(0)}; |
| end |
| end |
| end |
| `endif // SCR1_MTVEC_MODE_EN |
| |
| `ifdef SCR1_IPIC_EN |
| //------------------------------------------------------------------------------ |
| // CSR <-> IPIC interface |
| //------------------------------------------------------------------------------ |
| |
| assign csr_ipic_req = csr2ipic_r_req_o | csr2ipic_w_req_o; |
| assign csr2ipic_addr_o = csr_ipic_req ? exu2csr_rw_addr_i[2:0] : '0; |
| assign csr2ipic_wdata_o = csr2ipic_w_req_o ? exu2csr_w_data_i : '0; |
| `endif // SCR1_IPIC_EN |
| |
| `ifdef SCR1_DBG_EN |
| //------------------------------------------------------------------------------ |
| // CSR <-> HDU interface |
| //------------------------------------------------------------------------------ |
| |
| assign csr2hdu_req_o = csr_hdu_req & exu_req_no_exc; |
| assign csr2hdu_cmd_o = exu2csr_w_cmd_i; |
| assign csr2hdu_addr_o = exu2csr_rw_addr_i[SCR1_HDU_DEBUGCSR_ADDR_WIDTH-1:0]; |
| assign csr2hdu_wdata_o = exu2csr_w_data_i; |
| `endif // SCR1_DBG_EN |
| |
| `ifdef SCR1_TDU_EN |
| //------------------------------------------------------------------------------ |
| // CSR <-> TDU interface |
| //------------------------------------------------------------------------------ |
| |
| assign csr2tdu_req_o = csr_brkm_req & exu_req_no_exc; |
| assign csr2tdu_cmd_o = exu2csr_w_cmd_i; |
| assign csr2tdu_addr_o = exu2csr_rw_addr_i[SCR1_CSR_ADDR_TDU_OFFS_W-1:0]; |
| assign csr2tdu_wdata_o = exu2csr_w_data_i; |
| `endif // SCR1_TDU_EN |
| |
| `ifdef SCR1_TRGT_SIMULATION |
| //------------------------------------------------------------------------------ |
| // Assertions |
| //------------------------------------------------------------------------------ |
| |
| // X checks |
| |
| SCR1_SVA_CSR_XCHECK_CTRL : assert property ( |
| @(negedge clk) disable iff (~rst_n) |
| !$isunknown({exu2csr_r_req_i, exu2csr_w_req_i, exu2csr_take_irq_i, exu2csr_take_exc_i, exu2csr_mret_update_i |
| `ifndef SCR1_CSR_REDUCED_CNT |
| , exu2csr_instret_no_exc_i |
| `endif // SCR1_CSR_REDUCED_CNT |
| }) |
| ) else $error("CSR Error: unknown control values"); |
| |
| SCR1_SVA_CSR_XCHECK_READ : assert property ( |
| @(negedge clk) disable iff (~rst_n) |
| exu2csr_r_req_i |-> !$isunknown({exu2csr_rw_addr_i, csr2exu_r_data_o, csr2exu_rw_exc_o}) |
| ) else $error("CSR Error: unknown control values"); |
| |
| SCR1_SVA_CSR_XCHECK_WRITE : assert property ( |
| @(negedge clk) disable iff (~rst_n) |
| exu2csr_w_req_i |-> !$isunknown({exu2csr_rw_addr_i, exu2csr_w_cmd_i, exu2csr_w_data_i, csr2exu_rw_exc_o}) |
| ) else $error("CSR Error: unknown control values"); |
| |
| `ifdef SCR1_IPIC_EN |
| SCR1_SVA_CSR_XCHECK_READ_IPIC : assert property ( |
| @(negedge clk) disable iff (~rst_n) |
| csr2ipic_r_req_o |-> !$isunknown({csr2ipic_addr_o, ipic2csr_rdata_i}) |
| ) else $error("CSR Error: unknown control values"); |
| |
| SCR1_SVA_CSR_XCHECK_WRITE_IPIC : assert property ( |
| @(negedge clk) disable iff (~rst_n) |
| csr2ipic_w_req_o |-> !$isunknown({csr2ipic_addr_o, csr2ipic_wdata_o}) |
| ) else $error("CSR Error: unknown control values"); |
| `endif // SCR1_IPIC_EN |
| |
| // Behavior checks |
| |
| `ifndef VERILATOR |
| SCR1_SVA_CSR_MRET : assert property ( |
| @(negedge clk) disable iff (~rst_n) |
| e_mret |=> ($stable(csr_mepc_ff) & $stable(csr_mtval_ff)) |
| ) else $error("CSR Error: MRET wrong behavior"); |
| |
| SCR1_SVA_CSR_MRET_IRQ : assert property ( |
| @(negedge clk) disable iff (~rst_n) |
| (exu2csr_mret_instr_i & e_irq) |
| |=> ($stable(csr_mepc_ff) & (exu2csr_pc_curr_i != csr_mepc)) |
| ) else $error("CSR Error: MRET+IRQ wrong behavior"); |
| |
| SCR1_SVA_CSR_EXC_IRQ : assert property ( |
| @(negedge clk) disable iff (~rst_n) |
| (exu2csr_take_exc_i & exu2csr_take_irq_i |
| `ifdef SCR1_DBG_EN |
| & ~hdu2csr_no_commit_i |
| `endif |
| ) |=> |
| (~csr_mstatus_mie_ff & (~csr_mcause_i_ff) |
| & (exu2csr_pc_curr_i=={csr_mtvec_base, SCR1_CSR_MTVEC_BASE_ZERO_BITS'(0)})) |
| ) else $error("CSR Error: wrong EXC+IRQ"); |
| `endif // VERILATOR |
| SCR1_SVA_CSR_EVENTS : assert property ( |
| @(negedge clk) disable iff (~rst_n) |
| $onehot0({e_irq, e_exc, e_mret}) |
| ) else $error("CSR Error: more than one event at a time"); |
| |
| SCR1_SVA_CSR_RW_EXC : assert property ( |
| @(negedge clk) disable iff (~rst_n) |
| csr2exu_rw_exc_o |-> (exu2csr_w_req_i | exu2csr_r_req_i) |
| ) else $error("CSR Error: impossible exception"); |
| |
| `ifndef VERILATOR |
| SCR1_SVA_CSR_MSTATUS_MIE_UP : assert property ( |
| @(negedge clk) disable iff (~rst_n) |
| csr2exu_mstatus_mie_up_o |=> ~csr2exu_mstatus_mie_up_o |
| ) else $error("CSR Error: csr2exu_mstatus_mie_up_o can only be high for one mcycle"); |
| `endif // VERILATOR |
| |
| `ifndef SCR1_CSR_REDUCED_CNT |
| |
| `ifndef VERILATOR |
| SCR1_SVA_CSR_CYCLE_INC : assert property ( |
| @( |
| `ifndef SCR1_CLKCTRL_EN |
| negedge clk |
| `else // SCR1_CLKCTRL_EN |
| negedge clk_alw_on |
| `endif // SCR1_CLKCTRL_EN |
| ) disable iff (~rst_n) |
| (~|csr_mcycle_upd) |=> |
| `ifdef SCR1_MCOUNTEN_EN |
| ($past(csr_mcounten_cy_ff) ? (csr_mcycle == $past(csr_mcycle + 1'b1)) : $stable(csr_mcycle)) |
| `else //SCR1_MCOUNTEN_EN |
| (csr_mcycle == $past(csr_mcycle + 1'b1)) |
| `endif // SCR1_MCOUNTEN_EN |
| ) else $error("CSR Error: CYCLE increment wrong behavior"); |
| |
| SCR1_SVA_CSR_INSTRET_INC : assert property ( |
| @(negedge clk) disable iff (~rst_n) |
| (exu2csr_instret_no_exc_i & ~|csr_minstret_upd) |=> |
| `ifdef SCR1_MCOUNTEN_EN |
| ($past(csr_mcounten_ir_ff) ? (csr_minstret == $past(csr_minstret + 1'b1)) : $stable(csr_minstret)) |
| `else //SCR1_MCOUNTEN_EN |
| (csr_minstret == $past(csr_minstret + 1'b1)) |
| `endif // SCR1_MCOUNTEN_EN |
| ) else $error("CSR Error: INSTRET increment wrong behavior"); |
| `endif |
| SCR1_SVA_CSR_CYCLE_INSTRET_UP : assert property ( |
| @(negedge clk) disable iff (~rst_n) |
| ~(&csr_minstret_upd | &csr_mcycle_upd) |
| ) else $error("CSR Error: INSTRET/CYCLE up illegal value"); |
| |
| `endif // SCR1_CSR_REDUCED_CNT |
| |
| `endif // SCR1_TRGT_SIMULATION |
| |
| endmodule : scr1_pipe_csr |