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 <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include <util/bit_field.h>
|
||||
#include <util/ities.h>
|
||||
#include <util/sparse_array.h>
|
||||
|
@ -344,7 +345,15 @@ public:
|
|||
};
|
||||
|
||||
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:
|
||||
struct riscv_instrumentation_if : public iss::instrumentation_if {
|
||||
|
||||
|
@ -407,6 +416,8 @@ private:
|
|||
iss::status read_hartid(unsigned addr, reg_t &val);
|
||||
|
||||
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:
|
||||
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) {
|
||||
if (addr >= csr.size()) return iss::Err;
|
||||
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);
|
||||
if (it == csr_rd_cb.end()) {
|
||||
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) {
|
||||
if (addr >= csr.size()) return iss::Err;
|
||||
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);
|
||||
if((addr&0xc00)==0xc00)
|
||||
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>
|
||||
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(mem_read_cb) return mem_read_cb(paddr, length, data);
|
||||
switch (paddr.val) {
|
||||
case 0x0200BFF8: { // CLINT base, mtime reg
|
||||
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>
|
||||
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(mem_write_cb) return mem_write_cb(paddr, length, data);
|
||||
switch (paddr.val) {
|
||||
case 0x10013000: // UART0 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];
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
if ((ivec & 0x1) == 1 && trap_id != 0) this->reg.NEXT_PC += 4 * cause;
|
||||
// reset trap state
|
||||
this->reg.machine_state = PRIV_M;
|
||||
this->reg.PRIV = PRIV_M;
|
||||
this->reg.trap_state = 0;
|
||||
std::array<char, 32> buffer;
|
||||
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) {
|
||||
auto cur_priv = this->reg.machine_state;
|
||||
auto cur_priv = this->reg.PRIV;
|
||||
auto inst_priv = flags & 0x3;
|
||||
auto status = state.mstatus;
|
||||
|
||||
// pop the relevant lower-privilege interrupt enable and privilege mode stack
|
||||
// clear respective yIE
|
||||
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.MIE = state.mstatus.MPIE;
|
||||
} 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}};
|
||||
|
||||
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);
|
||||
|
||||
|
@ -222,6 +223,7 @@ struct tgf_c: public arch_if {
|
|||
inline uint32_t get_last_branch() { return reg.last_branch; }
|
||||
|
||||
protected:
|
||||
#pragma pack(push, 1)
|
||||
struct TGF_C_regs {
|
||||
uint32_t X0 = 0;
|
||||
uint32_t X1 = 0;
|
||||
|
@ -258,10 +260,11 @@ protected:
|
|||
uint32_t PC = 0;
|
||||
uint32_t NEXT_PC = 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;
|
||||
uint32_t last_branch;
|
||||
} reg;
|
||||
|
||||
#pragma pack(pop)
|
||||
std::array<address_type, 4> addr_mode;
|
||||
|
||||
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));
|
||||
reg.PC=address;
|
||||
reg.NEXT_PC=reg.PC;
|
||||
reg.PRIV=0x3;
|
||||
reg.trap_state=0;
|
||||
reg.machine_state=0x3;
|
||||
reg.icount=0;
|
||||
}
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ public:
|
|||
core_wrapper(core_complex *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; }
|
||||
|
||||
|
@ -113,7 +113,7 @@ public:
|
|||
void disass_output(uint64_t pc, const std::string instr) override {
|
||||
if (INFO <= Log<Output2FILE<disass>>::reporting_level() && Output2FILE<disass>::stream()) {
|
||||
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 << "]";
|
||||
Log<Output2FILE<disass>>().get(INFO, "disass")
|
||||
<< "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));
|
||||
// post execution stuff
|
||||
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
|
||||
if(trap_state!=0){
|
||||
super::core.enter_trap(trap_state, pc.val);
|
||||
if(*trap_state!=0){
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1610,7 +1610,7 @@ private:
|
|||
/* generate console output when executing the command */
|
||||
auto mnemonic = fmt::format(
|
||||
"{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);
|
||||
|
||||
}
|
||||
|
@ -1643,7 +1643,7 @@ private:
|
|||
/* generate console output when executing the command */
|
||||
auto mnemonic = fmt::format(
|
||||
"{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);
|
||||
|
||||
}
|
||||
|
@ -3341,6 +3341,19 @@ private:
|
|||
pc = pc + ((instr & 3) == 3 ? 4 : 2);
|
||||
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) {
|
||||
|
@ -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) {
|
||||
// we fetch at max 4 byte, alignment is 2
|
||||
enum {TRAP_ID=1<<16};
|
||||
const typename traits::addr_t upper_bits = ~traits::PGMASK;
|
||||
code_word_t insn = 0;
|
||||
auto *const data = (uint8_t *)&insn;
|
||||
auto pc=start;
|
||||
while(pred){
|
||||
auto paddr = this->core.v2p(pc);
|
||||
if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
|
||||
if (this->core.read(paddr, 2, data) != iss::Ok) throw trap_access(TRAP_ID, pc.val);
|
||||
if ((insn & 0x3) == 0x3) // this is a 32bit instruction
|
||||
if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok) throw trap_access(TRAP_ID, pc.val);
|
||||
} else {
|
||||
if (this->core.read(paddr, 4, data) != iss::Ok) throw trap_access(TRAP_ID, pc.val);
|
||||
while(pred()){
|
||||
auto res = fetch_ins(pc, data);
|
||||
if(res!=iss::Ok){
|
||||
auto new_pc = super::core.enter_trap(TRAP_ID, pc.val);
|
||||
res = fetch_ins(virt_addr_t{access_type::FETCH, new_pc}, data);
|
||||
if(res!=iss::Ok) throw simulation_stopped(0);
|
||||
}
|
||||
if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
|
||||
auto lut_val = extract_fields(insn);
|
||||
|
|
Loading…
Reference in New Issue