return npc;
}
-static void update_timer(state_t* state, size_t instret)
+void processor_t::check_timer()
{
- uint64_t count0 = (uint64_t)(uint32_t)state->mtime;
- state->mtime += instret;
- uint64_t before = count0 - state->stimecmp;
- if (int64_t(before ^ (before + instret)) < 0)
- state->mip |= MIP_STIP;
-}
-
-static size_t next_timer(state_t* state)
-{
- return state->stimecmp - (uint32_t)state->mtime;
+ // this assumes the rtc doesn't change asynchronously during step(),
+ if (state.stimecmp >= (uint32_t)state.prev_rtc
+ && state.stimecmp < (uint32_t)sim->rtc)
+ state.mip |= MIP_STIP;
+ state.prev_rtc = sim->rtc;
}
void processor_t::step(size_t n)
if (unlikely(!run || !n))
return;
- n = std::min(n, next_timer(&state) | 1U);
#define maybe_serialize() \
if (unlikely(pc == PC_SERIALIZE)) { \
try
{
+ check_timer();
take_interrupt();
if (unlikely(debug))
take_trap(t, pc);
}
- update_timer(&state, instret);
+ state.minstret += instret;
// tail-recurse if we didn't execute as many instructions as we'd hoped
if (instret < n)
break;
case CSR_MTIME:
case CSR_STIMEW:
- state.mtime = val;
+ // this implementation ignores writes to MTIME
break;
case CSR_MTIMEH:
case CSR_STIMEHW:
+ // this implementation ignores writes to MTIME
+ break;
+ case CSR_TIMEW:
+ val -= sim->rtc;
if (xlen == 32)
- state.mtime = (uint32_t)val | (state.mtime >> 32 << 32);
+ state.sutime_delta = (uint32_t)val | (state.sutime_delta >> 32 << 32);
else
- state.mtime = val;
+ state.sutime_delta = val;
+ break;
+ case CSR_TIMEHW:
+ val = ((val << 32) - sim->rtc) >> 32;
+ state.sutime_delta = (val << 32) | (uint32_t)state.sutime_delta;
break;
case CSR_CYCLEW:
- case CSR_TIMEW:
case CSR_INSTRETW:
- val -= state.mtime;
+ val -= state.minstret;
if (xlen == 32)
- state.sutime_delta = (uint32_t)val | (state.sutime_delta >> 32 << 32);
+ state.suinstret_delta = (uint32_t)val | (state.suinstret_delta >> 32 << 32);
else
- state.sutime_delta = val;
+ state.suinstret_delta = val;
break;
case CSR_CYCLEHW:
- case CSR_TIMEHW:
case CSR_INSTRETHW:
- val -= state.mtime;
- state.sutime_delta = (val << 32) | (uint32_t)state.sutime_delta;
+ val = ((val << 32) - state.minstret) >> 32;
+ state.suinstret_delta = (val << 32) | (uint32_t)state.suinstret_delta;
break;
case CSR_MSTATUS: {
if ((val ^ state.mstatus) & (MSTATUS_VM | MSTATUS_PRV | MSTATUS_PRV1 | MSTATUS_MPRV))
break;
return (state.fflags << FSR_AEXC_SHIFT) | (state.frm << FSR_RD_SHIFT);
case CSR_MTIME:
+ case CSR_STIME:
case CSR_STIMEW:
- return state.mtime;
+ return sim->rtc;
case CSR_MTIMEH:
+ case CSR_STIMEH:
case CSR_STIMEHW:
- return state.mtime >> 32;
- case CSR_CYCLE:
+ return sim->rtc >> 32;
case CSR_TIME:
- case CSR_INSTRET:
- case CSR_STIME:
- case CSR_CYCLEW:
case CSR_TIMEW:
+ return sim->rtc + state.sutime_delta;
+ case CSR_CYCLE:
+ case CSR_CYCLEW:
+ case CSR_INSTRET:
case CSR_INSTRETW:
- return state.mtime + state.sutime_delta;
- case CSR_CYCLEH:
+ return state.minstret + state.suinstret_delta;
case CSR_TIMEH:
+ case CSR_TIMEHW:
+ if (xlen == 64)
+ break;
+ return (sim->rtc + state.sutime_delta) >> 32;
+ case CSR_CYCLEH:
case CSR_INSTRETH:
- case CSR_STIMEH:
case CSR_CYCLEHW:
- case CSR_TIMEHW:
case CSR_INSTRETHW:
if (xlen == 64)
break;
- return (state.mtime + state.sutime_delta) >> 32;
+ return (state.minstret + state.suinstret_delta) >> 32;
case CSR_SSTATUS: {
reg_t ss = 0;
ss = set_field(ss, SSTATUS_IE, get_field(state.mstatus, MSTATUS_IE));
sim_t::sim_t(const char* isa, size_t nprocs, size_t mem_mb,
const std::vector<std::string>& args)
: htif(new htif_isasim_t(this, args)), procs(std::max(nprocs, size_t(1))),
- current_step(0), current_proc(0), debug(false)
+ rtc(0), current_step(0), current_proc(0), debug(false)
{
signal(SIGINT, &handle_signal);
// allocate target machine's memory, shrinking it as necessary
{
current_step = 0;
procs[current_proc]->yield_load_reservation();
- if (++current_proc == procs.size())
+ if (++current_proc == procs.size()) {
current_proc = 0;
+ rtc += INTERLEAVE / INSNS_PER_RTC_TICK;
+ }
htif->tick();
}