- Fix signal named priority, which is a keyword in SV

- Fix incorrect HIGHEST_WINS behaviour in one-hot selector
- Add test for asserting 32 IRQs at 16 priorities at once
- Add an entry counter to the soft dispatch code so tests can check
  the number of times hardware entered the vector
This commit is contained in:
Luke Wren 2022-08-07 23:17:03 +01:00
parent 2e3d69e98f
commit ad5fd24772
7 changed files with 114 additions and 9 deletions

View File

@ -21,7 +21,7 @@ always @ (*) begin: select
integer i;
for (i = 0; i < W_REQ; i = i + 1) begin
gnt[i] = req[i] && ~|(req & (
HIGHEST_WINS ? ~({W_REQ{1'b1}} >> i) : ~({W_REQ{1'b1}} << i)
HIGHEST_WINS ? ~({W_REQ{1'b1}} >> (W_REQ - 1 - i)) : ~({W_REQ{1'b1}} << i)
));
end
end

View File

@ -19,7 +19,7 @@ module hazard3_onehot_priority_dynamic #(
// Do not modify:
parameter W_PRIORITY = $clog2(N_PRIORITIES)
) (
input wire [W_REQ*W_PRIORITY-1:0] priority,
input wire [W_REQ*W_PRIORITY-1:0] pri,
input wire [W_REQ-1:0] req,
output wire [W_REQ-1:0] gnt
);
@ -32,7 +32,7 @@ always @ (*) begin: stratify
integer i, j;
for (i = 0; i < N_PRIORITIES; i = i + 1) begin
for (j = 0; j < W_REQ; j = j + 1) begin
req_stratified[i][j] = req[j] && priority[W_PRIORITY * j +: W_PRIORITY] == i;
req_stratified[i][j] = req[j] && pri[W_PRIORITY * j +: W_PRIORITY] == i;
end
level_has_req[i] = |req_stratified[i];
end

View File

