Add wfi timer loop example, and add mtime/mtimecmp to non-debug testbench
This commit is contained in:
parent
cc6a6c09ba
commit
c1f17b0b23
|
@ -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<bool>(true);
|
||||
#endif
|
||||
|
||||
uint64_t mtime = 0;
|
||||
uint64_t mtimecmp = 0;
|
||||
|
||||
// Reset + initial clock pulse
|
||||
top.step();
|
||||
top.p_clk.set<bool>(true);
|
||||
|
@ -132,6 +139,11 @@ int main(int argc, char **argv) {
|
|||
top.p_clk.set<bool>(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<bool>(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<uint32_t>(rdata);
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
SRCS := ../common/init.S main.c
|
||||
APP := wfi_loop
|
||||
CCFLAGS = -march=rv32imc -Os
|
||||
|
||||
include ../common/src_only_app.mk
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue