Skip to content

Commit bcb6f1e

Browse files
committed
Replace mtime counter with realtime timer
1 parent 24f5c80 commit bcb6f1e

File tree

8 files changed

+82
-20
lines changed

8 files changed

+82
-20
lines changed

Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ all: $(BIN) minimal.dtb
4242
OBJS := \
4343
riscv.o \
4444
ram.o \
45+
utils.o \
4546
plic.o \
4647
uart.o \
4748
main.o \

clint.c

+9-6
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55

66
void clint_update_interrupts(hart_t *hart, clint_state_t *clint)
77
{
8-
if (clint->mtime > clint->mtimecmp[hart->mhartid])
8+
uint64_t time_delta =
9+
clint->mtimecmp[hart->mhartid] - semu_timer_gettime(&hart->time);
10+
if ((int32_t) time_delta <= 0)
911
hart->sip |= RV_INT_STI_BIT;
1012
else
1113
hart->sip &= ~RV_INT_STI_BIT;
@@ -31,7 +33,8 @@ static bool clint_reg_read(clint_state_t *clint, uint32_t addr, uint32_t *value)
3133
}
3234

3335
if (addr < 0xBFFF) {
34-
*value = clint->mtime >> (32 & -!!(addr & 0b100));
36+
*value = (uint32_t) (semu_timer_gettime(&clint->mtime) >>
37+
(32 & -!!(addr & 0b100)));
3538
return true;
3639
}
3740
return false;
@@ -58,14 +61,14 @@ static bool clint_reg_write(clint_state_t *clint, uint32_t addr, uint32_t value)
5861
}
5962

6063
if (addr < 0xBFFF) {
61-
int32_t upper = clint->mtime >> 32;
62-
int32_t lowwer = clint->mtime;
64+
int32_t upper = clint->mtime.begin >> 32;
65+
int32_t lower = clint->mtime.begin;
6366
if (addr & 0b100)
6467
upper = value;
6568
else
66-
lowwer = value;
69+
lower = value;
6770

68-
clint->mtime = (uint64_t) upper << 32 | lowwer;
71+
semu_timer_rebase(&clint->mtime, (uint64_t) upper << 32 | lower);
6972
return true;
7073
}
7174
return false;

device.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ uint32_t *virtio_blk_init(virtio_blk_state_t *vblk, char *disk_file);
175175
typedef struct {
176176
uint32_t msip[4096];
177177
uint64_t mtimecmp[4095];
178-
uint64_t mtime;
178+
semu_timer_t mtime;
179179
} clint_state_t;
180180

181181
void clint_update_interrupts(hart_t *vm, clint_state_t *clint);

main.c

+1-9
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,6 @@ static void emu_update_timer_interrupt(hart_t *hart)
8181
clint_update_interrupts(hart, &data->clint);
8282
}
8383

84-
static void emu_update_global_timer(vm_t *vm)
85-
{
86-
emu_state_t *data = PRIV(vm->hart[0]);
87-
data->clint.mtime++;
88-
return;
89-
}
90-
9184
static void mem_load(hart_t *hart,
9285
uint32_t addr,
9386
uint8_t width,
@@ -523,6 +516,7 @@ static int semu_start(int argc, char **argv)
523516
/* Initialize the emulator */
524517
emu_state_t emu;
525518
memset(&emu, 0, sizeof(emu));
519+
semu_timer_init(&emu.clint.mtime, TIMER_FREQUENCY);
526520

527521
/* Set up RAM */
528522
emu.ram = mmap(NULL, RAM_SIZE, PROT_READ | PROT_WRITE,
@@ -591,8 +585,6 @@ static int semu_start(int argc, char **argv)
591585
/* Emulate */
592586
uint32_t peripheral_update_ctr = 0;
593587
while (!emu.stopped) {
594-
emu_update_global_timer(&vm);
595-
596588
for (uint32_t i = 0; i < vm.n_hart; i++) {
597589
if (peripheral_update_ctr-- == 0) {
598590
peripheral_update_ctr = 64;

riscv.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -434,10 +434,10 @@ static void csr_read(hart_t *vm, uint16_t addr, uint32_t *value)
434434
{
435435
switch (addr) {
436436
case RV_CSR_TIME:
437-
*value = vm->time;
437+
*value = semu_timer_gettime(&vm->time);
438438
return;
439439
case RV_CSR_TIMEH:
440-
*value = vm->time >> 32;
440+
*value = semu_timer_gettime(&vm->time) >> 32;
441441
return;
442442
case RV_CSR_INSTRET:
443443
*value = vm->instret;

riscv.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include <stdbool.h>
44
#include <stdint.h>
55

6+
#include "utils.h"
7+
68
/* ERR_EXCEPTION indicates that the instruction has raised one of the
79
* exceptions defined in the specification. If this flag is set, the
810
* additional fields "exc_cause" and "exc_val" must also be set to values
@@ -70,8 +72,7 @@ struct __hart_internal {
7072
* resets.
7173
*/
7274
uint64_t instret;
73-
uint64_t time;
74-
75+
semu_timer_t time;
7576
/* Instruction execution state must be set to "NONE" for instruction
7677
* execution to continue. If the state is not "NONE," the vm_step()
7778
* function will exit.

utils.c

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#include <time.h>
2+
3+
#include "utils.h"
4+
5+
#if defined(__APPLE__)
6+
#define HAVE_MACH_TIMER
7+
#include <mach/mach_time.h>
8+
#elif !defined(_WIN32) && !defined(_WIN64)
9+
#define HAVE_POSIX_TIMER
10+
#ifdef CLOCK_MONOTONIC
11+
#define CLOCKID CLOCK_MONOTONIC
12+
#else
13+
#define CLOCKID CLOCK_REALTIME
14+
#endif
15+
#endif
16+
17+
void semu_timer_init(semu_timer_t *timer, uint64_t freq)
18+
{
19+
timer->freq = freq;
20+
semu_timer_rebase(timer, 0);
21+
}
22+
23+
uint64_t semu_timer_clocksource(uint64_t freq)
24+
{
25+
#if defined(HAVE_POSIX_TIMER)
26+
struct timespec t;
27+
clock_gettime(CLOCKID, &t);
28+
return (t.tv_sec * freq) + (t.tv_nsec * freq / 1e9);
29+
#elif defined(HAVE_MACH_TIMER)
30+
static mach_timebase_info_data_t t;
31+
if (mach_clk.denom == 0)
32+
(void) mach_timebase_info(&t);
33+
return mach_absolute_time() * freq / t.denom * t.numer;
34+
#else
35+
return time(0) * freq;
36+
#endif
37+
}
38+
39+
uint64_t semu_timer_gettime(semu_timer_t *timer)
40+
{
41+
return semu_timer_clocksource(timer->freq) - timer->begin;
42+
}
43+
44+
void semu_timer_rebase(semu_timer_t *timer, uint64_t time)
45+
{
46+
timer->begin = semu_timer_clocksource(timer->freq) - time;
47+
}

utils.h

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#pragma once
2+
3+
#include <stdbool.h>
4+
#include <stdint.h>
5+
6+
7+
#define TIMER_FREQUENCY 65000000
8+
9+
/* TIMER */
10+
typedef struct {
11+
uint64_t begin;
12+
uint64_t freq;
13+
} semu_timer_t;
14+
15+
void semu_timer_init(semu_timer_t *timer, uint64_t freq);
16+
uint64_t semu_timer_clocksource(uint64_t freq);
17+
uint64_t semu_timer_gettime(semu_timer_t *timer);
18+
void semu_timer_rebase(semu_timer_t *timer, uint64_t time);

0 commit comments

Comments
 (0)