Add test for IRQ force array
This commit is contained in:
parent
f47f603595
commit
a44ff9b6f1
|
@ -5,6 +5,13 @@
|
||||||
#include "stdint.h"
|
#include "stdint.h"
|
||||||
#include "stdbool.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_read(csr, index) (read_set_csr(csr, (index)) >> 16)
|
||||||
|
|
||||||
#define h3irq_array_write(csr, index, data) (write_csr(csr, (index) | ((uint32_t)(data) << 16)))
|
#define h3irq_array_write(csr, index, data) (write_csr(csr, (index) | ((uint32_t)(data) << 16)))
|
||||||
|
@ -24,9 +31,18 @@ static inline bool h3irq_pending(unsigned int irq) {
|
||||||
return h3irq_array_read(hazard3_csr_meipa, irq >> 4) & (1u << (irq & 0xfu));
|
return h3irq_array_read(hazard3_csr_meipa, irq >> 4) & (1u << (irq & 0xfu));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool h3irq_force_pending(unsigned int irq) {
|
static inline void h3irq_force_pending(unsigned int irq, bool force) {
|
||||||
|
if (force) {
|
||||||
h3irq_array_set(hazard3_csr_meifa, irq >> 4, 1u << (irq & 0xfu));
|
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
|
// -1 for no IRQ
|
||||||
static inline int h3irq_get_current_irq() {
|
static inline int h3irq_get_current_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)));
|
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
|
#endif
|
||||||
|
|
|
@ -104,7 +104,7 @@ isr_irq\num:
|
||||||
.word isr_irq\num
|
.word isr_irq\num
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
#define NUM_IRQS 64
|
#define NUM_IRQS 32
|
||||||
|
|
||||||
.equ i, 0
|
.equ i, 0
|
||||||
.rept NUM_IRQS
|
.rept NUM_IRQS
|
||||||
|
|
|
@ -4,6 +4,7 @@ CCFLAGS := -march=rv32imac_zicsr -Os
|
||||||
MAX_CYCLES := 1000000
|
MAX_CYCLES := 1000000
|
||||||
INCDIR := include ../common
|
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_preempt_set_in_irq := ../common/irq_dispatch.S
|
||||||
EXTRA_SRCS_irq_set_all_with_pri := ../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 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);
|
void handler(void);
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// Enable external IRQs globally
|
global_irq_enable(true);
|
||||||
set_csr(mstatus, 0x8);
|
external_irq_enable(true);
|
||||||
set_csr(mie, 0x800);
|
|
||||||
// Enable one external IRQ at each priority level
|
// Enable one external IRQ at each priority level
|
||||||
for (int i = 0; i <= MAX_PRIORITY; ++i) {
|
for (int i = 0; i <= MAX_PRIORITY; ++i) {
|
||||||
h3irq_enable(i, true);
|
h3irq_enable(i, true);
|
||||||
h3irq_set_priority(i, i);
|
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
|
// 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,
|
// 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 PRIORITY_LEVELS 16
|
||||||
#define NUM_IRQS 32
|
#define NUM_IRQS 32
|
||||||
|
|
||||||
extern uintptr_t _external_irq_table[NUM_IRQS];
|
|
||||||
extern uint32_t _external_irq_entry_count;
|
|
||||||
|
|
||||||
void handler(void);
|
void handler(void);
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// Enable external IRQs globally
|
global_irq_enable(true);
|
||||||
set_csr(mstatus, 0x8);
|
external_irq_enable(true);
|
||||||
set_csr(mie, 0x800);
|
|
||||||
// Enable one external IRQ at each priority level
|
// Enable one external IRQ at each priority level
|
||||||
for (int i = 0; i < PRIORITY_LEVELS * 2; ++i) {
|
for (int i = 0; i < PRIORITY_LEVELS * 2; ++i) {
|
||||||
h3irq_enable(i, true);
|
h3irq_enable(i, true);
|
||||||
h3irq_set_priority(i, i / 2);
|
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
|
// 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,
|
// next-lowest, which will preempt it. So on, up to the highest level,
|
||||||
|
|
Loading…
Reference in New Issue