[rtl] Decouple mip and mie CSRs

This commit modifies the `mip` CSR to not depend on the `mie` CSR. While
the values of both these CSRs are combined to decide whether an
interrupt shall be handled, the RISC-V spec does not state that the
content of of `mip` should depend on `mie`. This commit better aligns
Ibex with other open-source RISC-V cores.

This resolves lowRISC/ibex#567 reported by @pfmooney.

Signed-off-by: Pirmin Vogel <vogelpi@lowrisc.org>
This commit is contained in:
Pirmin Vogel 2020-01-29 16:11:35 +01:00
parent 6708ba62ac
commit 2a42c23eaf
7 changed files with 54 additions and 79 deletions

View file

@ -45,12 +45,9 @@ module tb_cs_registers #(
logic irq_timer_i;
logic irq_external_i;
logic [14:0] irq_fast_i;
logic irq_pending_o; // interupt request pending
logic nmi_mode_i; // core is handling an NMI
logic csr_msip_o; // software interrupt pending
logic csr_mtip_o; // timer interrupt pending
logic csr_meip_o; // external interrupt pending
logic [14:0] csr_mfip_o; // fast interrupt pending
logic irq_pending_o; // interupt request pending
ibex_pkg::irqs_t irqs_o;
logic csr_mstatus_mie_o;
logic [31:0] csr_mepc_o;

View file

@ -58,7 +58,7 @@ lint_off -msg UNUSED -file "*/rtl/ibex_register_file_fpga.sv" -lines 20
// Signal unoptimizable: Feedback to clock or circular logic:
// ibex_core.cs_registers_i.mie_q
// Issue lowrisc/ibex#212
lint_off -msg UNOPTFLAT -file "*/rtl/ibex_cs_registers.sv" -lines 170
lint_off -msg UNOPTFLAT -file "*/rtl/ibex_cs_registers.sv" -lines 158
// Bits of signal are not used: instr_alu[24:15,11:7]
// instr flops are duplicated to reduce fan-out, neater to just leave unused

View file

