diff --git a/test/sim/common/tb_cxxrtl_io.h b/test/sim/common/tb_cxxrtl_io.h index c550ea9..e26c248 100644 --- a/test/sim/common/tb_cxxrtl_io.h +++ b/test/sim/common/tb_cxxrtl_io.h @@ -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 diff --git a/test/sim/sw_testcases/soft_irq.c b/test/sim/sw_testcases/soft_irq.c new file mode 100644 index 0000000..bd1cd16 --- /dev/null +++ b/test/sim/sw_testcases/soft_irq.c @@ -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)); +} diff --git a/test/sim/tb_cxxrtl/tb.cpp b/test/sim/tb_cxxrtl/tb.cpp index a84dd15..83441c4 100644 --- a/test/sim/tb_cxxrtl/tb.cpp +++ b/test/sim/tb_cxxrtl/tb.cpp @@ -18,13 +18,17 @@ uint8_t mem[MEM_SIZE]; static const unsigned int IO_BASE = 0x80000000; enum { - IO_PRINT_CHAR = 0x000, - IO_PRINT_U32 = 0x004, - IO_EXIT = 0x008, - IO_MTIME = 0x100, - IO_MTIMEH = 0x104, - IO_MTIMECMP = 0x108, - IO_MTIMECMPH = 0x10c + 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, + IO_MTIMECMPH = 0x10c }; static const int TCP_BUF_SIZE = 256; @@ -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; }