diff --git a/test/sim/common/hazard3_irq.h b/test/sim/common/hazard3_irq.h index 2e0e4f2..c7f0999 100644 --- a/test/sim/common/hazard3_irq.h +++ b/test/sim/common/hazard3_irq.h @@ -5,6 +5,13 @@ #include "stdint.h" #include "stdbool.h" +// Should match processor configuration in testbench: +#define NUM_IRQS 32 + +// Declarations for irq_dispatch.S +extern uintptr_t _external_irq_table[NUM_IRQS]; +extern uint32_t _external_irq_entry_count; + #define h3irq_array_read(csr, index) (read_set_csr(csr, (index)) >> 16) #define h3irq_array_write(csr, index, data) (write_csr(csr, (index) | ((uint32_t)(data) << 16))) @@ -24,8 +31,17 @@ static inline bool h3irq_pending(unsigned int irq) { return h3irq_array_read(hazard3_csr_meipa, irq >> 4) & (1u << (irq & 0xfu)); } -static inline bool h3irq_force_pending(unsigned int irq) { - h3irq_array_set(hazard3_csr_meifa, irq >> 4, 1u << (irq & 0xfu)); +static inline void h3irq_force_pending(unsigned int irq, bool force) { + if (force) { + h3irq_array_set(hazard3_csr_meifa, irq >> 4, 1u << (irq & 0xfu)); + } + else { + h3irq_array_clear(hazard3_csr_meifa, irq >> 4, 1u << (irq & 0xfu)); + } +} + +static inline bool h3irq_is_forced(unsigned int irq) { + return h3irq_array_read(hazard3_csr_meifa, irq >> 4) & (1u << (irq & 0xfu)); } // -1 for no IRQ @@ -44,4 +60,29 @@ static inline void h3irq_set_priority(unsigned int irq, uint32_t priority) { h3irq_array_set(hazard3_csr_meipra, irq >> 2, (priority & 0xfu) << (4 * (irq & 0x3))); } +static inline void h3irq_set_handler(unsigned int irq, void (*handler)(void)) { + _external_irq_table[irq] = (uintptr_t)handler; +} + +static inline void global_irq_enable(bool en) { + // mstatus.mie + if (en) { + set_csr(mstatus, 0x8); + } + else { + clear_csr(mstatus, 0x8); + } +} + +static inline void external_irq_enable(bool en) { + // mie.meie + if (en) { + set_csr(mie, 0x800); + } + else { + clear_csr(mie, 0x800); + } +} + + #endif diff --git a/test/sim/common/irq_dispatch.S b/test/sim/common/irq_dispatch.S index 6347f4a..770cf22 100644 --- a/test/sim/common/irq_dispatch.S +++ b/test/sim/common/irq_dispatch.S @@ -104,7 +104,7 @@ isr_irq\num: .word isr_irq\num .endm -#define NUM_IRQS 64 +#define NUM_IRQS 32 .equ i, 0 .rept NUM_IRQS diff --git a/test/sim/sw_testcases/Makefile b/test/sim/sw_testcases/Makefile index 7119393..1c26d87 100644 --- a/test/sim/sw_testcases/Makefile +++ b/test/sim/sw_testcases/Makefile @@ -4,6 +4,7 @@ CCFLAGS := -march=rv32imac_zicsr -Os MAX_CYCLES := 1000000 INCDIR := include ../common +EXTRA_SRCS_irq_force := ../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 diff --git a/test/sim/sw_testcases/irq_force.c b/test/sim/sw_testcases/irq_force.c new file mode 100644 index 0000000..dea7637 --- /dev/null +++ b/test/sim/sw_testcases/irq_force.c @@ -0,0 +1,101 @@ +#include "tb_cxxrtl_io.h" +#include "hazard3_csr.h" +#include "hazard3_irq.h" + +// Fire all IRQs simultaneously, and log the resulting handler calls + +#define mie_meie 0x800u + +void handler(void); + +int main() { + tb_assert(NUM_IRQS <= 32, "Test invalid for >32 IRQs"); + global_irq_enable(true); + external_irq_enable(true); + // Dry run: Check that IRQ force array can be written/read and that it + // sets the pending array appropriately + for (int i = 0; i < NUM_IRQS; ++i) { + h3irq_force_pending(i, true); + uint32_t expect_pending = i == 31 ? 0xffffffffu : (1u << (i + 1)) - 1; + tb_assert( + expect_pending == ( + h3irq_array_read(hazard3_csr_meifa, 0) | + (h3irq_array_read(hazard3_csr_meifa, 1) << 16) + ), + "Bad meifa readback\n" + ); + tb_assert( + expect_pending == ( + h3irq_array_read(hazard3_csr_meipa, 0) | + (h3irq_array_read(hazard3_csr_meipa, 1) << 16) + ), + "Bad meipa readback\n" + ); + } + for (int i = 0; i < NUM_IRQS; ++i) { + h3irq_force_pending(i, false); + } + tb_assert(h3irq_array_read(hazard3_csr_meifa, 0) == 0, "Failed to clear meifa\n"); + tb_assert(h3irq_array_read(hazard3_csr_meifa, 1) == 0, "Failed to clear meifa\n"); + tb_assert(h3irq_array_read(hazard3_csr_meipa, 0) == 0, "Failed to clear meipa\n"); + tb_assert(h3irq_array_read(hazard3_csr_meipa, 1) == 0, "Failed to clear meipa\n"); + + // Now fire each interrupt for real and make sure that the meinext read + // clears the force bit as it should, so that each interrupt fires + // exactly once. + for (int i = 0; i < NUM_IRQS; ++i) { + h3irq_enable(i, true); + h3irq_set_handler(i, handler); + } + + h3irq_array_write(hazard3_csr_meifa, 0, 0xffffu); + h3irq_array_write(hazard3_csr_meifa, 1, 0xffffu); + + while (h3irq_pending(31)) + ; + tb_printf("EIRQ vector entered %d times\n", _external_irq_entry_count); + + return 0; +} + +void handler(void) { + tb_printf("IRQ %02x\n", h3irq_get_current_irq()); +} + +/*EXPECTED-OUTPUT*************************************************************** + +IRQ 00 +IRQ 01 +IRQ 02 +IRQ 03 +IRQ 04 +IRQ 05 +IRQ 06 +IRQ 07 +IRQ 08 +IRQ 09 +IRQ 0a +IRQ 0b +IRQ 0c +IRQ 0d +IRQ 0e +IRQ 0f +IRQ 10 +IRQ 11 +IRQ 12 +IRQ 13 +IRQ 14 +IRQ 15 +IRQ 16 +IRQ 17 +IRQ 18 +IRQ 19 +IRQ 1a +IRQ 1b +IRQ 1c +IRQ 1d +IRQ 1e +IRQ 1f +EIRQ vector entered 2 times + +*******************************************************************************/ diff --git a/test/sim/sw_testcases/irq_preempt_set_in_irq.c b/test/sim/sw_testcases/irq_preempt_set_in_irq.c index 4482a91..b3bfe99 100644 --- a/test/sim/sw_testcases/irq_preempt_set_in_irq.c +++ b/test/sim/sw_testcases/irq_preempt_set_in_irq.c @@ -41,22 +41,17 @@ EIRQ vector was entered 16 times *******************************************************************************/ #define MAX_PRIORITY 15 -#define NUM_IRQS 64 - -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); + global_irq_enable(true); + external_irq_enable(true); // Enable one external IRQ at each priority level for (int i = 0; i <= MAX_PRIORITY; ++i) { h3irq_enable(i, true); h3irq_set_priority(i, i); - _external_irq_table[i] = (uintptr_t)handler; + h3irq_set_handler(i, 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, diff --git a/test/sim/sw_testcases/irq_set_all_with_pri.c b/test/sim/sw_testcases/irq_set_all_with_pri.c index a59cf9e..0a38c8f 100644 --- a/test/sim/sw_testcases/irq_set_all_with_pri.c +++ b/test/sim/sw_testcases/irq_set_all_with_pri.c @@ -57,20 +57,16 @@ EIRQ vector was entered 1 times #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); + global_irq_enable(true); + external_irq_enable(true); // 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; + h3irq_set_handler(i, 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,