/* * sc_core_adapter.h * * Created on: Jul 5, 2023 * Author: eyck */ #ifndef _SYSC_SC_CORE_ADAPTER_H_ #define _SYSC_SC_CORE_ADAPTER_H_ #include #include #include "core_complex.h" #include #include #include template class sc_core_adapter : public PLAT { public: using reg_t = typename iss::arch::traits::reg_t; using phys_addr_t = typename iss::arch::traits::phys_addr_t; using heart_state_t = typename PLAT::hart_state_type; sc_core_adapter(sysc::tgfs::core_complex *owner) : owner(owner) { } uint32_t get_mode() { return this->reg.PRIV; } inline void set_interrupt_execution(bool v) { this->interrupt_sim = v?1:0; } inline bool get_interrupt_execution() { return this->interrupt_sim; } heart_state_t &get_state() { return this->state; } void notify_phase(iss::arch_if::exec_phase p) override { if (p == iss::arch_if::ISTART) owner->sync(this->instr_if.get_total_cycles()); } iss::sync_type needed_sync() const override { return iss::PRE_SYNC; } void disass_output(uint64_t pc, const std::string instr) override { static constexpr std::array lvl = {{'U', 'S', 'H', 'M'}}; if (!owner->disass_output(pc, instr)) { std::stringstream s; s << "[p:" << lvl[this->reg.PRIV] << ";s:0x" << std::hex << std::setfill('0') << std::setw(sizeof(reg_t) * 2) << (reg_t)this->state.mstatus << std::dec << ";c:" << this->reg.icount + this->cycle_offset << "]"; SCCDEBUG(owner->name())<<"disass: " << "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t" << std::setw(40) << std::setfill(' ') << std::left << instr << s.str(); } }; iss::status read_mem(phys_addr_t addr, unsigned length, uint8_t *const data) override { if (addr.access && iss::access_type::DEBUG) return owner->read_mem_dbg(addr.val, length, data) ? iss::Ok : iss::Err; else { return owner->read_mem(addr.val, length, data, is_fetch(addr.access)) ? iss::Ok : iss::Err; } } iss::status write_mem(phys_addr_t addr, unsigned length, const uint8_t *const data) override { if (addr.access && iss::access_type::DEBUG) return owner->write_mem_dbg(addr.val, length, data) ? iss::Ok : iss::Err; else { auto res = owner->write_mem(addr.val, length, data) ? iss::Ok : iss::Err; // clear MTIP on mtimecmp write if (addr.val == 0x2004000) { reg_t val; this->read_csr(iss::arch::mip, val); if (val & (1ULL << 7)) this->write_csr(iss::arch::mip, val & ~(1ULL << 7)); } return res; } } iss::status read_csr(unsigned addr, reg_t &val) override { #ifndef CWR_SYSTEMC if((addr==iss::arch::time || addr==iss::arch::timeh) && owner->mtime_o.get_interface(0)){ uint64_t time_val; bool ret = owner->mtime_o->nb_peek(time_val); if (addr == iss::arch::time) { val = static_cast(time_val); } else if (addr == iss::arch::timeh) { if (sizeof(reg_t) != 4) return iss::Err; val = static_cast(time_val >> 32); } return ret?Ok:Err; #else if((addr==iss::arch::time || addr==iss::arch::timeh)){ uint64_t time_val = owner->mtime_i.read(); if (addr == iss::arch::time) { val = static_cast(time_val); } else if (addr == iss::arch::timeh) { if (sizeof(reg_t) != 4) return iss::Err; val = static_cast(time_val >> 32); } return iss::Ok; #endif } else { return PLAT::read_csr(addr, val); } } void wait_until(uint64_t flags) override { SCCDEBUG(owner->name()) << "Sleeping until interrupt"; while(this->reg.pending_trap == 0 && (this->csr[iss::arch::mip] & this->csr[iss::arch::mie]) == 0) { sc_core::wait(wfi_evt); } PLAT::wait_until(flags); } void local_irq(short id, bool value) { reg_t mask = 0; switch (id) { case 3: // SW mask = 1 << 3; break; case 7: // timer mask = 1 << 7; break; case 11: // external mask = 1 << 11; break; default: if(id>15) mask = 1 << id; break; } if (value) { this->csr[iss::arch::mip] |= mask; wfi_evt.notify(); } else this->csr[iss::arch::mip] &= ~mask; this->check_interrupt(); if(value) SCCTRACE(owner->name()) << "Triggering interrupt " << id << " Pending trap: " << this->reg.pending_trap; } private: sysc::tgfs::core_complex *const owner; sc_event wfi_evt; }; #endif /* _SYSC_SC_CORE_ADAPTER_H_ */