diff --git a/rtl/ibex_controller.sv b/rtl/ibex_controller.sv index db98a0ae..77869e98 100644 --- a/rtl/ibex_controller.sv +++ b/rtl/ibex_controller.sv @@ -75,6 +75,10 @@ module ibex_controller #( // mie CSR input logic irq_nm_i, // non-maskeable interrupt output logic nmi_mode_o, // core executing NMI handler + input logic [31:0] irqs_x_i, // x interrupt requests qualified with + // miex CSR + output logic irq_x_ack_o, // to ext. int controller + output logic [4:0] irq_x_ack_id_o, // to ext. int controller // debug signals input logic debug_req_i, @@ -150,6 +154,8 @@ module ibex_controller #( logic [3:0] mfip_id; logic unused_irq_timer; + logic [4:0] irq_x_id; + logic ecall_insn; logic mret_insn; logic dret_insn; @@ -353,6 +359,42 @@ module ibex_controller #( assign unused_irq_timer = irqs_i.irq_timer; + // generate ID of custom interrupts, highest priority to highest ID + always_comb begin : gen_irq_x_id + if (irqs_x_i[31]) irq_x_id = 5'd31; + else if (irqs_x_i[30]) irq_x_id = 5'd30; + else if (irqs_x_i[29]) irq_x_id = 5'd29; + else if (irqs_x_i[28]) irq_x_id = 5'd28; + else if (irqs_x_i[27]) irq_x_id = 5'd27; + else if (irqs_x_i[26]) irq_x_id = 5'd26; + else if (irqs_x_i[25]) irq_x_id = 5'd25; + else if (irqs_x_i[24]) irq_x_id = 5'd24; + else if (irqs_x_i[23]) irq_x_id = 5'd23; + else if (irqs_x_i[22]) irq_x_id = 5'd22; + else if (irqs_x_i[21]) irq_x_id = 5'd21; + else if (irqs_x_i[20]) irq_x_id = 5'd20; + else if (irqs_x_i[19]) irq_x_id = 5'd19; + else if (irqs_x_i[18]) irq_x_id = 5'd18; + else if (irqs_x_i[17]) irq_x_id = 5'd17; + else if (irqs_x_i[16]) irq_x_id = 5'd16; + else if (irqs_x_i[15]) irq_x_id = 5'd15; + else if (irqs_x_i[14]) irq_x_id = 5'd14; + else if (irqs_x_i[13]) irq_x_id = 5'd13; + else if (irqs_x_i[12]) irq_x_id = 5'd12; + else if (irqs_x_i[11]) irq_x_id = 5'd11; + else if (irqs_x_i[10]) irq_x_id = 5'd10; + else if (irqs_x_i[ 9]) irq_x_id = 5'd9; + else if (irqs_x_i[ 8]) irq_x_id = 5'd8; + else if (irqs_x_i[ 7]) irq_x_id = 5'd7; + else if (irqs_x_i[ 6]) irq_x_id = 5'd6; + else if (irqs_x_i[ 5]) irq_x_id = 5'd5; + else if (irqs_x_i[ 4]) irq_x_id = 5'd4; + else if (irqs_x_i[ 3]) irq_x_id = 5'd3; + else if (irqs_x_i[ 2]) irq_x_id = 5'd2; + else if (irqs_x_i[ 1]) irq_x_id = 5'd1; + else irq_x_id = 5'd0; + end + ///////////////////// // Core controller // ///////////////////// @@ -399,6 +441,9 @@ module ibex_controller #( controller_run_o = 1'b0; + irq_x_ack_o = 1'b0; + irq_x_ack_id_o = 5'b0; + unique case (ctrl_fsm_cs) RESET: begin instr_req_o = 1'b0; @@ -569,6 +614,13 @@ module ibex_controller #( if (irq_nm_i && !nmi_mode_q) begin exc_cause_o = EXC_CAUSE_IRQ_NM; nmi_mode_d = 1'b1; // enter NMI mode + end else if (irqs_x_i != 32'b0) begin + // generate exception cause ID from fast interrupt ID: + // - first bit distinguishes interrupts from exceptions, + exc_cause_o = exc_cause_e'({1'b1, irq_x_id}); + exc_pc_mux_o = EXC_PC_IRQ_X; + irq_x_ack_o = 1'b1; + irq_x_ack_id_o = irq_x_id; end else if (irqs_i.irq_fast != 15'b0) begin // generate exception cause ID from fast interrupt ID: // - first bit distinguishes interrupts from exceptions, diff --git a/rtl/ibex_core.sv b/rtl/ibex_core.sv index 33056ae5..79ab576b 100644 --- a/rtl/ibex_core.sv +++ b/rtl/ibex_core.sv @@ -67,6 +67,9 @@ module ibex_core #( input logic irq_external_i, input logic [14:0] irq_fast_i, input logic irq_nm_i, // non-maskeable interrupt + input logic [31:0] irq_x_i, + output logic irq_x_ack_o, + output logic [4:0] irq_x_ack_id_o, // Debug Interface input logic debug_req_i, @@ -264,6 +267,7 @@ module ibex_core #( logic irq_pending; logic nmi_mode; irqs_t irqs; + logic [31:0] irqs_x; logic csr_mstatus_mie; logic [31:0] csr_mepc, csr_depc; @@ -282,6 +286,7 @@ module ibex_core #( logic csr_save_cause; logic csr_mtvec_init; logic [31:0] csr_mtvec; + logic [31:0] csr_mtvecx; logic [31:0] csr_mtval; logic csr_mstatus_tw; priv_lvl_e priv_mode_id; @@ -458,6 +463,7 @@ module ibex_core #( .csr_mepc_i ( csr_mepc ), // exception return address .csr_depc_i ( csr_depc ), // debug return address .csr_mtvec_i ( csr_mtvec ), // trap-vector base address + .csr_mtvecx_i ( csr_mtvecx ), // x trap-vector base address .csr_mtvec_init_o ( csr_mtvec_init ), // pipeline stalls @@ -586,6 +592,9 @@ module ibex_core #( .irqs_i ( irqs ), .irq_nm_i ( irq_nm_i ), .nmi_mode_o ( nmi_mode ), + .irqs_x_i ( irqs_x ), + .irq_x_ack_o ( irq_x_ack_o ), + .irq_x_ack_id_o ( irq_x_ack_id_o ), // Debug Signal .debug_mode_o ( debug_mode ), @@ -991,6 +1000,7 @@ module ibex_core #( // mtvec .csr_mtvec_o ( csr_mtvec ), + .csr_mtvecx_o ( csr_mtvecx ), .csr_mtvec_init_i ( csr_mtvec_init ), .boot_addr_i ( boot_addr_i ), @@ -1007,9 +1017,11 @@ module ibex_core #( .irq_timer_i ( irq_timer_i ), .irq_external_i ( irq_external_i ), .irq_fast_i ( irq_fast_i ), + .irq_x_i ( irq_x_i ), .nmi_mode_i ( nmi_mode ), .irq_pending_o ( irq_pending ), .irqs_o ( irqs ), + .irqs_x_o ( irqs_x ), .csr_mstatus_mie_o ( csr_mstatus_mie ), .csr_mstatus_tw_o ( csr_mstatus_tw ), .csr_mepc_o ( csr_mepc ), diff --git a/rtl/ibex_core_tracing.sv b/rtl/ibex_core_tracing.sv index a14eb5af..6641cf8d 100644 --- a/rtl/ibex_core_tracing.sv +++ b/rtl/ibex_core_tracing.sv @@ -61,6 +61,9 @@ module ibex_core_tracing #( input logic irq_external_i, input logic [14:0] irq_fast_i, input logic irq_nm_i, // non-maskeable interrupt + output logic [31:0] irq_x_i, + output logic irq_x_ack_o, + output logic [3:0] irq_x_ack_id_o, // Debug Interface input logic debug_req_i, @@ -155,6 +158,9 @@ module ibex_core_tracing #( .irq_external_i, .irq_fast_i, .irq_nm_i, + .irq_x_i, + .irq_x_ack_o, + .irq_x_ack_id_o, .debug_req_i, diff --git a/rtl/ibex_cs_registers.sv b/rtl/ibex_cs_registers.sv index c776af27..0c6bdf97 100644 --- a/rtl/ibex_cs_registers.sv +++ b/rtl/ibex_cs_registers.sv @@ -43,6 +43,7 @@ module ibex_cs_registers #( // mtvec output logic [31:0] csr_mtvec_o, + output logic [31:0] csr_mtvecx_o, input logic csr_mtvec_init_i, input logic [31:0] boot_addr_i, @@ -59,9 +60,11 @@ module ibex_cs_registers #( input logic irq_timer_i, input logic irq_external_i, input logic [14:0] irq_fast_i, + input logic [31:0] irq_x_i, input logic nmi_mode_i, output logic irq_pending_o, // interrupt request pending output ibex_pkg::irqs_t irqs_o, // interrupt requests qualified with mie + output logic [31:0] irqs_x_o, // custom interrupt requests qualified with miex output logic csr_mstatus_mie_o, output logic [31:0] csr_mepc_o, @@ -209,6 +212,14 @@ module ibex_cs_registers #( logic [31:0] dscratch1_q; logic dscratch0_en, dscratch1_en; + // CLINTx + logic [31:0] miex_q; + logic miex_en; + logic [31:0] mipx; + logic [31:0] mtvecx_q, mtvecx_d; + logic mtvecx_err; + logic mtvecx_en; + // CSRs for recoverable NMIs // NOTE: these CSRS are nonstandard, see https://github.com/riscv/riscv-isa-manual/issues/261 status_stk_t mstack_q, mstack_d; @@ -286,6 +297,9 @@ module ibex_cs_registers #( assign mip.irq_external = irq_external_i; assign mip.irq_fast = irq_fast_i; + // mipx CSR is purely combinational - must be able to re-enable the clock upon WFI + assign mipx = irq_x_i; + // read logic always_comb begin csr_rdata_int = '0; @@ -458,6 +472,11 @@ module ibex_cs_registers #( csr_rdata_int = '0; end + // CLINTx + CSR_MIEX: csr_rdata_int = miex_q; + CSR_MIPX: csr_rdata_int = mipx; + CSR_MTVECX: csr_rdata_int = mtvecx_q; + default: begin illegal_csr = 1'b1; end @@ -503,6 +522,13 @@ module ibex_cs_registers #( cpuctrl_we = 1'b0; + miex_en = 1'b0; + mtvecx_en = csr_mtvec_init_i; + // mtvecx.MODE set to vectored + // mtvecx.BASE must be 256-byte aligned + mtvecx_d = csr_mtvec_init_i ? {boot_addr_i[31:8], 6'b0, 2'b01} : + {csr_wdata_int[31:8], 6'b0, 2'b01}; + if (csr_we_int) begin unique case (csr_addr_i) // mstatus: IE bit @@ -599,6 +625,10 @@ module ibex_cs_registers #( CSR_CPUCTRL: cpuctrl_we = 1'b1; + // CLINTx + CSR_MIEX: miex_en = 1'b1; + CSR_MTVECX: mtvecx_en = 1'b1; + default:; endcase end @@ -730,7 +760,14 @@ module ibex_cs_registers #( // Qualify incoming interrupt requests in mip CSR with mie CSR for controller and to re-enable // clock upon WFI (must be purely combinational). assign irqs_o = mip & mie_q; - assign irq_pending_o = |irqs_o; + assign irq_pending_o = (|irqs_o) | (|irqs_x_o); + + // Qualify incoming interrupt requests in mipx CSR with miex CSR for controller and to re-enable + // clock upon WFI (must be purely combinational). + assign irqs_x_o = mipx & miex_q; + + // directly output mtvecx to IF stage + assign csr_mtvecx_o = mtvecx_q; //////////////////////// // CSR instantiations // @@ -1412,7 +1449,39 @@ module ibex_cs_registers #( .rd_error_o (cpuctrl_err) ); - assign csr_shadow_err_o = mstatus_err | mtvec_err | pmp_csr_err | cpuctrl_err; + assign csr_shadow_err_o = mstatus_err | mtvec_err | mtvecx_err | pmp_csr_err | cpuctrl_err; + + //////////// + // CLINTx // + //////////// + + // MIEX + ibex_csr #( + .Width (32), + .ShadowCopy (1'b0), + .ResetValue ('0) + ) u_miex_csr ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .wr_data_i (csr_wdata_int), + .wr_en_i (miex_en), + .rd_data_o (miex_q), + .rd_error_o () + ); + + // MTVECX + ibex_csr #( + .Width (32), + .ShadowCopy (ShadowCSR), + .ResetValue (32'd1) + ) u_mtvecx_csr ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .wr_data_i (mtvecx_d), + .wr_en_i (mtvecx_en), + .rd_data_o (mtvecx_q), + .rd_error_o (mtvecx_err) + ); //////////////// // Assertions // diff --git a/rtl/ibex_id_stage.sv b/rtl/ibex_id_stage.sv index 7c91eae1..162ecdf3 100644 --- a/rtl/ibex_id_stage.sv +++ b/rtl/ibex_id_stage.sv @@ -127,6 +127,9 @@ module ibex_id_stage #( input ibex_pkg::irqs_t irqs_i, input logic irq_nm_i, output logic nmi_mode_o, + input logic [31:0] irqs_x_i, + output logic irq_x_ack_o, + output logic [4:0] irq_x_ack_id_o, input logic lsu_load_err_i, input logic lsu_store_err_i, @@ -582,6 +585,9 @@ module ibex_id_stage #( .irqs_i ( irqs_i ), .irq_nm_i ( irq_nm_i ), .nmi_mode_o ( nmi_mode_o ), + .irqs_x_i ( irqs_x_i ), + .irq_x_ack_o ( irq_x_ack_o ), + .irq_x_ack_id_o ( irq_x_ack_id_o ), // CSR Controller Signals .csr_save_if_o ( csr_save_if_o ), diff --git a/rtl/ibex_if_stage.sv b/rtl/ibex_if_stage.sv index 33911e46..201fb884 100644 --- a/rtl/ibex_if_stage.sv +++ b/rtl/ibex_if_stage.sv @@ -83,6 +83,7 @@ module ibex_if_stage #( input logic [31:0] csr_depc_i, // PC to restore after handling // the debug request input logic [31:0] csr_mtvec_i, // base PC to jump to on exception + input logic [31:0] csr_mtvecx_i, // base PC to jump to on x interrupts output logic csr_mtvec_init_o, // tell CS regfile to init mtvec // pipeline stall @@ -139,9 +140,11 @@ module ibex_if_stage #( logic [7:0] unused_boot_addr; logic [7:0] unused_csr_mtvec; + logic [7:0] unused_csr_mtvecx; assign unused_boot_addr = boot_addr_i[7:0]; assign unused_csr_mtvec = csr_mtvec_i[7:0]; + assign unused_csr_mtvecx = csr_mtvecx_i[7:0]; // extract interrupt ID from exception cause assign irq_id = {exc_cause}; @@ -152,6 +155,7 @@ module ibex_if_stage #( unique case (exc_pc_mux_i) EXC_PC_EXC: exc_pc = { csr_mtvec_i[31:8], 8'h00 }; EXC_PC_IRQ: exc_pc = { csr_mtvec_i[31:8], 1'b0, irq_id[4:0], 2'b00 }; + EXC_PC_IRQ_X: exc_pc = { csr_mtvecx_i[31:8],1'b0, irq_id[4:0], 2'b00 }; EXC_PC_DBD: exc_pc = DmHaltAddr; EXC_PC_DBG_EXC: exc_pc = DmExceptionAddr; default: exc_pc = { csr_mtvec_i[31:8], 8'h00 }; diff --git a/rtl/ibex_pkg.sv b/rtl/ibex_pkg.sv index 42ac4863..8aed775a 100644 --- a/rtl/ibex_pkg.sv +++ b/rtl/ibex_pkg.sv @@ -257,9 +257,10 @@ typedef enum logic [2:0] { } pc_sel_e; // Exception PC mux selection -typedef enum logic [1:0] { +typedef enum logic [2:0] { EXC_PC_EXC, EXC_PC_IRQ, + EXC_PC_IRQ_X, EXC_PC_DBD, EXC_PC_DBG_EXC // Exception while in debug mode } exc_pc_sel_e; @@ -386,6 +387,11 @@ typedef enum logic[11:0] { CSR_DSCRATCH0 = 12'h7b2, // optional CSR_DSCRATCH1 = 12'h7b3, // optional + // CLINTx + CSR_MIEX = 12'h7D0, + CSR_MTVECX = 12'h7D1, + CSR_MIPX = 12'h7D2, + // Machine Counter/Timers CSR_MCOUNTINHIBIT = 12'h320, CSR_MHPMEVENT3 = 12'h323,