From: Andrew Waterman Date: Thu, 26 Mar 2015 07:28:10 +0000 (-0700) Subject: Serialize counters without throwing C++ exceptions X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=180554d8f20e6ed5d90790579b85535c890ebc68;p=riscv-isa-sim.git Serialize counters without throwing C++ exceptions Ideally, a similar mechanism will apply to target machine exceptions. --- diff --git a/riscv/decode.h b/riscv/decode.h index 4ad4549..72efcd9 100644 --- a/riscv/decode.h +++ b/riscv/decode.h @@ -159,7 +159,11 @@ private: npc = sext_xlen(x); \ } while(0) +#define PC_SERIALIZE 3 /* sentinel value indicating simulator pipeline flush */ + #define validate_csr(which, write) ({ \ + if (!STATE.serialized) return PC_SERIALIZE; \ + STATE.serialized = false; \ unsigned my_priv = get_field(STATE.mstatus, MSTATUS_PRV); \ unsigned csr_priv = get_field((which), 0x300); \ unsigned csr_read_only = get_field((which), 0xC00) == 3; \ diff --git a/riscv/processor.cc b/riscv/processor.cc index 0ff5578..afae1ce 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -21,7 +21,7 @@ processor_t::processor_t(sim_t* _sim, mmu_t* _mmu, uint32_t _id) : sim(_sim), mmu(_mmu), ext(NULL), disassembler(new disassembler_t), - id(_id), run(false), debug(false), serialized(false) + id(_id), run(false), debug(false) { reset(true); mmu->set_processor(this); @@ -86,16 +86,6 @@ void processor_t::reset(bool value) ext->reset(); // reset the extension } -struct serialize_t {}; - -void processor_t::serialize() -{ - if (serialized) - serialized = false; - else - serialized = true, throw serialize_t(); -} - void processor_t::raise_interrupt(reg_t which) { throw trap_t(((reg_t)1 << 63) | which); @@ -183,17 +173,28 @@ void processor_t::step(size_t n) return; n = std::min(n, next_timer(&state) | 1U); + #define maybe_serialize() \ + if (unlikely(pc == PC_SERIALIZE)) { \ + pc = state.pc; \ + state.serialized = true; \ + continue; \ + } + try { take_interrupt(); if (unlikely(debug)) { - while (instret++ < n) + while (instret < n) { insn_fetch_t fetch = mmu->load_insn(pc); - disasm(fetch.insn); - state.pc = pc = execute_insn(this, pc, fetch); + if (!state.serialized) + disasm(fetch.insn); + pc = execute_insn(this, pc, fetch); + maybe_serialize(); + instret++; + state.pc = pc; } } else while (instret < n) @@ -204,22 +205,26 @@ void processor_t::step(size_t n) #define ICACHE_ACCESS(idx) { \ insn_fetch_t fetch = ic_entry->data; \ ic_entry++; \ - state.pc = pc = execute_insn(this, pc, fetch); \ - instret++; \ + pc = execute_insn(this, pc, fetch); \ if (idx == mmu_t::ICACHE_ENTRIES-1) break; \ if (unlikely(ic_entry->tag != pc)) break; \ + instret++; \ + state.pc = pc; \ } switch (idx) { #include "icache.h" } + + maybe_serialize(); + instret++; + state.pc = pc; } } catch(trap_t& t) { state.pc = take_trap(t, pc); } - catch(serialize_t& s) {} update_timer(&state, instret); } @@ -388,7 +393,6 @@ void processor_t::set_csr(int which, reg_t val) case CSR_SEPC: state.sepc = val; break; case CSR_STVEC: state.stvec = val & ~3; break; case CSR_STIMECMP: - serialize(); state.stip = false; state.stimecmp = val; break; @@ -426,7 +430,6 @@ reg_t processor_t::get_csr(int which) case CSR_SCYCLE: case CSR_STIME: case CSR_SINSTRET: - serialize(); return state.scount; case CSR_CYCLEH: case CSR_TIMEH: @@ -436,7 +439,6 @@ reg_t processor_t::get_csr(int which) case CSR_SINSTRETH: if (xlen == 64) break; - serialize(); return state.scount >> 32; case CSR_SSTATUS: { diff --git a/riscv/processor.h b/riscv/processor.h index 4189fea..e9d9c4f 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -55,6 +55,7 @@ struct state_t reg_t fromhost; reg_t scount; bool stip; + bool serialized; // whether timer CSRs are in a well-defined state uint32_t stimecmp; uint32_t fflags; uint32_t frm; @@ -104,7 +105,6 @@ private: bool run; // !reset bool debug; bool histogram_enabled; - bool serialized; std::vector instructions; std::vector opcode_map; @@ -112,7 +112,6 @@ private: std::map pc_histogram; void take_interrupt(); // take a trap if any interrupts are pending - void serialize(); // collapse into defined architectural state reg_t take_trap(trap_t& t, reg_t epc); // take an exception void disasm(insn_t insn); // disassemble and print an instruction