checkpoint before refactor
This commit is contained in:
parent
f7cec99fa6
commit
dae8acb8a3
|
@ -1 +1 @@
|
||||||
Subproject commit 37b66a36d40c499bfb3348b9a5e077b70445260e
|
Subproject commit 3db52dddcc002f9407d2170f22b8255d93869573
|
|
@ -50,6 +50,7 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <functional>
|
||||||
#include <util/bit_field.h>
|
#include <util/bit_field.h>
|
||||||
#include <util/ities.h>
|
#include <util/ities.h>
|
||||||
#include <util/sparse_array.h>
|
#include <util/sparse_array.h>
|
||||||
|
@ -345,6 +346,14 @@ public:
|
||||||
|
|
||||||
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
|
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
|
||||||
|
|
||||||
|
void setMemReadCb(std::function<iss::status(phys_addr_t, unsigned, uint8_t* const)> const& memReadCb) {
|
||||||
|
mem_read_cb = memReadCb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMemWriteCb(std::function<iss::status(phys_addr_t, unsigned, const uint8_t* const)> const& memWriteCb) {
|
||||||
|
mem_write_cb = memWriteCb;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct riscv_instrumentation_if : public iss::instrumentation_if {
|
struct riscv_instrumentation_if : public iss::instrumentation_if {
|
||||||
|
|
||||||
|
@ -407,6 +416,8 @@ private:
|
||||||
iss::status read_hartid(unsigned addr, reg_t &val);
|
iss::status read_hartid(unsigned addr, reg_t &val);
|
||||||
|
|
||||||
reg_t mhartid_reg{0xF};
|
reg_t mhartid_reg{0xF};
|
||||||
|
std::function<iss::status(phys_addr_t, unsigned, uint8_t *const)>mem_read_cb;
|
||||||
|
std::function<iss::status(phys_addr_t, unsigned, const uint8_t *const)> mem_write_cb;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void check_interrupt();
|
void check_interrupt();
|
||||||
|
@ -653,7 +664,7 @@ iss::status riscv_hart_m_p<BASE>::write(const address_type type, const access_ty
|
||||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_csr(unsigned addr, reg_t &val) {
|
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_csr(unsigned addr, reg_t &val) {
|
||||||
if (addr >= csr.size()) return iss::Err;
|
if (addr >= csr.size()) return iss::Err;
|
||||||
auto req_priv_lvl = (addr >> 8) & 0x3;
|
auto req_priv_lvl = (addr >> 8) & 0x3;
|
||||||
if (this->reg.machine_state < req_priv_lvl) throw illegal_instruction_fault(this->fault_data);
|
if (this->reg.PRIV < req_priv_lvl) throw illegal_instruction_fault(this->fault_data);
|
||||||
auto it = csr_rd_cb.find(addr);
|
auto it = csr_rd_cb.find(addr);
|
||||||
if (it == csr_rd_cb.end()) {
|
if (it == csr_rd_cb.end()) {
|
||||||
val = csr[addr & csr.page_addr_mask];
|
val = csr[addr & csr.page_addr_mask];
|
||||||
|
@ -667,7 +678,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_csr(unsigned add
|
||||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_csr(unsigned addr, reg_t val) {
|
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_csr(unsigned addr, reg_t val) {
|
||||||
if (addr >= csr.size()) return iss::Err;
|
if (addr >= csr.size()) return iss::Err;
|
||||||
auto req_priv_lvl = (addr >> 8) & 0x3;
|
auto req_priv_lvl = (addr >> 8) & 0x3;
|
||||||
if (this->reg.machine_state < req_priv_lvl)
|
if (this->reg.PRIV < req_priv_lvl)
|
||||||
throw illegal_instruction_fault(this->fault_data);
|
throw illegal_instruction_fault(this->fault_data);
|
||||||
if((addr&0xc00)==0xc00)
|
if((addr&0xc00)==0xc00)
|
||||||
throw illegal_instruction_fault(this->fault_data);
|
throw illegal_instruction_fault(this->fault_data);
|
||||||
|
@ -749,6 +760,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_ip(unsigned add
|
||||||
template <typename BASE>
|
template <typename BASE>
|
||||||
iss::status riscv_hart_m_p<BASE>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
|
iss::status riscv_hart_m_p<BASE>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
|
||||||
if ((paddr.val + length) > mem.size()) return iss::Err;
|
if ((paddr.val + length) > mem.size()) return iss::Err;
|
||||||
|
if(mem_read_cb) return mem_read_cb(paddr, length, data);
|
||||||
switch (paddr.val) {
|
switch (paddr.val) {
|
||||||
case 0x0200BFF8: { // CLINT base, mtime reg
|
case 0x0200BFF8: { // CLINT base, mtime reg
|
||||||
if (sizeof(reg_t) < length) return iss::Err;
|
if (sizeof(reg_t) < length) return iss::Err;
|
||||||
|
@ -774,6 +786,7 @@ iss::status riscv_hart_m_p<BASE>::read_mem(phys_addr_t paddr, unsigned length, u
|
||||||
template <typename BASE>
|
template <typename BASE>
|
||||||
iss::status riscv_hart_m_p<BASE>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) {
|
iss::status riscv_hart_m_p<BASE>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) {
|
||||||
if ((paddr.val + length) > mem.size()) return iss::Err;
|
if ((paddr.val + length) > mem.size()) return iss::Err;
|
||||||
|
if(mem_write_cb) return mem_write_cb(paddr, length, data);
|
||||||
switch (paddr.val) {
|
switch (paddr.val) {
|
||||||
case 0x10013000: // UART0 base, TXFIFO reg
|
case 0x10013000: // UART0 base, TXFIFO reg
|
||||||
case 0x10023000: // UART1 base, TXFIFO reg
|
case 0x10023000: // UART1 base, TXFIFO reg
|
||||||
|
@ -861,7 +874,7 @@ template <typename BASE> void riscv_hart_m_p<BASE>::check_interrupt() {
|
||||||
auto ena_irq = csr[mip] & csr[mie];
|
auto ena_irq = csr[mip] & csr[mie];
|
||||||
|
|
||||||
bool mie = state.mstatus.MIE;
|
bool mie = state.mstatus.MIE;
|
||||||
auto m_enabled = this->reg.machine_state < PRIV_M || (this->reg.machine_state == PRIV_M && mie);
|
auto m_enabled = this->reg.PRIV < PRIV_M || (this->reg.PRIV == PRIV_M && mie);
|
||||||
auto enabled_interrupts = m_enabled ? ena_irq & ~ideleg : 0;
|
auto enabled_interrupts = m_enabled ? ena_irq & ~ideleg : 0;
|
||||||
|
|
||||||
if (enabled_interrupts != 0) {
|
if (enabled_interrupts != 0) {
|
||||||
|
@ -906,7 +919,7 @@ template <typename BASE> uint64_t riscv_hart_m_p<BASE>::enter_trap(uint64_t flag
|
||||||
this->reg.NEXT_PC = ivec & ~0x1UL;
|
this->reg.NEXT_PC = ivec & ~0x1UL;
|
||||||
if ((ivec & 0x1) == 1 && trap_id != 0) this->reg.NEXT_PC += 4 * cause;
|
if ((ivec & 0x1) == 1 && trap_id != 0) this->reg.NEXT_PC += 4 * cause;
|
||||||
// reset trap state
|
// reset trap state
|
||||||
this->reg.machine_state = PRIV_M;
|
this->reg.PRIV = PRIV_M;
|
||||||
this->reg.trap_state = 0;
|
this->reg.trap_state = 0;
|
||||||
std::array<char, 32> buffer;
|
std::array<char, 32> buffer;
|
||||||
sprintf(buffer.data(), "0x%016lx", addr);
|
sprintf(buffer.data(), "0x%016lx", addr);
|
||||||
|
@ -918,14 +931,14 @@ template <typename BASE> uint64_t riscv_hart_m_p<BASE>::enter_trap(uint64_t flag
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE> uint64_t riscv_hart_m_p<BASE>::leave_trap(uint64_t flags) {
|
template <typename BASE> uint64_t riscv_hart_m_p<BASE>::leave_trap(uint64_t flags) {
|
||||||
auto cur_priv = this->reg.machine_state;
|
auto cur_priv = this->reg.PRIV;
|
||||||
auto inst_priv = flags & 0x3;
|
auto inst_priv = flags & 0x3;
|
||||||
auto status = state.mstatus;
|
auto status = state.mstatus;
|
||||||
|
|
||||||
// pop the relevant lower-privilege interrupt enable and privilege mode stack
|
// pop the relevant lower-privilege interrupt enable and privilege mode stack
|
||||||
// clear respective yIE
|
// clear respective yIE
|
||||||
if (inst_priv == PRIV_M) {
|
if (inst_priv == PRIV_M) {
|
||||||
this->reg.machine_state = state.mstatus.MPP;
|
this->reg.PRIV = state.mstatus.MPP;
|
||||||
state.mstatus.MPP = 0; // clear mpp to U mode
|
state.mstatus.MPP = 0; // clear mpp to U mode
|
||||||
state.mstatus.MIE = state.mstatus.MPIE;
|
state.mstatus.MIE = state.mstatus.MPIE;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -78,7 +78,8 @@ template <> struct traits<tgf_c> {
|
||||||
{32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,8,32,32,64}};
|
{32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,8,32,32,64}};
|
||||||
|
|
||||||
static constexpr std::array<const uint32_t, 38> reg_byte_offsets{
|
static constexpr std::array<const uint32_t, 38> reg_byte_offsets{
|
||||||
{0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,137,141,145}};
|
{0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,
|
||||||
|
128,132,136,137,141,145}};
|
||||||
|
|
||||||
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
|
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
|
||||||
|
|
||||||
|
@ -222,6 +223,7 @@ struct tgf_c: public arch_if {
|
||||||
inline uint32_t get_last_branch() { return reg.last_branch; }
|
inline uint32_t get_last_branch() { return reg.last_branch; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
#pragma pack(push, 1)
|
||||||
struct TGF_C_regs {
|
struct TGF_C_regs {
|
||||||
uint32_t X0 = 0;
|
uint32_t X0 = 0;
|
||||||
uint32_t X1 = 0;
|
uint32_t X1 = 0;
|
||||||
|
@ -258,10 +260,11 @@ protected:
|
||||||
uint32_t PC = 0;
|
uint32_t PC = 0;
|
||||||
uint32_t NEXT_PC = 0;
|
uint32_t NEXT_PC = 0;
|
||||||
uint8_t PRIV = 0;
|
uint8_t PRIV = 0;
|
||||||
uint32_t trap_state = 0, pending_trap = 0, machine_state = 0, last_branch = 0;
|
uint32_t trap_state = 0, pending_trap = 0;
|
||||||
uint64_t icount = 0;
|
uint64_t icount = 0;
|
||||||
|
uint32_t last_branch;
|
||||||
} reg;
|
} reg;
|
||||||
|
#pragma pack(pop)
|
||||||
std::array<address_type, 4> addr_mode;
|
std::array<address_type, 4> addr_mode;
|
||||||
|
|
||||||
uint64_t interrupt_sim=0;
|
uint64_t interrupt_sim=0;
|
||||||
|
|
|
@ -54,8 +54,8 @@ void tgf_c::reset(uint64_t address) {
|
||||||
for(size_t i=0; i<traits<tgf_c>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<tgf_c>::reg_t),0));
|
for(size_t i=0; i<traits<tgf_c>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<tgf_c>::reg_t),0));
|
||||||
reg.PC=address;
|
reg.PC=address;
|
||||||
reg.NEXT_PC=reg.PC;
|
reg.NEXT_PC=reg.PC;
|
||||||
|
reg.PRIV=0x3;
|
||||||
reg.trap_state=0;
|
reg.trap_state=0;
|
||||||
reg.machine_state=0x3;
|
|
||||||
reg.icount=0;
|
reg.icount=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,7 @@ public:
|
||||||
core_wrapper(core_complex *owner)
|
core_wrapper(core_complex *owner)
|
||||||
: owner(owner) { }
|
: owner(owner) { }
|
||||||
|
|
||||||
uint32_t get_mode() { return this->reg.machine_state; }
|
uint32_t get_mode() { return this->reg.PRIV; }
|
||||||
|
|
||||||
inline void set_interrupt_execution(bool v) { this->interrupt_sim = v?1:0; }
|
inline void set_interrupt_execution(bool v) { this->interrupt_sim = v?1:0; }
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ public:
|
||||||
void disass_output(uint64_t pc, const std::string instr) override {
|
void disass_output(uint64_t pc, const std::string instr) override {
|
||||||
if (INFO <= Log<Output2FILE<disass>>::reporting_level() && Output2FILE<disass>::stream()) {
|
if (INFO <= Log<Output2FILE<disass>>::reporting_level() && Output2FILE<disass>::stream()) {
|
||||||
std::stringstream s;
|
std::stringstream s;
|
||||||
s << "[p:" << lvl[this->reg.machine_state] << ";s:0x" << std::hex << std::setfill('0')
|
s << "[p:" << lvl[this->reg.PRIV] << ";s:0x" << std::hex << std::setfill('0')
|
||||||
<< std::setw(sizeof(reg_t) * 2) << (reg_t)state.mstatus << std::dec << ";c:" << this->reg.icount << "]";
|
<< std::setw(sizeof(reg_t) * 2) << (reg_t)state.mstatus << std::dec << ";c:" << this->reg.icount << "]";
|
||||||
Log<Output2FILE<disass>>().get(INFO, "disass")
|
Log<Output2FILE<disass>>().get(INFO, "disass")
|
||||||
<< "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t" << std::setw(40)
|
<< "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t" << std::setw(40)
|
||||||
|
|
|
@ -914,12 +914,12 @@ private:
|
||||||
writeSpace2(traits::MEM, *(X+rs1) + (int16_t)imm, (int16_t)*(X+rs2));
|
writeSpace2(traits::MEM, *(X+rs1) + (int16_t)imm, (int16_t)*(X+rs2));
|
||||||
// post execution stuff
|
// post execution stuff
|
||||||
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, 16);
|
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, 16);
|
||||||
auto& trap_state = super::template get_reg<uint32_t>(arch::traits<ARCH>::TRAP_STATE);
|
auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]);
|
||||||
// trap check
|
// trap check
|
||||||
if(trap_state!=0){
|
if(*trap_state!=0){
|
||||||
super::core.enter_trap(trap_state, pc.val);
|
super::core.enter_trap(*trap_state, pc.val);
|
||||||
}
|
}
|
||||||
pc.val=super::template get_reg<reg_t>(arch::traits<ARCH>::NEXT_PC);
|
pc.val=*NEXT_PC;
|
||||||
return pc;
|
return pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1610,7 +1610,7 @@ private:
|
||||||
/* generate console output when executing the command */
|
/* generate console output when executing the command */
|
||||||
auto mnemonic = fmt::format(
|
auto mnemonic = fmt::format(
|
||||||
"{mnemonic:10} {pred}, {succ}, {rs1}, {rd}", fmt::arg("mnemonic", "fence"),
|
"{mnemonic:10} {pred}, {succ}, {rs1}, {rd}", fmt::arg("mnemonic", "fence"),
|
||||||
fmt::arg("pred", name(pred)), fmt::arg("succ", name(succ)), fmt::arg("rs1", name(rs1)), fmt::arg("rd", name(rd)));
|
fmt::arg("pred", pred), fmt::arg("succ", succ), fmt::arg("rs1", name(rs1)), fmt::arg("rd", name(rd)));
|
||||||
this->core.disass_output(pc.val, mnemonic);
|
this->core.disass_output(pc.val, mnemonic);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1643,7 +1643,7 @@ private:
|
||||||
/* generate console output when executing the command */
|
/* generate console output when executing the command */
|
||||||
auto mnemonic = fmt::format(
|
auto mnemonic = fmt::format(
|
||||||
"{mnemonic:10} {rs1}, {rd}, {imm}", fmt::arg("mnemonic", "fence_i"),
|
"{mnemonic:10} {rs1}, {rd}, {imm}", fmt::arg("mnemonic", "fence_i"),
|
||||||
fmt::arg("rs1", name(rs1)), fmt::arg("rd", name(rd)), fmt::arg("imm", name(imm)));
|
fmt::arg("rs1", name(rs1)), fmt::arg("rd", name(rd)), fmt::arg("imm", imm));
|
||||||
this->core.disass_output(pc.val, mnemonic);
|
this->core.disass_output(pc.val, mnemonic);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3341,6 +3341,19 @@ private:
|
||||||
pc = pc + ((instr & 3) == 3 ? 4 : 2);
|
pc = pc + ((instr & 3) == 3 ? 4 : 2);
|
||||||
return pc;
|
return pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr typename traits::addr_t upper_bits = ~traits::PGMASK;
|
||||||
|
iss::status fetch_ins(virt_addr_t pc, uint8_t * data){
|
||||||
|
auto phys_pc = this->core.v2p(pc);
|
||||||
|
if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
|
||||||
|
if (this->core.read(phys_pc, 2, data) != iss::Ok) return iss::Err;
|
||||||
|
if ((data[0] & 0x3) == 0x3) // this is a 32bit instruction
|
||||||
|
if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok) return iss::Err;
|
||||||
|
} else {
|
||||||
|
if (this->core.read(phys_pc, 4, data) != iss::Ok) return iss::Err;
|
||||||
|
}
|
||||||
|
return iss::Ok;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
|
template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
|
||||||
|
@ -3367,18 +3380,15 @@ template <typename ARCH>
|
||||||
typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(virt_addr_t start, std::function<bool(void)> pred) {
|
typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(virt_addr_t start, std::function<bool(void)> pred) {
|
||||||
// we fetch at max 4 byte, alignment is 2
|
// we fetch at max 4 byte, alignment is 2
|
||||||
enum {TRAP_ID=1<<16};
|
enum {TRAP_ID=1<<16};
|
||||||
const typename traits::addr_t upper_bits = ~traits::PGMASK;
|
|
||||||
code_word_t insn = 0;
|
code_word_t insn = 0;
|
||||||
auto *const data = (uint8_t *)&insn;
|
auto *const data = (uint8_t *)&insn;
|
||||||
auto pc=start;
|
auto pc=start;
|
||||||
while(pred){
|
while(pred()){
|
||||||
auto paddr = this->core.v2p(pc);
|
auto res = fetch_ins(pc, data);
|
||||||
if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
|
if(res!=iss::Ok){
|
||||||
if (this->core.read(paddr, 2, data) != iss::Ok) throw trap_access(TRAP_ID, pc.val);
|
auto new_pc = super::core.enter_trap(TRAP_ID, pc.val);
|
||||||
if ((insn & 0x3) == 0x3) // this is a 32bit instruction
|
res = fetch_ins(virt_addr_t{access_type::FETCH, new_pc}, data);
|
||||||
if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok) throw trap_access(TRAP_ID, pc.val);
|
if(res!=iss::Ok) throw simulation_stopped(0);
|
||||||
} else {
|
|
||||||
if (this->core.read(paddr, 4, data) != iss::Ok) throw trap_access(TRAP_ID, pc.val);
|
|
||||||
}
|
}
|
||||||
if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
|
if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
|
||||||
auto lut_val = extract_fields(insn);
|
auto lut_val = extract_fields(insn);
|
||||||
|
|
Loading…
Reference in New Issue