URL
https://opencores.org/ocsvn/riscv_vhdl/riscv_vhdl/trunk
Subversion Repositories riscv_vhdl
[/] [riscv_vhdl/] [trunk/] [debugger/] [src/] [cpu_fnc_plugin/] [cpu_riscv_func.cpp] - Rev 4
Compare with Previous | Blame | View Log
/** * @file * @copyright Copyright 2016 GNSS Sensor Ltd. All right reserved. * @author Sergey Khabarov - sergeykhbr@gmail.com * @brief CPU functional simulator class definition. */ #include <api_core.h> #include "cpu_riscv_func.h" namespace debugger { CpuRiver_Functional::CpuRiver_Functional(const char *name) : CpuGeneric(name), portRegs_(this, "regs", DSUREG(ureg.v.iregs), Reg_Total), portSavedRegs_(this, "savedregs", 0, Reg_Total), // not mapped !!! portCSR_(this, "csr", DSUREG(csr), 1<<12) { registerInterface(static_cast<ICpuRiscV *>(this)); registerAttribute("ListExtISA", &listExtISA_); registerAttribute("VendorID", &vendorID_); registerAttribute("VectorTable", &vectorTable_); } CpuRiver_Functional::~CpuRiver_Functional() { } void CpuRiver_Functional::postinitService() { // Supported instruction sets: for (int i = 0; i < INSTR_HASH_TABLE_SIZE; i++) { listInstr_[i].make_list(0); } addIsaUserRV64I(); addIsaPrivilegedRV64I(); for (unsigned i = 0; i < listExtISA_.size(); i++) { if (listExtISA_[i].to_string()[0] == 'A') { addIsaExtensionA(); } else if (listExtISA_[i].to_string()[0] == 'C') { addIsaExtensionC(); } else if (listExtISA_[i].to_string()[0] == 'F') { addIsaExtensionF(); } else if (listExtISA_[i].to_string()[0] == 'M') { addIsaExtensionM(); } } // Power-on reset(false); CpuGeneric::postinitService(); } unsigned CpuRiver_Functional::addSupportedInstruction( RiscvInstruction *instr) { AttributeType tmp(instr); listInstr_[instr->hash()].add_to_list(&tmp); return 0; } void CpuRiver_Functional::handleTrap() { csr_mstatus_type mstatus; csr_mcause_type mcause; if (interrupt_pending_ == 0) { return; } mstatus.value = portCSR_.read(CSR_mstatus).val; mcause.value = portCSR_.read(CSR_mcause).val; uint64_t exception_mask = (1ull << INTERRUPT_USoftware) - 1; if ((interrupt_pending_ & exception_mask) == 0 && mstatus.bits.MIE == 0 && cur_prv_level == PRV_M) { return; } if (mcause.value == EXCEPTION_Breakpoint) { DsuMapType::udbg_type::debug_region_type::breakpoint_control_reg t1; t1.val = br_control_.getValue().val; if (t1.bits.trap_on_break == 0) { sw_breakpoint_ = true; interrupt_pending_ &= ~(1ull << EXCEPTION_Breakpoint); npc_.setValue(pc_.getValue()); halt("EBREAK Breakpoint"); return; } } // All traps handle via machine mode while CSR mdelegate // doesn't setup other. // @todo delegating mstatus.bits.MPP = cur_prv_level; mstatus.bits.MPIE = (mstatus.value >> cur_prv_level) & 0x1; mstatus.bits.MIE = 0; cur_prv_level = PRV_M; portCSR_.write(CSR_mstatus, mstatus.value); int xepc = static_cast<int>((cur_prv_level << 8) + 0x41); if (interrupt_pending_ & exception_mask) { // Exception portCSR_.write(xepc, pc_.getValue().val); } else { // Software interrupt handled after instruction was executed portCSR_.write(xepc, npc_.getValue().val); } npc_.setValue(portCSR_.read(CSR_mtvec)); interrupt_pending_ = 0; } void CpuRiver_Functional::reset(bool active) { CpuGeneric::reset(active); portRegs_.reset(); portCSR_.reset(); portCSR_.write(CSR_mvendorid, vendorID_.to_uint64()); portCSR_.write(CSR_mtvec, vectorTable_.to_uint64()); cur_prv_level = PRV_M; // Current privilege level } GenericInstruction *CpuRiver_Functional::decodeInstruction(Reg64Type *cache) { RiscvInstruction *instr = NULL; int hash_idx = hash32(cacheline_[0].buf32[0]); for (unsigned i = 0; i < listInstr_[hash_idx].size(); i++) { instr = static_cast<RiscvInstruction *>( listInstr_[hash_idx][i].to_iface()); if (instr->parse(cacheline_[0].buf32)) { break; } instr = NULL; } // Check compressed instructions: if (instr == NULL) { hash_idx = hash16(cacheline_[0].buf16[0]); for (unsigned i = 0; i < listInstr_[hash_idx].size(); i++) { instr = static_cast<RiscvInstruction *>( listInstr_[hash_idx][i].to_iface()); if (instr->parse(cacheline_[0].buf32)) { break; } instr = NULL; } } return instr; } void CpuRiver_Functional::generateIllegalOpcode() { raiseSignal(EXCEPTION_InstrIllegal); RISCV_error("Illegal instruction at 0x%08" RV_PRI64 "x", getPC()); } void CpuRiver_Functional::trackContextStart() { if (reg_trace_file == 0) { return; } /** Save previous reg values to find modification after exec() */ uint64_t *dst = portSavedRegs_.getpR64(); uint64_t *src = portRegs_.getpR64(); memcpy(dst, src, Reg_Total*sizeof(uint64_t)); } void CpuRiver_Functional::trackContextEnd() { if (reg_trace_file == 0) { return; } int sz; char tstr[1024]; sz = RISCV_sprintf(tstr, sizeof(tstr),"%8I64d [%08x]: ", step_cnt_, pc_.getValue().buf32[0]); bool reg_changed = false; uint64_t *prev = portSavedRegs_.getpR64(); uint64_t *cur = portRegs_.getpR64(); for (int i = 0; i < Reg_Total; i++) { if (prev[i] != cur[i]) { reg_changed = true; sz += RISCV_sprintf(&tstr[sz], sizeof(tstr) - sz, "%3s <= %016I64x", IREGS_NAMES[i], cur[i]);//, instr_->name()); } } if (instr_ && !reg_changed) { sz += RISCV_sprintf(&tstr[sz], sizeof(tstr) - sz, "-", NULL); } (*reg_trace_file) << tstr << "\n"; reg_trace_file->flush(); } void CpuRiver_Functional::raiseSignal(int idx) { if (idx < INTERRUPT_USoftware) { // Exception: csr_mcause_type cause; cause.value = 0; cause.bits.irq = 0; cause.bits.code = idx; portCSR_.write(CSR_mcause, cause.value); interrupt_pending_ |= 1LL << idx; } else if (idx < SIGNAL_HardReset) { csr_mcause_type cause; cause.value = 0; cause.bits.irq = 1; cause.bits.code = idx - INTERRUPT_USoftware; portCSR_.write(CSR_mcause, cause.value); interrupt_pending_ |= 1LL << idx; } else if (idx == SIGNAL_HardReset) { } else { RISCV_error("Raise unsupported signal %d", idx); } } void CpuRiver_Functional::lowerSignal(int idx) { if (idx == SIGNAL_HardReset) { } else if (idx < SIGNAL_HardReset) { interrupt_pending_ &= ~(1 << idx); } else { RISCV_error("Lower unsupported signal %d", idx); } } uint64_t CpuRiver_Functional::readCSR(int idx) { if (idx == CSR_mtime) { return step_cnt_; } return portCSR_.read(idx).val; } void CpuRiver_Functional::writeCSR(int idx, uint64_t val) { switch (idx) { // Read-Only registers case CSR_misa: case CSR_mvendorid: case CSR_marchid: case CSR_mimplementationid: case CSR_mhartid: break; case CSR_mtime: break; default: portCSR_.write(idx, val); } } } // namespace debugger