Add test for IRQ force array

This commit is contained in:
Luke Wren 2022-08-09 23:38:14 +01:00
parent f47f603595
commit a44ff9b6f1
6 changed files with 152 additions and 18 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
*******************************************************************************/

View File

@ -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,

View File

@ -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,