- 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;
|
integer i;
|
||||||
for (i = 0; i < W_REQ; i = i + 1) begin
|
for (i = 0; i < W_REQ; i = i + 1) begin
|
||||||
gnt[i] = req[i] && ~|(req & (
|
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
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ module hazard3_onehot_priority_dynamic #(
|
||||||
// Do not modify:
|
// Do not modify:
|
||||||
parameter W_PRIORITY = $clog2(N_PRIORITIES)
|
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,
|
input wire [W_REQ-1:0] req,
|
||||||
output wire [W_REQ-1:0] gnt
|
output wire [W_REQ-1:0] gnt
|
||||||
);
|
);
|
||||||
|
|
@ -32,7 +32,7 @@ always @ (*) begin: stratify
|
||||||
integer i, j;
|
integer i, j;
|
||||||
for (i = 0; i < N_PRIORITIES; i = i + 1) begin
|
for (i = 0; i < N_PRIORITIES; i = i + 1) begin
|
||||||
for (j = 0; j < W_REQ; j = j + 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
|
end
|
||||||
level_has_req[i] = |req_stratified[i];
|
level_has_req[i] = |req_stratified[i];
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -313,7 +313,7 @@ end
|
||||||
localparam MAX_IRQS = 512;
|
localparam MAX_IRQS = 512;
|
||||||
localparam [MAX_IRQS-1:0] IRQ_IMPL_MASK = ~({MAX_IRQS{1'b1}} << NUM_IRQS);
|
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:
|
// Assigned later:
|
||||||
wire [MAX_IRQS-1:0] meipa;
|
wire [MAX_IRQS-1:0] meipa;
|
||||||
|
|
@ -471,9 +471,9 @@ hazard3_onehot_priority_dynamic #(
|
||||||
.PRIORITY_HIGHEST_WINS (1),
|
.PRIORITY_HIGHEST_WINS (1),
|
||||||
.TIEBREAK_HIGHEST_WINS (0)
|
.TIEBREAK_HIGHEST_WINS (0)
|
||||||
) eirq_priority_u (
|
) eirq_priority_u (
|
||||||
.priority (meipra[NUM_IRQS-1:0] & {NUM_IRQS{IRQ_PRIORITY_MASK}}),
|
.pri (meipra[4*NUM_IRQS-1:0] & {NUM_IRQS{IRQ_PRIORITY_MASK}}),
|
||||||
.req (eirq_active_above_ppreempt),
|
.req (eirq_active_above_ppreempt),
|
||||||
.gnt (highest_eirq_onehot)
|
.gnt (highest_eirq_onehot)
|
||||||
);
|
);
|
||||||
|
|
||||||
always @ (*) begin: get_highest_eirq_priority
|
always @ (*) begin: get_highest_eirq_priority
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,14 @@ isr_external_irq:
|
||||||
sw t5, 56(sp)
|
sw t5, 56(sp)
|
||||||
sw t6, 60(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
|
csrr a0, mepc
|
||||||
sw a0, 64(sp)
|
sw a0, 64(sp)
|
||||||
// Make sure to set meicontext.clearts to clear and save mie.msie/mtie
|
// Make sure to set meicontext.clearts to clear and save mie.msie/mtie
|
||||||
|
|
@ -117,3 +125,7 @@ _external_irq_table:
|
||||||
ref_eirq i
|
ref_eirq i
|
||||||
.equ i, i + 1
|
.equ i, i + 1
|
||||||
.endr
|
.endr
|
||||||
|
|
||||||
|
.global _external_irq_entry_count
|
||||||
|
_external_irq_entry_count:
|
||||||
|
.word 0
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,6 @@ MAX_CYCLES := 1000000
|
||||||
INCDIR := include ../common
|
INCDIR := include ../common
|
||||||
|
|
||||||
EXTRA_SRCS_irq_preempt_set_in_irq := ../common/irq_dispatch.S
|
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
|
include ../common/src_only_app.mk
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ Exiting IRQ 3
|
||||||
Exiting IRQ 2
|
Exiting IRQ 2
|
||||||
Exiting IRQ 1
|
Exiting IRQ 1
|
||||||
Exiting IRQ 0
|
Exiting IRQ 0
|
||||||
Done.
|
EIRQ vector was entered 16 times
|
||||||
|
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
|
@ -44,6 +44,7 @@ Done.
|
||||||
#define NUM_IRQS 64
|
#define NUM_IRQS 64
|
||||||
|
|
||||||
extern uintptr_t _external_irq_table[NUM_IRQS];
|
extern uintptr_t _external_irq_table[NUM_IRQS];
|
||||||
|
extern uint32_t _external_irq_entry_count;
|
||||||
|
|
||||||
void handler(void);
|
void handler(void);
|
||||||
|
|
||||||
|
|
@ -64,7 +65,7 @@ int main() {
|
||||||
tb_set_irq_masked(0x1);
|
tb_set_irq_masked(0x1);
|
||||||
asm ("wfi");
|
asm ("wfi");
|
||||||
|
|
||||||
tb_puts("Done.\n");
|
tb_printf("EIRQ vector was entered %d times\n", _external_irq_entry_count);
|
||||||
return 0;
|
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