@ -313,7 +313,7 @@ end
localparam MAX_IRQS = 512;
localparam [MAX_IRQS-1:0] IRQ_IMPL_MASK = ~({MAX_IRQS{1'b1}} << NUM_IRQS);
localparam IRQ_PRIORITY_MASK = ~(4'hf >> IRQ_PRIORITY_BITS);
localparam [3:0] IRQ_PRIORITY_MASK = ~(4'hf >> IRQ_PRIORITY_BITS);
// Assigned later:
wire [MAX_IRQS-1:0] meipa;
@ -471,9 +471,9 @@ hazard3_onehot_priority_dynamic #(
.PRIORITY_HIGHEST_WINS (1),
.TIEBREAK_HIGHEST_WINS (0)
) eirq_priority_u (
.priority (meipra[NUM_IRQS-1:0] & {NUM_IRQS{IRQ_PRIORITY_MASK}}),
.req (eirq_active_above_ppreempt),
.gnt (highest_eirq_onehot)
.pri (meipra[4*NUM_IRQS-1:0] & {NUM_IRQS{IRQ_PRIORITY_MASK}}),
.req (eirq_active_above_ppreempt),
.gnt (highest_eirq_onehot)
);
always @ (*) begin: get_highest_eirq_priority

View File

@ -23,6 +23,14 @@ isr_external_irq:
sw t5, 56(sp)
sw t6, 60(sp)
// Update a count of the number of external IRQ vector entries (just for
// use in tests)
la a0, _external_irq_entry_count
lw a1, (a0)
addi a1, a1, 1
sw a1, (a0)
// Make sure to delete the above ^^^ if you use this code for real!
csrr a0, mepc
sw a0, 64(sp)
// Make sure to set meicontext.clearts to clear and save mie.msie/mtie
@ -117,3 +125,7 @@ _external_irq_table:
ref_eirq i
.equ i, i + 1
.endr
.global _external_irq_entry_count
_external_irq_entry_count:
.word 0

View File

@ -5,5 +5,6 @@ MAX_CYCLES := 1000000
INCDIR := include ../common
EXTRA_SRCS_irq_preempt_set_in_irq := ../common/irq_dispatch.S
EXTRA_SRCS_irq_set_all_with_pri := ../common/irq_dispatch.S
include ../common/src_only_app.mk

View File

@ -36,7 +36,7 @@ Exiting IRQ 3
Exiting IRQ 2
Exiting IRQ 1
Exiting IRQ 0
Done.
EIRQ vector was entered 16 times
*******************************************************************************/
@ -44,6 +44,7 @@ Done.
#define NUM_IRQS 64
extern uintptr_t _external_irq_table[NUM_IRQS];
extern uint32_t _external_irq_entry_count;
void handler(void);
@ -64,7 +65,7 @@ int main() {
tb_set_irq_masked(0x1);
asm ("wfi");
tb_puts("Done.\n");
tb_printf("EIRQ vector was entered %d times\n", _external_irq_entry_count);
return 0;
}

View File

@ -0,0 +1,91 @@
#include "tb_cxxrtl_io.h"
#include "hazard3_irq.h"
// Similar to the irq_preempt_set_in_irq test, but there are two IRQs at each
// priority level, and rather than posting the high-priority IRQs from within
// lower priority IRQs, we post every single IRQ at once. Check that:
//
// - The IRQS run from highest to lowest priority order (which happens to be
// opposite to the default tiebreak order for these IRQs)
//
// - Within each priority level, the IRQs are tiebroken lowest-first
//
// - Each IRQ enters and exits before any lower IRQ enters
//
// - The EIRQ vector was entered exactly once (save/restore was shared between
// all the IRQs at their different priority levels)
/*EXPECTED-OUTPUT***************************************************************
Posting IRQs
Entered IRQ 15
Exiting IRQ 15
Entered IRQ 14
Exiting IRQ 14
Entered IRQ 13
Exiting IRQ 13
Entered IRQ 12
Exiting IRQ 12
Entered IRQ 11
Exiting IRQ 11
Entered IRQ 10
Exiting IRQ 10
Entered IRQ 9
Exiting IRQ 9
Entered IRQ 8
Exiting IRQ 8
Entered IRQ 7
Exiting IRQ 7
Entered IRQ 6
Exiting IRQ 6
Entered IRQ 5
Exiting IRQ 5
Entered IRQ 4
Exiting IRQ 4
Entered IRQ 3
Exiting IRQ 3
Entered IRQ 2
Exiting IRQ 2
Entered IRQ 1
Exiting IRQ 1
Entered IRQ 0
Exiting IRQ 0
EIRQ vector was entered 1 times
gstat
*******************************************************************************/
#define PRIORITY_LEVELS 16
#define NUM_IRQS 32
extern uintptr_t _external_irq_table[NUM_IRQS];
extern uint32_t _external_irq_entry_count;
void handler(void);
int main() {
// Enable external IRQs globally
set_csr(mstatus, 0x8);
set_csr(mie, 0x800);
// Enable one external IRQ at each priority level
for (int i = 0; i < PRIORITY_LEVELS * 2; ++i) {
h3irq_enable(i, true);
h3irq_set_priority(i, i / 2);
_external_irq_table[i] = (uintptr_t)handler;
}
// Set off the lowest-priority IRQ. The IRQ handler will then set the
// next-lowest, which will preempt it. So on, up to the highest level,
// then return all the way back down through the nested frames.
tb_puts("Posting IRQs\n");
tb_set_irq_masked(0xffffffffu);
asm ("wfi");
tb_printf("EIRQ vector was entered %d times\n", _external_irq_entry_count);
return 0;
}
void handler(void) {
int irqnum = h3irq_get_current_irq();
tb_printf("Entered IRQ %d\n", irqnum);
tb_clr_irq_masked(1u << irqnum);
tb_printf("Exiting IRQ %d\n", irqnum);
}