From c27d0de2a0a7b6e7d18fbbed4274c459bf5b68f2 Mon Sep 17 00:00:00 2001 From: Jim Huang Date: Thu, 18 Jan 2024 10:15:30 +0800 Subject: [PATCH] Enforce 64-bit timer manipulation The initial code was overly complex and also exhibited slightly slower performance. --- device.h | 2 +- main.c | 9 ++++----- riscv.c | 5 ++--- riscv.h | 2 +- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/device.h b/device.h index fd7f07b..754065f 100644 --- a/device.h +++ b/device.h @@ -185,5 +185,5 @@ typedef struct { #if SEMU_HAS(VIRTIOBLK) virtio_blk_state_t vblk; #endif - uint32_t timer_lo, timer_hi; + uint64_t timer; } emu_state_t; diff --git a/main.c b/main.c index ced5eb8..c6e2fc0 100644 --- a/main.c +++ b/main.c @@ -162,8 +162,8 @@ static inline sbi_ret_t handle_sbi_ecall_TIMER(vm_t *vm, int32_t fid) emu_state_t *data = (emu_state_t *) vm->priv; switch (fid) { case SBI_TIMER__SET_TIMER: - data->timer_lo = vm->x_regs[RV_R_A0]; - data->timer_hi = vm->x_regs[RV_R_A1]; + data->timer = (((uint64_t) vm->x_regs[RV_R_A1]) << 32) | + (uint64_t) (vm->x_regs[RV_R_A0]); return (sbi_ret_t){SBI_SUCCESS, 0}; default: return (sbi_ret_t){SBI_ERR_NOT_SUPPORTED, 0}; @@ -406,7 +406,7 @@ static int semu_start(int argc, char **argv) atexit(unmap_files); /* Set up RISC-V hart */ - emu.timer_hi = emu.timer_lo = 0xFFFFFFFF; + emu.timer = 0xFFFFFFFFFFFFFFFF; vm.s_mode = true; vm.x_regs[RV_R_A0] = 0; /* hart ID. i.e., cpuid */ vm.x_regs[RV_R_A1] = dtb_addr; @@ -446,8 +446,7 @@ static int semu_start(int argc, char **argv) #endif } - if (vm.insn_count_hi > emu.timer_hi || - (vm.insn_count_hi == emu.timer_hi && vm.insn_count > emu.timer_lo)) + if (vm.insn_count > emu.timer) vm.sip |= RV_INT_STI_BIT; else vm.sip &= ~RV_INT_STI_BIT; diff --git a/riscv.c b/riscv.c index 785b2fc..d36fb22 100644 --- a/riscv.c +++ b/riscv.c @@ -439,7 +439,7 @@ static void csr_read(vm_t *vm, uint16_t addr, uint32_t *value) * and writes should set the value after the increment. However, * we do not expose any way to write the counters. */ - *value = (addr & (1 << 7)) ? vm->insn_count_hi : vm->insn_count; + *value = vm->insn_count >> ((addr & (1 << 7)) ? 32 : 0); } return; } @@ -806,9 +806,8 @@ void vm_step(vm_t *vm) return; vm->pc += 4; + /* Assume no integer overflow */ vm->insn_count++; - if (!vm->insn_count) - vm->insn_count_hi++; uint32_t insn_opcode = insn & MASK(7), value; switch (insn_opcode) { diff --git a/riscv.h b/riscv.h index 04b60b8..d318c31 100644 --- a/riscv.h +++ b/riscv.h @@ -68,7 +68,7 @@ struct __vm_internal { * utilized in these capacities and should not be modified between logical * resets. */ - uint32_t insn_count, insn_count_hi; + uint64_t insn_count; /* Instruction execution state must be set to "NONE" for instruction * execution to continue. If the state is not "NONE," the vm_step()