[rtl,dv,doc] Flip priority of fast interrupts

This matches the priority used in Spike.

This also fixes an issue in the DV where the priority of
external/software/timer interrupts wasn't calculated correctly.
This commit is contained in:
Greg Chadwick 2021-09-17 15:33:55 +01:00 committed by Greg Chadwick
parent ff6797b26f
commit f4e3eefcfb
3 changed files with 38 additions and 24 deletions

View file

@ -50,7 +50,8 @@ To enable interrupts, both the global interrupt enable (MIE) bit in the ``mstatu
For more information, see the :ref:`cs-registers` documentation.
If multiple interrupts are pending, they are handled in the priority order defined by the RISC-V Privileged Specification, version 1.11 (see Machine Interrupt Registers, Section 3.1.9).
The highest priority is given to the interrupt with the highest ID, except for timer interrupts, which have the lowest priority.
The fast interrupts have a platform defined priority.
In Ibex they take priority over all other interrupts and between fast interrupts the highest priority is given to the interrupt with the lowest ID.
The NMI is enabled independent of the values in the ``mstatus`` and ``mie`` CSRs, and it is not visible through the ``mip`` CSR.
It has interrupt ID 31, i.e., it has the highest priority of all interrupts and the core jumps to the trap-handler base address (in ``mtvec``) plus 0x7C to handle the NMI.

View file

@ -202,7 +202,7 @@ class core_ibex_debug_intr_basic_test extends core_ibex_base_test;
irq_txn.irq_timer, 3'b0, irq_txn.irq_software, 3'b0};
`uvm_info(`gfn, $sformatf("irq: 0x%0x", irq), UVM_LOW)
irq_valid = get_max_valid_irq_id(irq);
irq_valid = get_valid_irq_id(irq);
`uvm_info(`gfn, $sformatf("irq_id: 0x%0x", irq_id), UVM_LOW)
return irq_valid;
@ -305,22 +305,43 @@ class core_ibex_debug_intr_basic_test extends core_ibex_base_test;
if (ret_val) send_irq_stimulus_end();
endtask
function int get_max_valid_irq_id(bit [irq_agent_pkg::DATA_WIDTH-1:0] irq);
function int get_valid_irq_id(bit [irq_agent_pkg::DATA_WIDTH-1:0] irq);
int i;
bit have_irq = 1'b0;
// Ibex implementation of MIE does not mask NM interrupts, so need to check this separately
if (irq[irq_agent_pkg::DATA_WIDTH - 1]) begin
irq_id = irq_agent_pkg::DATA_WIDTH - 1;
return 1;
end
for (i = irq_agent_pkg::DATA_WIDTH - 2; i >= 0; i = i - 1) begin
// Ensure that irq is active and unmasked by the core
for (i = irq_agent_pkg::DATA_WIDTH - 2; i >= 16; i = i - 1) begin
// Fast interrupts (IDs 30-16) are prioritised with the lowest ID first, but any fast
// interrupt has priority over other interrupts.
if (irq[i] == 1'b1 && core_init_mie[i] == 1'b1) begin
irq_id = i;
return 1;
break;
have_irq = 1'b1;
end
end
return 0;
if (!have_irq) begin
// If there was no enabled fast interrupt, check the other interrupts
if (irq[11] && core_init_mie[11]) begin
// External interrupt
irq_id = 11;
have_irq = 1'b1;
end else if (irq[3] && core_init_mie[3]) begin
// Software interrupt
irq_id = 3;
have_irq = 1'b1;
end else if (irq[7] && core_init_mie[7]) begin
// Timer interrupt
irq_id = 7;
have_irq = 1'b1;
end
// Other interrupt IDs aren't implemented in Ibex
end
return have_irq;
endfunction
virtual task check_mcause(bit irq_or_exc, bit[ibex_mem_intf_agent_pkg::DATA_WIDTH-2:0] cause);

View file

@ -349,23 +349,15 @@ module ibex_controller #(
assign handle_irq = ~debug_mode_q & ~nmi_mode_q &
(irq_nm_i | (irq_pending_i & csr_mstatus_mie_i));
// generate ID of fast interrupts, highest priority to highest ID
// generate ID of fast interrupts, highest priority to lowest ID
always_comb begin : gen_mfip_id
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[ 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;
mfip_id = 4'd0;
for (int i = 14;i >= 0; i--) begin
if (irqs_i.irq_fast[i]) begin
mfip_id = i[3:0];
end
end
end
assign unused_irq_timer = irqs_i.irq_timer;