From 719c21fec3015ad5bd19a4daee81f97344d51c05 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Sun, 12 Dec 2021 15:53:04 +0000 Subject: [PATCH] Add IRQ tests. Disable waves by default in runtests --- test/sim/sw_testcases/Makefile | 8 +- test/sim/sw_testcases/Readme.md | 10 +- test/sim/sw_testcases/irq_individual_enable.c | 170 ++++++++++++++++++ test/sim/sw_testcases/irq_individual_pend.c | 169 +++++++++++++++++ test/sim/sw_testcases/irq_set_all.c | 138 ++++++++++++++ test/sim/sw_testcases/runtests | 2 +- 6 files changed, 492 insertions(+), 5 deletions(-) create mode 100644 test/sim/sw_testcases/irq_individual_enable.c create mode 100644 test/sim/sw_testcases/irq_individual_pend.c create mode 100644 test/sim/sw_testcases/irq_set_all.c diff --git a/test/sim/sw_testcases/Makefile b/test/sim/sw_testcases/Makefile index 4c02243..1b793fd 100644 --- a/test/sim/sw_testcases/Makefile +++ b/test/sim/sw_testcases/Makefile @@ -1,5 +1,7 @@ -APP := hellow -SRCS := ../common/init.S $(APP).c -CCFLAGS = -march=rv32imac -Os +APP := hellow +SRCS := ../common/init.S $(APP).c +CCFLAGS := -march=rv32imac -Os +MAX_CYCLES := 1000000 + include ../common/src_only_app.mk diff --git a/test/sim/sw_testcases/Readme.md b/test/sim/sw_testcases/Readme.md index 47ac870..e6d04d8 100644 --- a/test/sim/sw_testcases/Readme.md +++ b/test/sim/sw_testcases/Readme.md @@ -30,7 +30,15 @@ To run the tests: ./runtests ``` -This will first rebuild the simulator (`../tb_cxxrtl/`) if needed, then build and run all the software testcases, then print out a summary of test pass/fail status. The `./run_tests` executable itself returns a successful exit code if and only if all tests passed. A VCD trace and printf log will be created for each test, with the same name as the test, for debugging failures. +This will first rebuild the simulator (`../tb_cxxrtl/`) if needed, then build and run all the software testcases, then print out a summary of test pass/fail status. The `./run_tests` executable itself returns a successful exit code if and only if all tests passed. A printf log will be created for each test, with the same name as the test, at `tmp/test_name.log`. + +VCD waveform dumping is not enabled by default, because tests run faster without waves, and dumping waves for all tests uses > 1 GB of disk space. To re-run a failing test and get wave output, run: + +```bash +make APP=test_name +``` + +This creates a VCD file at `tmp/test_name_run.vcd`. To clean up the junk: diff --git a/test/sim/sw_testcases/irq_individual_enable.c b/test/sim/sw_testcases/irq_individual_enable.c new file mode 100644 index 0000000..5bf22ab --- /dev/null +++ b/test/sim/sw_testcases/irq_individual_enable.c @@ -0,0 +1,170 @@ +#include "tb_cxxrtl_io.h" +#include "hazard3_csr.h" + +// Pend all IRQs, enable them one-by-one and log their firing. + +#define mie_meie 0x800u + +int main() { + asm volatile ("csrsi mstatus, 0x8"); + write_csr(hazard3_csr_meie0, 0u); + write_csr(mie, mie_meie); + + tb_set_irq_masked(-1u); + + for (int i = 31; i >= 0; --i) { + tb_printf("Enabling IRQ %d\n", i); + write_csr(hazard3_csr_meie0, 1u << i); + } + + return 0; +} + +void __attribute__((interrupt)) isr_external_irq() { + tb_puts("-> external irq handler\n"); + tb_assert(read_csr(mcause) == 0x8000000bu, "mcause should indicate external IRQ\n"); + tb_assert(read_csr(mip) == 0x880u, "mip should indicate external + timer IRQ\n"); + + // mlei updates dynamically, should be read exactly once at the start of an + // IRQ handler. + uint32_t mlei = read_csr(hazard3_csr_mlei); + tb_printf("mlei = %u\n", mlei); + tb_printf("meip0 = %08x\n", read_csr(hazard3_csr_meip0)); + + // mlei is scaled by 4 to make it cheaper to index a software vector table. + tb_assert(read_csr(hazard3_csr_meip0) & (1u << (mlei >> 2)), "IRQ indicated by mlei is not pending\n"); + tb_clr_irq_masked(1u << (mlei >> 2)); +} + +/*EXPECTED-OUTPUT*************************************************************** + +Enabling IRQ 31 +-> external irq handler +mlei = 124 +meip0 = ffffffff +Enabling IRQ 30 +-> external irq handler +mlei = 120 +meip0 = 7fffffff +Enabling IRQ 29 +-> external irq handler +mlei = 116 +meip0 = 3fffffff +Enabling IRQ 28 +-> external irq handler +mlei = 112 +meip0 = 1fffffff +Enabling IRQ 27 +-> external irq handler +mlei = 108 +meip0 = 0fffffff +Enabling IRQ 26 +-> external irq handler +mlei = 104 +meip0 = 07ffffff +Enabling IRQ 25 +-> external irq handler +mlei = 100 +meip0 = 03ffffff +Enabling IRQ 24 +-> external irq handler +mlei = 96 +meip0 = 01ffffff +Enabling IRQ 23 +-> external irq handler +mlei = 92 +meip0 = 00ffffff +Enabling IRQ 22 +-> external irq handler +mlei = 88 +meip0 = 007fffff +Enabling IRQ 21 +-> external irq handler +mlei = 84 +meip0 = 003fffff +Enabling IRQ 20 +-> external irq handler +mlei = 80 +meip0 = 001fffff +Enabling IRQ 19 +-> external irq handler +mlei = 76 +meip0 = 000fffff +Enabling IRQ 18 +-> external irq handler +mlei = 72 +meip0 = 0007ffff +Enabling IRQ 17 +-> external irq handler +mlei = 68 +meip0 = 0003ffff +Enabling IRQ 16 +-> external irq handler +mlei = 64 +meip0 = 0001ffff +Enabling IRQ 15 +-> external irq handler +mlei = 60 +meip0 = 0000ffff +Enabling IRQ 14 +-> external irq handler +mlei = 56 +meip0 = 00007fff +Enabling IRQ 13 +-> external irq handler +mlei = 52 +meip0 = 00003fff +Enabling IRQ 12 +-> external irq handler +mlei = 48 +meip0 = 00001fff +Enabling IRQ 11 +-> external irq handler +mlei = 44 +meip0 = 00000fff +Enabling IRQ 10 +-> external irq handler +mlei = 40 +meip0 = 000007ff +Enabling IRQ 9 +-> external irq handler +mlei = 36 +meip0 = 000003ff +Enabling IRQ 8 +-> external irq handler +mlei = 32 +meip0 = 000001ff +Enabling IRQ 7 +-> external irq handler +mlei = 28 +meip0 = 000000ff +Enabling IRQ 6 +-> external irq handler +mlei = 24 +meip0 = 0000007f +Enabling IRQ 5 +-> external irq handler +mlei = 20 +meip0 = 0000003f +Enabling IRQ 4 +-> external irq handler +mlei = 16 +meip0 = 0000001f +Enabling IRQ 3 +-> external irq handler +mlei = 12 +meip0 = 0000000f +Enabling IRQ 2 +-> external irq handler +mlei = 8 +meip0 = 00000007 +Enabling IRQ 1 +-> external irq handler +mlei = 4 +meip0 = 00000003 +Enabling IRQ 0 +-> external irq handler +mlei = 0 +meip0 = 00000001 + +*******************************************************************************/ diff --git a/test/sim/sw_testcases/irq_individual_pend.c b/test/sim/sw_testcases/irq_individual_pend.c new file mode 100644 index 0000000..6d206cb --- /dev/null +++ b/test/sim/sw_testcases/irq_individual_pend.c @@ -0,0 +1,169 @@ +#include "tb_cxxrtl_io.h" +#include "hazard3_csr.h" + +// Set IRQ mask (meie0) wide-open, then pend the IRQs one by one and log their +// firing. + +#define mie_meie 0x800u + +int main() { + asm volatile ("csrsi mstatus, 0x8"); + write_csr(hazard3_csr_meie0, -1u); + write_csr(mie, mie_meie); + + for (int i = 0; i < 32; ++i) { + tb_printf("Setting IRQ %d\n", i); + tb_set_irq_masked(1u << i); + } + + return 0; +} + +void __attribute__((interrupt)) isr_external_irq() { + tb_puts("-> external irq handler\n"); + tb_assert(read_csr(mcause) == 0x8000000bu, "mcause should indicate external IRQ\n"); + tb_assert(read_csr(mip) == 0x880u, "mip should indicate external + timer IRQ\n"); + + // mlei updates dynamically, should be read exactly once at the start of an + // IRQ handler. + uint32_t mlei = read_csr(hazard3_csr_mlei); + tb_printf("mlei = %u\n", mlei); + tb_printf("meip0 = %08x\n", read_csr(hazard3_csr_meip0)); + + // mlei is scaled by 4 to make it cheaper to index a software vector table. + tb_assert(read_csr(hazard3_csr_meip0) & (1u << (mlei >> 2)), "IRQ indicated by mlei is not pending\n"); + tb_clr_irq_masked(1u << (mlei >> 2)); +} + +/*EXPECTED-OUTPUT*************************************************************** + +Setting IRQ 0 +-> external irq handler +mlei = 0 +meip0 = 00000001 +Setting IRQ 1 +-> external irq handler +mlei = 4 +meip0 = 00000002 +Setting IRQ 2 +-> external irq handler +mlei = 8 +meip0 = 00000004 +Setting IRQ 3 +-> external irq handler +mlei = 12 +meip0 = 00000008 +Setting IRQ 4 +-> external irq handler +mlei = 16 +meip0 = 00000010 +Setting IRQ 5 +-> external irq handler +mlei = 20 +meip0 = 00000020 +Setting IRQ 6 +-> external irq handler +mlei = 24 +meip0 = 00000040 +Setting IRQ 7 +-> external irq handler +mlei = 28 +meip0 = 00000080 +Setting IRQ 8 +-> external irq handler +mlei = 32 +meip0 = 00000100 +Setting IRQ 9 +-> external irq handler +mlei = 36 +meip0 = 00000200 +Setting IRQ 10 +-> external irq handler +mlei = 40 +meip0 = 00000400 +Setting IRQ 11 +-> external irq handler +mlei = 44 +meip0 = 00000800 +Setting IRQ 12 +-> external irq handler +mlei = 48 +meip0 = 00001000 +Setting IRQ 13 +-> external irq handler +mlei = 52 +meip0 = 00002000 +Setting IRQ 14 +-> external irq handler +mlei = 56 +meip0 = 00004000 +Setting IRQ 15 +-> external irq handler +mlei = 60 +meip0 = 00008000 +Setting IRQ 16 +-> external irq handler +mlei = 64 +meip0 = 00010000 +Setting IRQ 17 +-> external irq handler +mlei = 68 +meip0 = 00020000 +Setting IRQ 18 +-> external irq handler +mlei = 72 +meip0 = 00040000 +Setting IRQ 19 +-> external irq handler +mlei = 76 +meip0 = 00080000 +Setting IRQ 20 +-> external irq handler +mlei = 80 +meip0 = 00100000 +Setting IRQ 21 +-> external irq handler +mlei = 84 +meip0 = 00200000 +Setting IRQ 22 +-> external irq handler +mlei = 88 +meip0 = 00400000 +Setting IRQ 23 +-> external irq handler +mlei = 92 +meip0 = 00800000 +Setting IRQ 24 +-> external irq handler +mlei = 96 +meip0 = 01000000 +Setting IRQ 25 +-> external irq handler +mlei = 100 +meip0 = 02000000 +Setting IRQ 26 +-> external irq handler +mlei = 104 +meip0 = 04000000 +Setting IRQ 27 +-> external irq handler +mlei = 108 +meip0 = 08000000 +Setting IRQ 28 +-> external irq handler +mlei = 112 +meip0 = 10000000 +Setting IRQ 29 +-> external irq handler +mlei = 116 +meip0 = 20000000 +Setting IRQ 30 +-> external irq handler +mlei = 120 +meip0 = 40000000 +Setting IRQ 31 +-> external irq handler +mlei = 124 +meip0 = 80000000 + +*******************************************************************************/ diff --git a/test/sim/sw_testcases/irq_set_all.c b/test/sim/sw_testcases/irq_set_all.c new file mode 100644 index 0000000..ad954b7 --- /dev/null +++ b/test/sim/sw_testcases/irq_set_all.c @@ -0,0 +1,138 @@ +#include "tb_cxxrtl_io.h" +#include "hazard3_csr.h" + +// Fire all IRQs simultaneously, and log the resulting handler calls + +#define mie_meie 0x800u + +int main() { + asm volatile ("csrsi mstatus, 0x8"); + write_csr(mie, mie_meie); + write_csr(hazard3_csr_meie0, -1u); + + tb_puts("Firing all IRQs\n"); + tb_set_irq_masked(-1u); + tb_puts("Returned OK\n"); + + return 0; +} + +void __attribute__((interrupt)) isr_external_irq() { + tb_puts("-> external irq handler\n"); + tb_assert(read_csr(mcause) == 0x8000000bu, "mcause should indicate external IRQ\n"); + tb_assert(read_csr(mip) == 0x880u, "mip should indicate external + timer IRQ\n"); + + // mlei updates dynamically, should be read exactly once at the start of an + // IRQ handler. + uint32_t mlei = read_csr(hazard3_csr_mlei); + tb_printf("mlei = %u\n", mlei); + tb_printf("meip0 = %08x\n", read_csr(hazard3_csr_meip0)); + + // mlei is scaled by 4 to make it cheaper to index a software vector table. + tb_assert(read_csr(hazard3_csr_meip0) & (1u << (mlei >> 2)), "IRQ indicated by mlei is not pending\n"); + tb_clr_irq_masked(1u << (mlei >> 2)); +} + +/*EXPECTED-OUTPUT*************************************************************** + +Firing all IRQs +-> external irq handler +mlei = 0 +meip0 = ffffffff +-> external irq handler +mlei = 4 +meip0 = fffffffe +-> external irq handler +mlei = 8 +meip0 = fffffffc +-> external irq handler +mlei = 12 +meip0 = fffffff8 +-> external irq handler +mlei = 16 +meip0 = fffffff0 +-> external irq handler +mlei = 20 +meip0 = ffffffe0 +-> external irq handler +mlei = 24 +meip0 = ffffffc0 +-> external irq handler +mlei = 28 +meip0 = ffffff80 +-> external irq handler +mlei = 32 +meip0 = ffffff00 +-> external irq handler +mlei = 36 +meip0 = fffffe00 +-> external irq handler +mlei = 40 +meip0 = fffffc00 +-> external irq handler +mlei = 44 +meip0 = fffff800 +-> external irq handler +mlei = 48 +meip0 = fffff000 +-> external irq handler +mlei = 52 +meip0 = ffffe000 +-> external irq handler +mlei = 56 +meip0 = ffffc000 +-> external irq handler +mlei = 60 +meip0 = ffff8000 +-> external irq handler +mlei = 64 +meip0 = ffff0000 +-> external irq handler +mlei = 68 +meip0 = fffe0000 +-> external irq handler +mlei = 72 +meip0 = fffc0000 +-> external irq handler +mlei = 76 +meip0 = fff80000 +-> external irq handler +mlei = 80 +meip0 = fff00000 +-> external irq handler +mlei = 84 +meip0 = ffe00000 +-> external irq handler +mlei = 88 +meip0 = ffc00000 +-> external irq handler +mlei = 92 +meip0 = ff800000 +-> external irq handler +mlei = 96 +meip0 = ff000000 +-> external irq handler +mlei = 100 +meip0 = fe000000 +-> external irq handler +mlei = 104 +meip0 = fc000000 +-> external irq handler +mlei = 108 +meip0 = f8000000 +-> external irq handler +mlei = 112 +meip0 = f0000000 +-> external irq handler +mlei = 116 +meip0 = e0000000 +-> external irq handler +mlei = 120 +meip0 = c0000000 +-> external irq handler +mlei = 124 +meip0 = 80000000 +Returned OK + + +*******************************************************************************/ diff --git a/test/sim/sw_testcases/runtests b/test/sim/sw_testcases/runtests index 99b9d8a..eab492a 100755 --- a/test/sim/sw_testcases/runtests +++ b/test/sim/sw_testcases/runtests @@ -34,7 +34,7 @@ for test in testlist: continue test_run_ret = subprocess.run( - ["../tb_cxxrtl/tb", "--bin", f"tmp/{test}.bin", "--vcd", f"tmp/{test}_run.vcd", "--cycles", "1000000"], + ["../tb_cxxrtl/tb", "--bin", f"tmp/{test}.bin", "--cycles", "1000000"], stdout = subprocess.PIPE, timeout=10 )