diff --git a/src/iss/arch/tgc5c.cpp b/src/iss/arch/tgc5c.cpp index 2b9fc3f..6996cb8 100644 --- a/src/iss/arch/tgc5c.cpp +++ b/src/iss/arch/tgc5c.cpp @@ -63,7 +63,7 @@ uint8_t *tgc5c::get_regs_base_ptr() { return reinterpret_cast(®); } -tgc5c::phys_addr_t tgc5c::virt2phys(const iss::addr_t &pc) { - return phys_addr_t(pc); // change logical address to physical address +tgc5c::phys_addr_t tgc5c::virt2phys(const iss::addr_t &addr) { + return phys_addr_t(addr.access, addr.space, addr.val&traits::addr_mask); } diff --git a/src/iss/arch/tgc5c.h b/src/iss/arch/tgc5c.h index 38e2e31..319f31f 100644 --- a/src/iss/arch/tgc5c.h +++ b/src/iss/arch/tgc5c.h @@ -195,14 +195,6 @@ struct tgc5c: public arch_if { inline uint64_t stop_code() { return interrupt_sim; } - inline phys_addr_t v2p(const iss::addr_t& addr){ - if (addr.space != traits::MEM || addr.type == iss::address_type::PHYSICAL || - addr_mode[static_cast(addr.access)&0x3]==address_type::PHYSICAL) { - return phys_addr_t(addr.access, addr.space, addr.val&traits::addr_mask); - } else - return virt2phys(addr); - } - virtual phys_addr_t virt2phys(const iss::addr_t& addr); virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } diff --git a/src/sysc/register_tgc_c.cpp b/src/sysc/register_tgc_c.cpp index be81241..7ea4d5b 100644 --- a/src/sysc/register_tgc_c.cpp +++ b/src/sysc/register_tgc_c.cpp @@ -42,15 +42,15 @@ namespace iss { namespace interp { using namespace sysc; volatile std::array tgc_init = { - core_factory::instance().register_creator("tgc5c|m_p|interp", [](unsigned gdb_port, void* data) -> std::tuple{ + iss_factory::instance().register_creator("tgc5c|m_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t { auto cc = reinterpret_cast(data); - arch::tgc5c* cpu = new sc_core_adapter>(cc); - return {cpu_ptr{cpu}, vm_ptr{create(cpu, gdb_port)}}; + auto* cpu = new sc_core_adapter>(cc); + return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; }), - core_factory::instance().register_creator("tgc5c|mu_p|interp", [](unsigned gdb_port, void* data) -> std::tuple{ + iss_factory::instance().register_creator("tgc5c|mu_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t { auto cc = reinterpret_cast(data); - arch::tgc5c* cpu = new sc_core_adapter>(cc); - return {cpu_ptr{cpu}, vm_ptr{create(cpu, gdb_port)}}; + auto* cpu = new sc_core_adapter>(cc); + return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; }) }; } @@ -58,15 +58,15 @@ volatile std::array tgc_init = { namespace tcc { using namespace sysc; volatile std::array tgc_init = { - core_factory::instance().register_creator("tgc5c|m_p|tcc", [](unsigned gdb_port, void* data) -> std::tuple{ + iss_factory::instance().register_creator("tgc5c|m_p|tcc", [](unsigned gdb_port, void* data) -> iss_factory::base_t { auto cc = reinterpret_cast(data); - arch::tgc5c* cpu = new sc_core_adapter>(cc); - return {cpu_ptr{cpu}, vm_ptr{create(cpu, gdb_port)}}; + auto* cpu = new sc_core_adapter>(cc); + return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; }), - core_factory::instance().register_creator("tgc5c|mu_p|tcc", [](unsigned gdb_port, void* data) -> std::tuple{ + iss_factory::instance().register_creator("tgc5c|mu_p|tcc", [](unsigned gdb_port, void* data) -> iss_factory::base_t { auto cc = reinterpret_cast(data); - arch::tgc5c* cpu = new sc_core_adapter>(cc); - return {cpu_ptr{cpu}, vm_ptr{create(cpu, gdb_port)}}; + auto* cpu = new sc_core_adapter>(cc); + return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast(cpu), gdb_port)}}; }) }; } diff --git a/src/vm/interp/vm_tgc5c.cpp b/src/vm/interp/vm_tgc5c.cpp index 07218cf..46b46c0 100644 --- a/src/vm/interp/vm_tgc5c.cpp +++ b/src/vm/interp/vm_tgc5c.cpp @@ -152,14 +152,22 @@ private: /**************************************************************************** * start opcode definitions ****************************************************************************/ - struct InstructionDesriptor { + struct instruction_descriptor { size_t length; uint32_t value; uint32_t mask; typename arch::traits::opcode_e op; }; + struct decoding_tree_node{ + std::vector instrs; + std::vector children; + uint32_t submask = std::numeric_limits::max(); + uint32_t value; + decoding_tree_node(uint32_t value) : value(value){} + }; - const std::array instr_descr = {{ + decoding_tree_node* root {nullptr}; + const std::array instr_descr = {{ /* entries are: size, valid value, valid mask, function ptr */ {32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, arch::traits::opcode_e::LUI}, {32, 0b00000000000000000000000000010111, 0b00000000000000000000000001111111, arch::traits::opcode_e::AUIPC}, @@ -250,18 +258,76 @@ private: {16, 0b0000000000000000, 0b1111111111111111, arch::traits::opcode_e::DII}, }}; - //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; - //} + if(this->core.has_mmu()) { + auto phys_pc = this->core.virt2phys(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; +// } + } else { + if (this->core.read(phys_addr_t(pc.access, pc.space, pc.val), 4, data) != iss::Ok) + return iss::Err; + + } return iss::Ok; } + + void populate_decoding_tree(decoding_tree_node* root){ + //create submask + for(auto instr: root->instrs){ + root->submask &= instr.mask; + } + //put each instr according to submask&encoding into children + for(auto instr: root->instrs){ + bool foundMatch = false; + for(auto child: root->children){ + //use value as identifying trait + if(child->value == (instr.value&root->submask)){ + child->instrs.push_back(instr); + foundMatch = true; + } + } + if(!foundMatch){ + decoding_tree_node* child = new decoding_tree_node(instr.value&root->submask); + child->instrs.push_back(instr); + root->children.push_back(child); + } + } + root->instrs.clear(); + //call populate_decoding_tree for all children + if(root->children.size() >1) + for(auto child: root->children){ + populate_decoding_tree(child); + } + else{ + //sort instrs by value of the mask, this works bc we want to have the least restrictive one last + std::sort(root->children[0]->instrs.begin(), root->children[0]->instrs.end(), [](const instruction_descriptor& instr1, const instruction_descriptor& instr2) { + return instr1.mask > instr2.mask; + }); + } + } + typename arch::traits::opcode_e decode_instr(decoding_tree_node* node, code_word_t word){ + if(!node->children.size()){ + if(node->instrs.size() == 1) return node->instrs[0].op; + for(auto instr : node->instrs){ + if((instr.mask&word) == instr.value) return instr.op; + } + } + else{ + for(auto child : node->children){ + if (child->value == (node->submask&word)){ + return decode_instr(child, word); + } + } + } + return arch::traits::opcode_e::MAX_OPCODE; + } }; template void debug_fn(CODE_WORD insn) { @@ -288,16 +354,11 @@ constexpr size_t bit_count(uint32_t u) { template vm_impl::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) : vm_base(core, core_id, cluster_id) { - unsigned id=0; - for (auto instr : instr_descr) { - auto quadrant = instr.value & 0x3; - qlut[quadrant].push_back(instruction_pattern{instr.value, instr.mask, instr.op}); - } - for(auto& lut: qlut){ - std::sort(std::begin(lut), std::end(lut), [](instruction_pattern const& a, instruction_pattern const& b){ - return bit_count(a.mask) > bit_count(b.mask); - }); + root = new decoding_tree_node(std::numeric_limits::max()); + for(auto instr:instr_descr){ + root->instrs.push_back(instr); } + populate_decoding_tree(root); } inline bool is_count_limit_enabled(finish_cond_e cond){ @@ -308,14 +369,6 @@ inline bool is_jump_to_self_enabled(finish_cond_e cond){ return (cond & finish_cond_e::JUMP_TO_SELF) == finish_cond_e::JUMP_TO_SELF; } -template -typename arch::traits::opcode_e vm_impl::decode_inst_id(code_word_t instr){ - for(auto& e: qlut[instr&0x3]){ - if(!((instr&e.mask) ^ e.value )) return e.id; - } - return arch::traits::opcode_e::MAX_OPCODE; -} - template typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit){ auto pc=start; @@ -337,7 +390,7 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co } else { if (is_jump_to_self_enabled(cond) && (instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0' - auto inst_id = decode_inst_id(instr); + auto inst_id = decode_instr(root, instr); // pre execution stuff this->core.reg.last_branch = 0; if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast(inst_id)); diff --git a/src/vm/tcc/vm_tgc5c.cpp b/src/vm/tcc/vm_tgc5c.cpp index 55bc1f6..474807b 100644 --- a/src/vm/tcc/vm_tgc5c.cpp +++ b/src/vm/tcc/vm_tgc5c.cpp @@ -3138,9 +3138,9 @@ private: } }; -template void debug_fn(CODE_WORD insn) { - volatile CODE_WORD x = insn; - insn = 2 * x; +template void debug_fn(CODE_WORD instr) { + volatile CODE_WORD x = instr; + instr = 2 * x; } template vm_impl::vm_impl() { this(new ARCH()); } @@ -3163,30 +3163,30 @@ std::tuple vm_impl::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, tu_builder& tu) { // we fetch at max 4 byte, alignment is 2 enum {TRAP_ID=1<<16}; - code_word_t insn = 0; - // const typename traits::addr_t upper_bits = ~traits::PGMASK; + code_word_t instr = 0; phys_addr_t paddr(pc); - auto *const data = (uint8_t *)&insn; - paddr = this->core.v2p(pc); + if(this->core.has_mmu()) + paddr = this->core.virt2phys(pc); + //TODO: re-add page handling // if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary // auto res = this->core.read(paddr, 2, data); // if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); -// if ((insn & 0x3) == 0x3) { // this is a 32bit instruction +// if ((instr & 0x3) == 0x3) { // this is a 32bit instruction // res = this->core.read(this->core.v2p(pc + 2), 2, data + 2); // } // } else { - auto res = this->core.read(paddr, 4, data); + auto res = this->core.read(paddr, 4, reinterpret_cast(&instr)); if (res != 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 (instr == 0x0000006f || (instr&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0' // curr pc on stack ++inst_cnt; - auto lut_val = extract_fields(insn); - auto f = qlut[insn & 0x3][lut_val]; + auto lut_val = extract_fields(instr); + auto f = qlut[instr & 0x3][lut_val]; if (f == nullptr) { f = &this_class::illegal_intruction; } - return (this->*f)(pc, insn, tu); + return (this->*f)(pc, instr, tu); } template void vm_impl::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) {