Add test for IRQ force array
This commit is contained in:
parent
f47f603595
commit
a44ff9b6f1
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
*******************************************************************************/
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue