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;
|
static const unsigned int IO_BASE = 0x80000000;
|
||||||
enum {
|
enum {
|
||||||
IO_PRINT_CHAR = 0,
|
IO_PRINT_CHAR = 0x000,
|
||||||
IO_PRINT_U32 = 4,
|
IO_PRINT_U32 = 0x004,
|
||||||
IO_EXIT = 8
|
IO_EXIT = 0x008,
|
||||||
|
IO_MTIME = 0x100,
|
||||||
|
IO_MTIMEH = 0x104,
|
||||||
|
IO_MTIMECMP = 0x108,
|
||||||
|
IO_MTIMECMPH = 0x10c
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *help_str =
|
const char *help_str =
|
||||||
|
@ -115,6 +119,9 @@ int main(int argc, char **argv) {
|
||||||
top.p_ahblm__hready.set<bool>(true);
|
top.p_ahblm__hready.set<bool>(true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
uint64_t mtime = 0;
|
||||||
|
uint64_t mtimecmp = 0;
|
||||||
|
|
||||||
// Reset + initial clock pulse
|
// Reset + initial clock pulse
|
||||||
top.step();
|
top.step();
|
||||||
top.p_clk.set<bool>(true);
|
top.p_clk.set<bool>(true);
|
||||||
|
@ -132,6 +139,11 @@ int main(int argc, char **argv) {
|
||||||
top.p_clk.set<bool>(true);
|
top.p_clk.set<bool>(true);
|
||||||
top.step();
|
top.step();
|
||||||
top.step(); // workaround for github.com/YosysHQ/yosys/issues/2780
|
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
|
// Handle current data phase, then move current address phase to data phase
|
||||||
uint32_t rdata = 0;
|
uint32_t rdata = 0;
|
||||||
if (bus_trans && bus_write) {
|
if (bus_trans && bus_write) {
|
||||||
|
@ -158,6 +170,18 @@ int main(int argc, char **argv) {
|
||||||
printf("Ran for %ld cycles\n", cycle + 1);
|
printf("Ran for %ld cycles\n", cycle + 1);
|
||||||
break;
|
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) {
|
else if (bus_trans && !bus_write) {
|
||||||
bus_addr &= ~0x3u;
|
bus_addr &= ~0x3u;
|
||||||
|
@ -168,6 +192,18 @@ int main(int argc, char **argv) {
|
||||||
mem[bus_addr + 2] << 16 |
|
mem[bus_addr + 2] << 16 |
|
||||||
mem[bus_addr + 3] << 24;
|
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
|
#ifdef DUAL_PORT
|
||||||
top.p_d__hrdata.set<uint32_t>(rdata);
|
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