Allow IRQs to be set/cleared by sw in tb. Add soft IRQ test

This commit is contained in:
Luke Wren 2021-12-12 14:58:50 +00:00
parent a232833d81
commit 9fb2af800f
3 changed files with 131 additions and 7 deletions

View File

@ -4,6 +4,10 @@
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
// ----------------------------------------------------------------------------
// Testbench IO hardware layout
#define IO_BASE 0x80000000
@ -11,6 +15,14 @@ typedef struct {
volatile uint32_t print_char;
volatile uint32_t print_u32;
volatile uint32_t exit;
uint32_t _pad0;
volatile uint32_t set_softirq;
volatile uint32_t clr_softirq;
uint32_t _pad1[2];
volatile uint32_t set_irq;
uint32_t _pad2[3];
volatile uint32_t clr_irq;
uint32_t _pad3[3];
} io_hw_t;
#define mm_io ((io_hw_t *const)IO_BASE)
@ -24,6 +36,8 @@ typedef struct {
#define mm_timer ((timer_hw_t *const)(IO_BASE + 0x100))
// ----------------------------------------------------------------------------
// Testbench IO convenience functions
static inline void tb_putc(char c) {
mm_io->print_char = (uint32_t)c;
@ -57,4 +71,28 @@ static inline void tb_printf(const char *fmt, ...) {
#define tb_assert(cond, ...) if (!(cond)) {tb_printf(__VA_ARGS__); tb_exit(-1);}
static inline void tb_set_softirq() {
mm_io->set_softirq = 1;
}
static inline void tb_clr_softirq() {
mm_io->clr_softirq = 1;
}
static inline bool tb_get_softirq() {
return (bool)mm_io->set_softirq;
}
static inline void tb_set_irq_masked(uint32_t mask) {
mm_io->set_irq = mask;
}
static inline void tb_clr_irq_masked(uint32_t mask) {
mm_io->clr_irq = mask;
}
static inline uint32_t tb_get_irq_mask() {
return mm_io->set_irq;
}
#endif

View File

@ -0,0 +1,64 @@
#include "tb_cxxrtl_io.h"
#include "hazard3_csr.h"
/*EXPECTED-OUTPUT***************************************************************
Dry run
Set mie only
Then set IRQ
-> handle_soft_irq
mip = 00000088 // mtip is also set, because mtimecmp is 0
mie = 00000008 // only msie is set
mcause = 80000003 // MSB indicates IRQ. LSBs are index of mip.
mstatus = 00001880 // MPP = 3. mpie = 1, mie = 0, since we just took an IRQ.
Returned from IRQ
Clear mie, do another dry run
*******************************************************************************/
#define mip_msip 0x8u
#define mie_msie mip_msip
int main() {
tb_assert(!(read_csr(mip) & mip_msip), "mip.msip should be clear at start of test\n");
tb_puts("Dry run\n");
tb_set_softirq();
tb_assert(tb_get_softirq(), "Failed to set soft_irq through tb\n");
tb_assert(read_csr(mip) & mip_msip, "soft_irq not reflected in mip\n");
tb_clr_softirq();
tb_assert(!tb_get_softirq(), "Failed to clear soft_irq through tb\n");
tb_assert(!(read_csr(mip) & mip_msip), "soft_irq clear not reflected in mip\n");
tb_puts("Set mie only\n");
write_csr(mie, mie_msie);
asm volatile ("csrsi mstatus, 0x8");
// IRQ should not fire yet.
tb_puts("Then set IRQ\n");
tb_set_softirq();
tb_assert(!(read_csr(mip) & mip_msip), "soft_irq should have been cleared by IRQ\n");
tb_puts("Returned from IRQ\n");
tb_puts("Clear mie, do another dry run\n");
write_csr(mie, 0);
tb_set_softirq();
tb_assert(tb_get_softirq(), "Failed to set soft_irq through tb\n");
tb_assert(read_csr(mip) & mip_msip, "soft_irq not reflected in mip\n");
tb_clr_softirq();
tb_assert(!tb_get_softirq(), "Failed to clear soft_irq through tb\n");
tb_assert(!(read_csr(mip) & mip_msip), "soft_irq clear not reflected in mip\n");
return 0;
}
void __attribute__((interrupt)) isr_machine_softirq() {
tb_puts("-> handle_soft_irq\n");
tb_printf("mip = %08x\n", read_csr(mip));
tb_printf("mie = %08x\n", read_csr(mie));
tb_clr_softirq();
tb_printf("mcause = %08x\n", read_csr(mcause));
tb_printf("mstatus = %08x\n", read_csr(mstatus));
}

View File

@ -21,6 +21,10 @@ enum {
IO_PRINT_CHAR = 0x000,
IO_PRINT_U32 = 0x004,
IO_EXIT = 0x008,
IO_SET_SOFTIRQ = 0x010,
IO_CLR_SOFTIRQ = 0x014,
IO_SET_IRQ = 0x020,
IO_CLR_IRQ = 0x030,
IO_MTIME = 0x100,
IO_MTIMEH = 0x104,
IO_MTIMECMP = 0x108,
@ -300,6 +304,18 @@ int main(int argc, char **argv) {
printf("Ran for %ld cycles\n", cycle + 1);
break;
}
else if (bus_addr == IO_BASE + IO_SET_SOFTIRQ) {
top.p_soft__irq.set<bool>(true);
}
else if (bus_addr == IO_BASE + IO_CLR_SOFTIRQ) {
top.p_soft__irq.set<bool>(false);
}
else if (bus_addr == IO_BASE + IO_SET_IRQ) {
top.p_irq.set<uint32_t>(top.p_irq.get<uint32_t>() | wdata);
}
else if (bus_addr == IO_BASE + IO_CLR_IRQ) {
top.p_irq.set<uint32_t>(top.p_irq.get<uint32_t>() & ~wdata);
}
else if (bus_addr == IO_BASE + IO_MTIME) {
mtime = (mtime & 0xffffffff00000000u) | wdata;
}
@ -325,6 +341,12 @@ int main(int argc, char **argv) {
mem[bus_addr + 2] << 16 |
mem[bus_addr + 3] << 24;
}
else if (bus_addr == IO_BASE + IO_SET_SOFTIRQ || bus_addr == IO_BASE + IO_CLR_SOFTIRQ) {
rdata = top.p_soft__irq.get<bool>();
}
else if (bus_addr == IO_BASE + IO_SET_IRQ || bus_addr == IO_BASE + IO_CLR_IRQ) {
rdata = top.p_irq.get<uint32_t>();
}
else if (bus_addr == IO_BASE + IO_MTIME) {
rdata = mtime;
}