- 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:
parent
2e3d69e98f
commit
ad5fd24772
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue