Browse Source

Use single, shared real-time counter

This required disentangling INSTRET/CYCLE from TIME.
pull/23/head
Andrew Waterman 11 years ago
parent
commit
c1273bcbaf
  1. 73
      riscv/processor.cc
  2. 7
      riscv/processor.h
  3. 6
      riscv/sim.cc
  4. 2
      riscv/sim.h

73
riscv/processor.cc

@ -202,18 +202,13 @@ static reg_t execute_insn(processor_t* p, reg_t pc, insn_fetch_t fetch)
return npc; 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; // this assumes the rtc doesn't change asynchronously during step(),
state->mtime += instret; if (state.stimecmp >= (uint32_t)state.prev_rtc
uint64_t before = count0 - state->stimecmp; && state.stimecmp < (uint32_t)sim->rtc)
if (int64_t(before ^ (before + instret)) < 0) state.mip |= MIP_STIP;
state->mip |= MIP_STIP; state.prev_rtc = sim->rtc;
}
static size_t next_timer(state_t* state)
{
return state->stimecmp - (uint32_t)state->mtime;
} }
void processor_t::step(size_t n) void processor_t::step(size_t n)
@ -224,7 +219,6 @@ void processor_t::step(size_t n)
if (unlikely(!run || !n)) if (unlikely(!run || !n))
return; return;
n = std::min(n, next_timer(&state) | 1U);
#define maybe_serialize() \ #define maybe_serialize() \
if (unlikely(pc == PC_SERIALIZE)) { \ if (unlikely(pc == PC_SERIALIZE)) { \
@ -235,6 +229,7 @@ void processor_t::step(size_t n)
try try
{ {
check_timer();
take_interrupt(); take_interrupt();
if (unlikely(debug)) if (unlikely(debug))
@ -280,7 +275,7 @@ void processor_t::step(size_t n)
take_trap(t, pc); 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 // tail-recurse if we didn't execute as many instructions as we'd hoped
if (instret < n) if (instret < n)
@ -371,29 +366,35 @@ void processor_t::set_csr(int which, reg_t val)
break; break;
case CSR_MTIME: case CSR_MTIME:
case CSR_STIMEW: case CSR_STIMEW:
state.mtime = val; // this implementation ignores writes to MTIME
break; break;
case CSR_MTIMEH: case CSR_MTIMEH:
case CSR_STIMEHW: case CSR_STIMEHW:
// this implementation ignores writes to MTIME
break;
case CSR_TIMEW:
val -= sim->rtc;
if (xlen == 32) if (xlen == 32)
state.mtime = (uint32_t)val | (state.mtime >> 32 << 32); state.sutime_delta = (uint32_t)val | (state.sutime_delta >> 32 << 32);
else 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; break;
case CSR_CYCLEW: case CSR_CYCLEW:
case CSR_TIMEW:
case CSR_INSTRETW: case CSR_INSTRETW:
val -= state.mtime; val -= state.minstret;
if (xlen == 32) 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 else
state.sutime_delta = val; state.suinstret_delta = val;
break; break;
case CSR_CYCLEHW: case CSR_CYCLEHW:
case CSR_TIMEHW:
case CSR_INSTRETHW: case CSR_INSTRETHW:
val -= state.mtime; val = ((val << 32) - state.minstret) >> 32;
state.sutime_delta = (val << 32) | (uint32_t)state.sutime_delta; state.suinstret_delta = (val << 32) | (uint32_t)state.suinstret_delta;
break; break;
case CSR_MSTATUS: { case CSR_MSTATUS: {
if ((val ^ state.mstatus) & (MSTATUS_VM | MSTATUS_PRV | MSTATUS_PRV1 | MSTATUS_MPRV)) if ((val ^ state.mstatus) & (MSTATUS_VM | MSTATUS_PRV | MSTATUS_PRV1 | MSTATUS_MPRV))
@ -496,29 +497,33 @@ reg_t processor_t::get_csr(int which)
break; break;
return (state.fflags << FSR_AEXC_SHIFT) | (state.frm << FSR_RD_SHIFT); return (state.fflags << FSR_AEXC_SHIFT) | (state.frm << FSR_RD_SHIFT);
case CSR_MTIME: case CSR_MTIME:
case CSR_STIME:
case CSR_STIMEW: case CSR_STIMEW:
return state.mtime; return sim->rtc;
case CSR_MTIMEH: case CSR_MTIMEH:
case CSR_STIMEH:
case CSR_STIMEHW: case CSR_STIMEHW:
return state.mtime >> 32; return sim->rtc >> 32;
case CSR_CYCLE:
case CSR_TIME: case CSR_TIME:
case CSR_INSTRET:
case CSR_STIME:
case CSR_CYCLEW:
case CSR_TIMEW: case CSR_TIMEW:
return sim->rtc + state.sutime_delta;
case CSR_CYCLE:
case CSR_CYCLEW:
case CSR_INSTRET:
case CSR_INSTRETW: case CSR_INSTRETW:
return state.mtime + state.sutime_delta; return state.minstret + state.suinstret_delta;
case CSR_CYCLEH:
case CSR_TIMEH: 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_INSTRETH:
case CSR_STIMEH:
case CSR_CYCLEHW: case CSR_CYCLEHW:
case CSR_TIMEHW:
case CSR_INSTRETHW: case CSR_INSTRETHW:
if (xlen == 64) if (xlen == 64)
break; break;
return (state.mtime + state.sutime_delta) >> 32; return (state.minstret + state.suinstret_delta) >> 32;
case CSR_SSTATUS: { case CSR_SSTATUS: {
reg_t ss = 0; reg_t ss = 0;
ss = set_field(ss, SSTATUS_IE, get_field(state.mstatus, MSTATUS_IE)); ss = set_field(ss, SSTATUS_IE, get_field(state.mstatus, MSTATUS_IE));

7
riscv/processor.h

@ -45,7 +45,7 @@ struct state_t
reg_t mbadaddr; reg_t mbadaddr;
reg_t mscratch; reg_t mscratch;
reg_t mcause; reg_t mcause;
reg_t mtime; reg_t minstret;
reg_t mie; reg_t mie;
reg_t mip; reg_t mip;
reg_t sepc; reg_t sepc;
@ -55,12 +55,14 @@ struct state_t
reg_t sptbr; reg_t sptbr;
reg_t scause; reg_t scause;
reg_t sutime_delta; reg_t sutime_delta;
reg_t suinstret_delta;
reg_t tohost; reg_t tohost;
reg_t fromhost; reg_t fromhost;
bool serialized; // whether timer CSRs are in a well-defined state reg_t prev_rtc;
uint32_t stimecmp; uint32_t stimecmp;
uint32_t fflags; uint32_t fflags;
uint32_t frm; uint32_t frm;
bool serialized; // whether timer CSRs are in a well-defined state
reg_t load_reservation; reg_t load_reservation;
@ -118,6 +120,7 @@ private:
std::vector<insn_desc_t> opcode_store; std::vector<insn_desc_t> opcode_store;
std::map<size_t,size_t> pc_histogram; std::map<size_t,size_t> pc_histogram;
void check_timer();
void take_interrupt(); // take a trap if any interrupts are pending void take_interrupt(); // take a trap if any interrupts are pending
void take_trap(trap_t& t, reg_t epc); // take an exception void take_trap(trap_t& t, reg_t epc); // take an exception
void disasm(insn_t insn); // disassemble and print an instruction void disasm(insn_t insn); // disassemble and print an instruction

6
riscv/sim.cc

@ -21,7 +21,7 @@ static void handle_signal(int sig)
sim_t::sim_t(const char* isa, size_t nprocs, size_t mem_mb, sim_t::sim_t(const char* isa, size_t nprocs, size_t mem_mb,
const std::vector<std::string>& args) const std::vector<std::string>& args)
: htif(new htif_isasim_t(this, args)), procs(std::max(nprocs, size_t(1))), : 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); signal(SIGINT, &handle_signal);
// allocate target machine's memory, shrinking it as necessary // allocate target machine's memory, shrinking it as necessary
@ -93,8 +93,10 @@ void sim_t::step(size_t n)
{ {
current_step = 0; current_step = 0;
procs[current_proc]->yield_load_reservation(); procs[current_proc]->yield_load_reservation();
if (++current_proc == procs.size()) if (++current_proc == procs.size()) {
current_proc = 0; current_proc = 0;
rtc += INTERLEAVE / INSNS_PER_RTC_TICK;
}
htif->tick(); htif->tick();
} }

2
riscv/sim.h

@ -47,6 +47,8 @@ private:
void step(size_t n); // step through simulation void step(size_t n); // step through simulation
static const size_t INTERLEAVE = 5000; static const size_t INTERLEAVE = 5000;
static const size_t INSNS_PER_RTC_TICK = 100; // 10 MHz clock for 1 BIPS core
reg_t rtc;
size_t current_step; size_t current_step;
size_t current_proc; size_t current_proc;
bool debug; bool debug;

Loading…
Cancel
Save