From c1f17b0b23d7e1a52241663bfb53568c89440f2d Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Sat, 6 Nov 2021 09:59:27 +0000 Subject: [PATCH] Add wfi timer loop example, and add mtime/mtimecmp to non-debug testbench --- test/sim/tb_cxxrtl/tb.cpp | 42 +++++++++++++++++++++++++++--- test/sim/wfi_loop/Makefile | 5 ++++ test/sim/wfi_loop/main.c | 53 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 test/sim/wfi_loop/Makefile create mode 100644 test/sim/wfi_loop/main.c diff --git a/test/sim/tb_cxxrtl/tb.cpp b/test/sim/tb_cxxrtl/tb.cpp index f9b9e93..6bc850d 100644 --- a/test/sim/tb_cxxrtl/tb.cpp +++ b/test/sim/tb_cxxrtl/tb.cpp @@ -15,9 +15,13 @@ uint8_t mem[MEM_SIZE]; static const unsigned int IO_BASE = 0x80000000; enum { - IO_PRINT_CHAR = 0, - IO_PRINT_U32 = 4, - IO_EXIT = 8 + IO_PRINT_CHAR = 0x000, + IO_PRINT_U32 = 0x004, + IO_EXIT = 0x008, + IO_MTIME = 0x100, + IO_MTIMEH = 0x104, + IO_MTIMECMP = 0x108, + IO_MTIMECMPH = 0x10c }; const char *help_str = @@ -115,6 +119,9 @@ int main(int argc, char **argv) { top.p_ahblm__hready.set(true); #endif + uint64_t mtime = 0; + uint64_t mtimecmp = 0; + // Reset + initial clock pulse top.step(); top.p_clk.set(true); @@ -132,6 +139,11 @@ int main(int argc, char **argv) { top.p_clk.set(true); top.step(); top.step(); // workaround for github.com/YosysHQ/yosys/issues/2780 + + // Default update logic for mtime, mtimecmp + ++mtime; + top.p_timer__irq.set(mtime >= mtimecmp); + // Handle current data phase, then move current address phase to data phase uint32_t rdata = 0; if (bus_trans && bus_write) { @@ -158,6 +170,18 @@ int main(int argc, char **argv) { printf("Ran for %ld cycles\n", cycle + 1); break; } + else if (bus_addr == IO_BASE + IO_MTIME) { + mtime = (mtime & 0xffffffff00000000u) | wdata; + } + else if (bus_addr == IO_BASE + IO_MTIMEH) { + mtime = (mtime & 0x00000000ffffffffu) | ((uint64_t)wdata << 32); + } + else if (bus_addr == IO_BASE + IO_MTIMECMP) { + mtimecmp = (mtimecmp & 0xffffffff00000000u) | wdata; + } + else if (bus_addr == IO_BASE + IO_MTIMECMPH) { + mtimecmp = (mtimecmp & 0x00000000ffffffffu) | ((uint64_t)wdata << 32); + } } else if (bus_trans && !bus_write) { bus_addr &= ~0x3u; @@ -168,6 +192,18 @@ int main(int argc, char **argv) { mem[bus_addr + 2] << 16 | mem[bus_addr + 3] << 24; } + else if (bus_addr == IO_BASE + IO_MTIME) { + rdata = mtime; + } + else if (bus_addr == IO_BASE + IO_MTIMEH) { + rdata = mtime >> 32; + } + else if (bus_addr == IO_BASE + IO_MTIMECMP) { + rdata = mtimecmp; + } + else if (bus_addr == IO_BASE + IO_MTIMECMPH) { + rdata = mtimecmp >> 32; + } } #ifdef DUAL_PORT top.p_d__hrdata.set(rdata); diff --git a/test/sim/wfi_loop/Makefile b/test/sim/wfi_loop/Makefile new file mode 100644 index 0000000..054b352 --- /dev/null +++ b/test/sim/wfi_loop/Makefile @@ -0,0 +1,5 @@ +SRCS := ../common/init.S main.c +APP := wfi_loop +CCFLAGS = -march=rv32imc -Os + +include ../common/src_only_app.mk diff --git a/test/sim/wfi_loop/main.c b/test/sim/wfi_loop/main.c new file mode 100644 index 0000000..da09184 --- /dev/null +++ b/test/sim/wfi_loop/main.c @@ -0,0 +1,53 @@ +#include "tb_cxxrtl_io.h" + +#define TIMER_INTERVAL 1000 +#define MAX_IRQ_COUNT 10 + +#define __wfi() asm volatile ("wfi") +#define __compiler_mb() asm volatile ("" ::: "memory") + +typedef struct { + volatile uint32_t mtime; + volatile uint32_t mtimeh; + volatile uint32_t mtimecmp; + volatile uint32_t mtimecmph; +} timer_hw; + +timer_hw *const timer = (timer_hw*)(IO_BASE + 0x100); + +int irq_count; +void __attribute__((interrupt)) isr_machine_timer() { + __compiler_mb(); + ++irq_count; + __compiler_mb(); + + tb_printf("IRQ %d\n", irq_count); + + // Disable timer IRQ via MTIE, or set the next timer IRQ + if (irq_count >= MAX_IRQ_COUNT) + asm ("csrc mie, %0" :: "r" (1u << 7)); + else + timer->mtimecmp = timer->mtime + TIMER_INTERVAL; +} + +int main() { + + irq_count = 0; + __compiler_mb(); + // Per-IRQ enable for timer IRQ + asm ("csrs mie, %0" :: "r" (1u << 7)); + tb_puts("Enabling IRQS...\n"); + // Global IRQ enable. Timer IRQ will fire immediately. + asm ("csrsi mstatus, 0x8"); + + // Count the number of sleep loop iterations to make sure the wfi waits + int wait_spin_count; + while (irq_count < MAX_IRQ_COUNT) { + ++wait_spin_count; + __wfi(); + __compiler_mb(); + } + + tb_printf("Took %d IRQs, span %d times\n", irq_count, wait_spin_count); + return irq_count != wait_spin_count + 1; +}