@ -56,11 +56,9 @@ module ibex_controller (
// interrupt signals
input logic csr_mstatus_mie_i, // M-mode interrupt enable bit
input logic csr_msip_i, // software interrupt pending
input logic csr_mtip_i, // timer interrupt pending
input logic csr_meip_i, // external interrupt pending
input logic [14:0] csr_mfip_i, // fast interrupt pending
input logic irq_pending_i, // interrupt request pending
input ibex_pkg::irqs_t irqs_i, // interrupt requests qualified with
// mie CSR
input logic irq_nm_i, // non-maskeable interrupt
output logic nmi_mode_o, // core executing NMI handler
@ -124,7 +122,7 @@ module ibex_controller (
logic handle_irq;
logic [3:0] mfip_id;
logic unused_csr_mtip;
logic unused_irq_timer;
logic ecall_insn;
logic mret_insn;
@ -221,25 +219,25 @@ module ibex_controller (
// generate ID of fast interrupts, highest priority to highest ID
always_comb begin : gen_mfip_id
if (csr_mfip_i[14]) mfip_id = 4'd14;
else if (csr_mfip_i[13]) mfip_id = 4'd13;
else if (csr_mfip_i[12]) mfip_id = 4'd12;
else if (csr_mfip_i[11]) mfip_id = 4'd11;
else if (csr_mfip_i[10]) mfip_id = 4'd10;
else if (csr_mfip_i[ 9]) mfip_id = 4'd9;
else if (csr_mfip_i[ 8]) mfip_id = 4'd8;
else if (csr_mfip_i[ 7]) mfip_id = 4'd7;
else if (csr_mfip_i[ 6]) mfip_id = 4'd6;
else if (csr_mfip_i[ 5]) mfip_id = 4'd5;
else if (csr_mfip_i[ 5]) mfip_id = 4'd5;
else if (csr_mfip_i[ 4]) mfip_id = 4'd4;
else if (csr_mfip_i[ 3]) mfip_id = 4'd3;
else if (csr_mfip_i[ 2]) mfip_id = 4'd2;
else if (csr_mfip_i[ 1]) mfip_id = 4'd1;
else mfip_id = 4'd0;
if (irqs_i.irq_fast[14]) mfip_id = 4'd14;
else if (irqs_i.irq_fast[13]) mfip_id = 4'd13;
else if (irqs_i.irq_fast[12]) mfip_id = 4'd12;
else if (irqs_i.irq_fast[11]) mfip_id = 4'd11;
else if (irqs_i.irq_fast[10]) mfip_id = 4'd10;
else if (irqs_i.irq_fast[ 9]) mfip_id = 4'd9;
else if (irqs_i.irq_fast[ 8]) mfip_id = 4'd8;
else if (irqs_i.irq_fast[ 7]) mfip_id = 4'd7;
else if (irqs_i.irq_fast[ 6]) mfip_id = 4'd6;
else if (irqs_i.irq_fast[ 5]) mfip_id = 4'd5;
else if (irqs_i.irq_fast[ 5]) mfip_id = 4'd5;
else if (irqs_i.irq_fast[ 4]) mfip_id = 4'd4;
else if (irqs_i.irq_fast[ 3]) mfip_id = 4'd3;
else if (irqs_i.irq_fast[ 2]) mfip_id = 4'd2;
else if (irqs_i.irq_fast[ 1]) mfip_id = 4'd1;
else mfip_id = 4'd0;
end
assign unused_csr_mtip = csr_mtip_i;
assign unused_irq_timer = irqs_i.irq_timer;
/////////////////////
// Core controller //
@ -418,17 +416,17 @@ 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 (csr_mfip_i != 15'b0) begin
end else if (irqs_i.irq_fast != 15'b0) begin
// generate exception cause ID from fast interrupt ID:
// - first bit distinguishes interrupts from exceptions,
// - second bit adds 16 to fast interrupt ID
// for example EXC_CAUSE_IRQ_FAST_0 = {1'b1, 5'd16}
exc_cause_o = exc_cause_e'({2'b11, mfip_id});
end else if (csr_meip_i) begin
end else if (irqs_i.irq_external) begin
exc_cause_o = EXC_CAUSE_IRQ_EXTERNAL_M;
end else if (csr_msip_i) begin
end else if (irqs_i.irq_software) begin
exc_cause_o = EXC_CAUSE_IRQ_SOFTWARE_M;
end else begin // csr_mtip_i
end else begin // irqs_i.irq_timer
exc_cause_o = EXC_CAUSE_IRQ_TIMER_M;
end
end

View file

@ -184,10 +184,7 @@ module ibex_core #(
// Interrupts
logic irq_pending;
logic nmi_mode;
logic csr_msip;
logic csr_mtip;
logic csr_meip;
logic [14:0] csr_mfip;
irqs_t irqs;
logic csr_mstatus_mie;
logic [31:0] csr_mepc, csr_depc;
@ -450,11 +447,8 @@ module ibex_core #(
// Interrupt Signals
.csr_mstatus_mie_i ( csr_mstatus_mie ),
.csr_msip_i ( csr_msip ),
.csr_mtip_i ( csr_mtip ),
.csr_meip_i ( csr_meip ),
.csr_mfip_i ( csr_mfip ),
.irq_pending_i ( irq_pending ),
.irqs_i ( irqs ),
.irq_nm_i ( irq_nm_i ),
.nmi_mode_o ( nmi_mode ),
@ -626,12 +620,9 @@ module ibex_core #(
.irq_timer_i ( irq_timer_i ),
.irq_external_i ( irq_external_i ),
.irq_fast_i ( irq_fast_i ),
.irq_pending_o ( irq_pending ),
.nmi_mode_i ( nmi_mode ),
.csr_msip_o ( csr_msip ),
.csr_mtip_o ( csr_mtip ),
.csr_meip_o ( csr_meip ),
.csr_mfip_o ( csr_mfip ),
.irq_pending_o ( irq_pending ),
.irqs_o ( irqs ),
.csr_mstatus_mie_o ( csr_mstatus_mie ),
.csr_mstatus_tw_o ( csr_mstatus_tw ),
.csr_mepc_o ( csr_mepc ),

View file

@ -52,12 +52,9 @@ module ibex_cs_registers #(
input logic irq_timer_i,
input logic irq_external_i,
input logic [14:0] irq_fast_i,
output logic irq_pending_o, // interupt request pending
input logic nmi_mode_i,
output logic csr_msip_o, // software interrupt pending
output logic csr_mtip_o, // timer interrupt pending
output logic csr_meip_o, // external interrupt pending
output logic [14:0] csr_mfip_o, // fast interrupt pending
output logic irq_pending_o, // interrupt request pending
output ibex_pkg::irqs_t irqs_o, // interrupt requests qualified with mie
output logic csr_mstatus_mie_o,
output logic [31:0] csr_mepc_o,
@ -134,15 +131,6 @@ module ibex_cs_registers #(
priv_lvl_e mpp;
} StatusStk_t;
// struct for mip/mie CSRs
typedef struct packed {
logic irq_software;
logic irq_timer;
logic irq_external;
logic [14:0] irq_fast; // 15 fast interrupts,
// one interrupt is reserved for NMI (not visible through mip/mie)
} Interrupts_t;
typedef struct packed {
x_debug_ver_e xdebugver;
logic [11:0] zero2;
@ -167,13 +155,13 @@ module ibex_cs_registers #(
// CSRs
priv_lvl_e priv_lvl_q, priv_lvl_d;
Status_t mstatus_q, mstatus_d;
Interrupts_t mie_q, mie_d;
irqs_t mie_q, mie_d;
logic [31:0] mscratch_q, mscratch_d;
logic [31:0] mepc_q, mepc_d;
logic [5:0] mcause_q, mcause_d;
logic [31:0] mtval_q, mtval_d;
logic [31:0] mtvec_q, mtvec_d;
Interrupts_t mip;
irqs_t mip;
Dcsr_t dcsr_q, dcsr_d;
logic [31:0] depc_q, depc_d;
logic [31:0] dscratch0_q, dscratch0_d;
@ -242,10 +230,10 @@ module ibex_cs_registers #(
assign illegal_csr_insn_o = csr_access_i & (illegal_csr | illegal_csr_write | illegal_csr_priv);
// mip CSR is purely combinational - must be able to re-enable the clock upon WFI
assign mip.irq_software = irq_software_i & mie_q.irq_software;
assign mip.irq_timer = irq_timer_i & mie_q.irq_timer;
assign mip.irq_external = irq_external_i & mie_q.irq_external;
assign mip.irq_fast = irq_fast_i & mie_q.irq_fast;
assign mip.irq_software = irq_software_i;
assign mip.irq_timer = irq_timer_i;
assign mip.irq_external = irq_external_i;
assign mip.irq_fast = irq_fast_i;
// read logic
always_comb begin
@ -632,11 +620,6 @@ module ibex_cs_registers #(
assign csr_rdata_o = csr_rdata_int;
// directly output some registers
assign csr_msip_o = mip.irq_software;
assign csr_mtip_o = mip.irq_timer;
assign csr_meip_o = mip.irq_external;
assign csr_mfip_o = mip.irq_fast;
assign csr_mepc_o = mepc_q;
assign csr_depc_o = depc_q;
assign csr_mtvec_o = mtvec_q;
@ -647,7 +630,10 @@ module ibex_cs_registers #(
assign debug_ebreakm_o = dcsr_q.ebreakm;
assign debug_ebreaku_o = dcsr_q.ebreaku;
assign irq_pending_o = csr_msip_o | csr_mtip_o | csr_meip_o | (|csr_mfip_o);
// 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;
// actual registers
always_ff @(posedge clk_i or negedge rst_ni) begin

View file

@ -101,11 +101,8 @@ module ibex_id_stage #(
// Interrupt signals
input logic csr_mstatus_mie_i,
input logic csr_msip_i,
input logic csr_mtip_i,
input logic csr_meip_i,
input logic [14:0] csr_mfip_i,
input logic irq_pending_i,
input ibex_pkg::irqs_t irqs_i,
input logic irq_nm_i,
output logic nmi_mode_o,
@ -447,11 +444,8 @@ module ibex_id_stage #(
// interrupt signals
.csr_mstatus_mie_i ( csr_mstatus_mie_i ),
.csr_msip_i ( csr_msip_i ),
.csr_mtip_i ( csr_mtip_i ),
.csr_meip_i ( csr_meip_i ),
.csr_mfip_i ( csr_mfip_i ),
.irq_pending_i ( irq_pending_i ),
.irqs_i ( irqs_i ),
.irq_nm_i ( irq_nm_i ),
.nmi_mode_o ( nmi_mode_o ),

View file

@ -166,6 +166,15 @@ typedef enum logic [1:0] {
EXC_PC_DBG_EXC // Exception while in debug mode
} exc_pc_sel_e;
// Interrupt requests
typedef struct packed {
logic irq_software;
logic irq_timer;
logic irq_external;
logic [14:0] irq_fast; // 15 fast interrupts,
// one interrupt is reserved for NMI (not visible through mip/mie)
} irqs_t;
// Exception cause
typedef enum logic [5:0] {
EXC_CAUSE_IRQ_SOFTWARE_M = {1'b1, 5'd03},