Skip to content

Commit

Permalink
Replace mtime counter with realtime timer
Browse files Browse the repository at this point in the history
  • Loading branch information
chiangkd committed Jul 14, 2024
1 parent 914d14e commit 779f478
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 20 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ all: $(BIN) minimal.dtb
OBJS := \
riscv.o \
ram.o \
timer.o \
plic.o \
uart.o \
main.o \
Expand Down
15 changes: 9 additions & 6 deletions clint.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

void clint_update_interrupts(hart_t *hart, clint_state_t *clint)
{
if (clint->mtime > clint->mtimecmp[hart->mhartid])
uint64_t time_delta =
clint->mtimecmp[hart->mhartid] - semu_timer_gettime(&hart->time);
if (time_delta & 0x8000000000000000 || time_delta == 0)
hart->sip |= RV_INT_STI_BIT;
else
hart->sip &= ~RV_INT_STI_BIT;
Expand All @@ -31,7 +33,8 @@ static bool clint_reg_read(clint_state_t *clint, uint32_t addr, uint32_t *value)
}

if (addr < 0xBFFF) {
*value = clint->mtime >> (32 & -!!(addr & 0b100));
*value = (uint32_t) (semu_timer_gettime(&clint->mtime) >>
(32 & -!!(addr & 0b100)));
return true;
}
return false;
Expand All @@ -58,14 +61,14 @@ static bool clint_reg_write(clint_state_t *clint, uint32_t addr, uint32_t value)
}

if (addr < 0xBFFF) {
int32_t upper = clint->mtime >> 32;
int32_t lowwer = clint->mtime;
int32_t upper = clint->mtime.begin >> 32;
int32_t lower = clint->mtime.begin;
if (addr & 0b100)
upper = value;
else
lowwer = value;
lower = value;

clint->mtime = (uint64_t) upper << 32 | lowwer;
semu_timer_rebase(&clint->mtime, (uint64_t) upper << 32 | lower);
return true;
}
return false;
Expand Down
2 changes: 1 addition & 1 deletion device.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ uint32_t *virtio_blk_init(virtio_blk_state_t *vblk, char *disk_file);
typedef struct {
uint32_t msip[4096];
uint64_t mtimecmp[4095];
uint64_t mtime;
semu_timer_t mtime;
} clint_state_t;

void clint_update_interrupts(hart_t *vm, clint_state_t *clint);
Expand Down
10 changes: 1 addition & 9 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,6 @@ static void emu_update_timer_interrupt(hart_t *hart)
clint_update_interrupts(hart, &data->clint);
}

static void emu_update_global_timer(vm_t *vm)
{
emu_state_t *data = PRIV(vm->hart[0]);
data->clint.mtime++;
return;
}

static void mem_load(hart_t *hart,
uint32_t addr,
uint8_t width,
Expand Down Expand Up @@ -523,6 +516,7 @@ static int semu_start(int argc, char **argv)
/* Initialize the emulator */
emu_state_t emu;
memset(&emu, 0, sizeof(emu));
semu_timer_init(&emu.clint.mtime, 65000000);

/* Set up RAM */
emu.ram = mmap(NULL, RAM_SIZE, PROT_READ | PROT_WRITE,
Expand Down Expand Up @@ -590,8 +584,6 @@ static int semu_start(int argc, char **argv)
/* Emulate */
uint32_t peripheral_update_ctr = 0;
while (!emu.stopped) {
emu_update_global_timer(&vm);

for (uint32_t i = 0; i < vm.n_hart; i++) {
if (peripheral_update_ctr-- == 0) {
peripheral_update_ctr = 64;
Expand Down
4 changes: 2 additions & 2 deletions riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -434,10 +434,10 @@ static void csr_read(hart_t *vm, uint16_t addr, uint32_t *value)
{
switch (addr) {
case RV_CSR_TIME:
*value = vm->time;
*value = semu_timer_gettime(&vm->time);
return;
case RV_CSR_TIMEH:
*value = vm->time >> 32;
*value = semu_timer_gettime(&vm->time) >> 32;
return;
case RV_CSR_INSTRET:
*value = vm->instret;
Expand Down
5 changes: 3 additions & 2 deletions riscv.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include <stdbool.h>
#include <stdint.h>

#include "timer.h"

/* ERR_EXCEPTION indicates that the instruction has raised one of the
* exceptions defined in the specification. If this flag is set, the
* additional fields "exc_cause" and "exc_val" must also be set to values
Expand Down Expand Up @@ -70,8 +72,7 @@ struct __hart_internal {
* resets.
*/
uint64_t instret;
uint64_t time;

semu_timer_t time;
/* Instruction execution state must be set to "NONE" for instruction
* execution to continue. If the state is not "NONE," the vm_step()
* function will exit.
Expand Down
47 changes: 47 additions & 0 deletions timer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include <time.h>

#include "riscv.h"

#if defined(__APPLE__)
#define HAVE_MACH_TIMER
#include <mach/mach_time.h>
#elif !defined(_WIN32) && !defined(_WIN64)
#define HAVE_POSIX_TIMER
#ifdef CLOCK_MONOTONIC
#define CLOCKID CLOCK_MONOTONIC
#else
#define CLOCKID CLOCK_REALTIME
#endif
#endif

void semu_timer_init(semu_timer_t *timer, uint64_t freq)
{
timer->freq = freq;
semu_timer_rebase(timer, 0);
}

uint64_t semu_timer_clocksource(uint64_t freq)
{
#if defined(HAVE_POSIX_TIMER)
struct timespec t;
clock_gettime(CLOCKID, &t);
return (t.tv_sec * freq) + (t.tv_nsec * freq / 1e9);
#elif defined(HAVE_MACH_TIMER)
static mach_timebase_info_data_t t;
if (mach_clk.denom == 0)
(void) mach_timebase_info(&t);
return mach_absolute_time() * freq / t.denom * t.numer;
#else
return time(0) * freq;
#endif
}

uint64_t semu_timer_gettime(semu_timer_t *timer)
{
return semu_timer_clocksource(timer->freq) - timer->begin;
}

void semu_timer_rebase(semu_timer_t *timer, uint64_t time)
{
timer->begin = semu_timer_clocksource(timer->freq) - time;
}
16 changes: 16 additions & 0 deletions timer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include <stdbool.h>
#include <stdint.h>


/* TIMER */
typedef struct {
uint64_t begin;
uint64_t freq;
} semu_timer_t;

void semu_timer_init(semu_timer_t *timer, uint64_t freq);
uint64_t semu_timer_clocksource(uint64_t freq);
uint64_t semu_timer_gettime(semu_timer_t *timer);
void semu_timer_rebase(semu_timer_t *timer, uint64_t time);

0 comments on commit 779f478

Please sign in to comment.