//////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2017, MINRES Technologies GmbH // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // 3. Neither the name of the copyright holder nor the names of its contributors // may be used to endorse or promote products derived from this software // without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // // Contributors: // eyck@minres.com - initial API and implementation // // //////////////////////////////////////////////////////////////////////////////// #include "scc/report.h" #include "iss/arch/riscv_hart_msu_vp.h" #include "iss/arch/rv32imac.h" #include "iss/iss.h" #include "iss/vm_types.h" #include "iss/debugger/server.h" #include "iss/debugger/gdb_session.h" #include "iss/debugger/target_adapter_if.h" #include "iss/debugger/encoderdecoder.h" #include "sysc/SiFive/core_complex.h" #ifdef WITH_SCV #include #endif namespace sysc { namespace SiFive { namespace { iss::debugger::encoder_decoder encdec; } namespace { const char lvl[] = {'U', 'S', 'H', 'M'}; const char *trap_str[] = {"Instruction address misaligned", "Instruction access fault", "Illegal instruction", "Breakpoint", "Load address misaligned", "Load access fault", "Store/AMO address misaligned", "Store/AMO access fault", "Environment call from U-mode", "Environment call from S-mode", "Reserved", "Environment call from M-mode", "Instruction page fault", "Load page fault", "Reserved", "Store/AMO page fault"}; const char *irq_str[] = { "User software interrupt", "Supervisor software interrupt", "Reserved", "Machine software interrupt", "User timer interrupt", "Supervisor timer interrupt", "Reserved", "Machine timer interrupt", "User external interrupt", "Supervisor external interrupt", "Reserved", "Machine external interrupt"}; } class core_wrapper : public iss::arch::riscv_hart_msu_vp { public: using core_type = iss::arch::rv32imac; using base_type = iss::arch::riscv_hart_msu_vp; using phys_addr_t = typename iss::arch::traits::phys_addr_t; core_wrapper(core_complex *owner) : owner(owner) {} uint32_t get_mode(){ return this->reg.machine_state; } base_type::hart_state& get_state() { return this->state; } void notify_phase(iss::arch_if::exec_phase phase); void disass_output(uint64_t pc, const std::string instr) override { #ifndef WITH_SCV std::stringstream s; s << "[p:" << lvl[this->reg.machine_state] << ";s:0x" << std::hex << std::setfill('0') << std::setw(sizeof(reg_t) * 2) << (reg_t)state.mstatus << std::dec << ";c:" << this->reg.icount << "]"; CLOG(INFO, disass) << "0x"<disass_output(pc,instr); #endif }; iss::status read_mem(phys_addr_t addr, unsigned length, uint8_t *const data) { if (addr.type & iss::DEBUG) return owner->read_mem_dbg(addr.val, length, data) ? iss::Ok : iss::Err; else { return owner->read_mem(addr.val, length, data,addr.type && iss::FETCH) ? iss::Ok : iss::Err; } } iss::status write_mem(phys_addr_t addr, unsigned length, const uint8_t *const data) { if (addr.type & iss::DEBUG) return owner->write_mem_dbg(addr.val, length, data) ? iss::Ok : iss::Err; else return owner->write_mem(addr.val, length, data) ? iss::Ok : iss::Err; } private: core_complex *const owner; }; int cmd_sysc(int argc, char* argv[], iss::debugger::out_func of, iss::debugger::data_func df, iss::debugger::target_adapter_if* tgt_adapter){ if(argc>1) { if(strcasecmp(argv[1], "print_time")==0){ std::string t = sc_core::sc_time_stamp().to_string(); of(t.c_str()); char buf[64]; encdec.enc_string(t.c_str(), buf, 63); df(buf); return iss::Ok; } else if(strcasecmp(argv[1], "break")==0){ sc_core::sc_time t; if(argc==4){ t= scc::parse_from_string(argv[2], argv[3]); } else if(argc==3){ t= scc::parse_from_string(argv[2]); } else return iss::Err; // no check needed as it is only called if debug server is active tgt_adapter->add_break_condition([t]()->unsigned{ LOG(TRACE)<<"Checking condition at "<=t?std::numeric_limits::max():0; }); return iss::Ok; } return iss::Err; } return iss::Err; } void core_wrapper::notify_phase(exec_phase phase) { core_type::notify_phase(phase); if (phase == ISTART) owner->sync(); } core_complex::core_complex(sc_core::sc_module_name name) : sc_core::sc_module(name) , NAMED(initiator) , NAMED(clk_i) , NAMED(rst_i) , NAMED(elf_file, this) , NAMED(enable_disass, true, this) , NAMED(reset_address, 0ULL, this) , NAMED(gdb_server_port, 0, this) , NAMED(dump_ir, false, this) , read_lut(tlm_dmi_ext()) , write_lut(tlm_dmi_ext()) , tgt_adapter(nullptr) #ifdef WITH_SCV , m_db(scv_tr_db::get_default_db()) , stream_handle(nullptr) , instr_tr_handle(nullptr) , fetch_tr_handle(nullptr) #endif { initiator.register_invalidate_direct_mem_ptr([=](uint64_t start, uint64_t end) -> void { auto lut_entry = read_lut.getEntry(start); if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && end <= lut_entry.get_end_address() + 1) { read_lut.removeEntry(lut_entry); } lut_entry = write_lut.getEntry(start); if (lut_entry.get_granted_access() != tlm::tlm_dmi::DMI_ACCESS_NONE && end <= lut_entry.get_end_address() + 1) { write_lut.removeEntry(lut_entry); } }); SC_THREAD(run); SC_METHOD(clk_cb); sensitive << clk_i; } core_complex::~core_complex() = default; void core_complex::trace(sc_core::sc_trace_file *trf) {} void core_complex::before_end_of_elaboration() { cpu = std::make_unique(this); vm = iss::create(cpu.get(), gdb_server_port.value, dump_ir.value); vm->setDisassEnabled(enable_disass.value); auto* srv = iss::debugger::server::get(); if(srv) tgt_adapter = srv->get_target(); if(tgt_adapter) tgt_adapter->add_custom_command({ "sysc", [this](int argc, char* argv[], iss::debugger::out_func of, iss::debugger::data_func df)-> int { return cmd_sysc(argc, argv, of, df, tgt_adapter); }, "SystemC sub-commands: break