Compare commits
	
		
			1 Commits
		
	
	
		
			813b40409d
			...
			b5d915f389
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| b5d915f389 | 
| @@ -63,7 +63,7 @@ uint8_t *tgc5c::get_regs_base_ptr() { | |||||||
| 	return reinterpret_cast<uint8_t*>(®); | 	return reinterpret_cast<uint8_t*>(®); | ||||||
| } | } | ||||||
|  |  | ||||||
| tgc5c::phys_addr_t tgc5c::virt2phys(const iss::addr_t &pc) { | tgc5c::phys_addr_t tgc5c::virt2phys(const iss::addr_t &addr) { | ||||||
|     return phys_addr_t(pc); // change logical address to physical address |     return phys_addr_t(addr.access, addr.space, addr.val&traits<tgc5c>::addr_mask); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -195,14 +195,6 @@ struct tgc5c: public arch_if { | |||||||
|  |  | ||||||
|     inline uint64_t stop_code() { return interrupt_sim; } |     inline uint64_t stop_code() { return interrupt_sim; } | ||||||
|  |  | ||||||
|     inline phys_addr_t v2p(const iss::addr_t& addr){ |  | ||||||
|         if (addr.space != traits<tgc5c>::MEM || addr.type == iss::address_type::PHYSICAL || |  | ||||||
|                 addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL) { |  | ||||||
|             return phys_addr_t(addr.access, addr.space, addr.val&traits<tgc5c>::addr_mask); |  | ||||||
|         } else |  | ||||||
|             return virt2phys(addr); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     virtual phys_addr_t virt2phys(const iss::addr_t& addr); |     virtual phys_addr_t virt2phys(const iss::addr_t& addr); | ||||||
|  |  | ||||||
|     virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } |     virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } | ||||||
|   | |||||||
| @@ -42,15 +42,15 @@ namespace iss { | |||||||
| namespace interp { | namespace interp { | ||||||
| using namespace sysc; | using namespace sysc; | ||||||
| volatile std::array<bool, 2> tgc_init = { | volatile std::array<bool, 2> tgc_init = { | ||||||
|         core_factory::instance().register_creator("tgc5c|m_p|interp", [](unsigned gdb_port, void* data) -> std::tuple<cpu_ptr, vm_ptr>{ |         iss_factory::instance().register_creator("tgc5c|m_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t { | ||||||
|             auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data); |             auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data); | ||||||
|             arch::tgc5c* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::tgc5c>>(cc); |             auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::tgc5c>>(cc); | ||||||
|             return {cpu_ptr{cpu}, vm_ptr{create(cpu, gdb_port)}}; |             return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc5c*>(cpu), gdb_port)}}; | ||||||
|         }), |         }), | ||||||
|         core_factory::instance().register_creator("tgc5c|mu_p|interp", [](unsigned gdb_port, void* data) -> std::tuple<cpu_ptr, vm_ptr>{ |         iss_factory::instance().register_creator("tgc5c|mu_p|interp", [](unsigned gdb_port, void* data) -> iss_factory::base_t { | ||||||
|             auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data); |             auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data); | ||||||
|             arch::tgc5c* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::tgc5c>>(cc); |             auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::tgc5c>>(cc); | ||||||
|             return {cpu_ptr{cpu}, vm_ptr{create(cpu, gdb_port)}}; |             return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc5c*>(cpu), gdb_port)}}; | ||||||
|         }) |         }) | ||||||
| }; | }; | ||||||
| } | } | ||||||
| @@ -58,15 +58,15 @@ volatile std::array<bool, 2> tgc_init = { | |||||||
| namespace tcc { | namespace tcc { | ||||||
| using namespace sysc; | using namespace sysc; | ||||||
| volatile std::array<bool, 2> tgc_init = { | volatile std::array<bool, 2> tgc_init = { | ||||||
|         core_factory::instance().register_creator("tgc5c|m_p|tcc", [](unsigned gdb_port, void* data) -> std::tuple<cpu_ptr, vm_ptr>{ |         iss_factory::instance().register_creator("tgc5c|m_p|tcc", [](unsigned gdb_port, void* data) -> iss_factory::base_t { | ||||||
|             auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data); |             auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data); | ||||||
|             arch::tgc5c* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::tgc5c>>(cc); |             auto* cpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::tgc5c>>(cc); | ||||||
|             return {cpu_ptr{cpu}, vm_ptr{create(cpu, gdb_port)}}; |             return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc5c*>(cpu), gdb_port)}}; | ||||||
|         }), |         }), | ||||||
|         core_factory::instance().register_creator("tgc5c|mu_p|tcc", [](unsigned gdb_port, void* data) -> std::tuple<cpu_ptr, vm_ptr>{ |         iss_factory::instance().register_creator("tgc5c|mu_p|tcc", [](unsigned gdb_port, void* data) -> iss_factory::base_t { | ||||||
|             auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data); |             auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data); | ||||||
|             arch::tgc5c* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::tgc5c>>(cc); |             auto* cpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::tgc5c>>(cc); | ||||||
|             return {cpu_ptr{cpu}, vm_ptr{create(cpu, gdb_port)}}; |             return {sysc::sc_cpu_ptr{cpu}, vm_ptr{create(static_cast<arch::tgc5c*>(cpu), gdb_port)}}; | ||||||
|         }) |         }) | ||||||
| }; | }; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -152,14 +152,22 @@ private: | |||||||
|     /**************************************************************************** |     /**************************************************************************** | ||||||
|      * start opcode definitions |      * start opcode definitions | ||||||
|      ****************************************************************************/ |      ****************************************************************************/ | ||||||
|     struct InstructionDesriptor { |     struct instruction_descriptor { | ||||||
|         size_t length; |         size_t length; | ||||||
|         uint32_t value; |         uint32_t value; | ||||||
|         uint32_t mask; |         uint32_t mask; | ||||||
|         typename arch::traits<ARCH>::opcode_e op; |         typename arch::traits<ARCH>::opcode_e op; | ||||||
|     }; |     }; | ||||||
|  |     struct decoding_tree_node{ | ||||||
|  |         std::vector<instruction_descriptor> instrs; | ||||||
|  |         std::vector<decoding_tree_node*> children; | ||||||
|  |         uint32_t submask = std::numeric_limits<uint32_t>::max(); | ||||||
|  |         uint32_t value; | ||||||
|  |         decoding_tree_node(uint32_t value) : value(value){} | ||||||
|  |     }; | ||||||
|  |  | ||||||
|     const std::array<InstructionDesriptor, 87> instr_descr = {{ |     decoding_tree_node* root {nullptr}; | ||||||
|  |     const std::array<instruction_descriptor, 87> instr_descr = {{ | ||||||
|          /* entries are: size, valid value, valid mask, function ptr */ |          /* entries are: size, valid value, valid mask, function ptr */ | ||||||
|         {32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, arch::traits<ARCH>::opcode_e::LUI}, |         {32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, arch::traits<ARCH>::opcode_e::LUI}, | ||||||
|         {32, 0b00000000000000000000000000010111, 0b00000000000000000000000001111111, arch::traits<ARCH>::opcode_e::AUIPC}, |         {32, 0b00000000000000000000000000010111, 0b00000000000000000000000001111111, arch::traits<ARCH>::opcode_e::AUIPC}, | ||||||
| @@ -250,18 +258,76 @@ private: | |||||||
|         {16, 0b0000000000000000, 0b1111111111111111, arch::traits<ARCH>::opcode_e::DII}, |         {16, 0b0000000000000000, 0b1111111111111111, arch::traits<ARCH>::opcode_e::DII}, | ||||||
|     }}; |     }}; | ||||||
|  |  | ||||||
|     //static constexpr typename traits::addr_t upper_bits = ~traits::PGMASK; |  | ||||||
|     iss::status fetch_ins(virt_addr_t pc, uint8_t * data){ |     iss::status fetch_ins(virt_addr_t pc, uint8_t * data){ | ||||||
|         auto phys_pc = this->core.v2p(pc); |         if(this->core.has_mmu()) { | ||||||
|         //if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary |             auto phys_pc = this->core.virt2phys(pc); | ||||||
|         //    if (this->core.read(phys_pc, 2, data) != iss::Ok) return iss::Err; | //            if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary | ||||||
|         //    if ((data[0] & 0x3) == 0x3) // this is a 32bit instruction | //                if (this->core.read(phys_pc, 2, data) != iss::Ok) return iss::Err; | ||||||
|         //        if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok) return iss::Err; | //                if ((data[0] & 0x3) == 0x3) // this is a 32bit instruction | ||||||
|         //} else { | //                    if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok) | ||||||
|             if (this->core.read(phys_pc, 4, data) != iss::Ok)  return iss::Err; | //                        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; |         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<ARCH>::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<ARCH>::opcode_e::MAX_OPCODE; | ||||||
|  |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| template <typename CODE_WORD> void debug_fn(CODE_WORD insn) { | template <typename CODE_WORD> void debug_fn(CODE_WORD insn) { | ||||||
| @@ -288,16 +354,11 @@ constexpr size_t bit_count(uint32_t u) { | |||||||
| template <typename ARCH> | template <typename ARCH> | ||||||
| vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) | vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id) | ||||||
| : vm_base<ARCH>(core, core_id, cluster_id) { | : vm_base<ARCH>(core, core_id, cluster_id) { | ||||||
|     unsigned id=0; |     root = new decoding_tree_node(std::numeric_limits<uint32_t>::max()); | ||||||
|     for (auto instr : instr_descr) { |     for(auto instr:instr_descr){ | ||||||
|         auto quadrant = instr.value & 0x3; |         root->instrs.push_back(instr); | ||||||
|         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); |  | ||||||
|         }); |  | ||||||
|     } |     } | ||||||
|  |     populate_decoding_tree(root); | ||||||
| } | } | ||||||
|  |  | ||||||
| inline bool is_count_limit_enabled(finish_cond_e cond){ | 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; |     return (cond & finish_cond_e::JUMP_TO_SELF) == finish_cond_e::JUMP_TO_SELF; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename ARCH> |  | ||||||
| typename arch::traits<ARCH>::opcode_e vm_impl<ARCH>::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<ARCH>::opcode_e::MAX_OPCODE; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template <typename ARCH> | template <typename ARCH> | ||||||
| typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit){ | typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit){ | ||||||
|     auto pc=start; |     auto pc=start; | ||||||
| @@ -337,7 +390,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co | |||||||
|         } else { |         } else { | ||||||
|             if (is_jump_to_self_enabled(cond) && |             if (is_jump_to_self_enabled(cond) && | ||||||
|                     (instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0' |                     (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 |             // pre execution stuff | ||||||
|              this->core.reg.last_branch = 0; |              this->core.reg.last_branch = 0; | ||||||
|             if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id)); |             if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id)); | ||||||
|   | |||||||
| @@ -3138,9 +3138,9 @@ private: | |||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| template <typename CODE_WORD> void debug_fn(CODE_WORD insn) { | template <typename CODE_WORD> void debug_fn(CODE_WORD instr) { | ||||||
|     volatile CODE_WORD x = insn; |     volatile CODE_WORD x = instr; | ||||||
|     insn = 2 * x; |     instr = 2 * x; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); } | template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); } | ||||||
| @@ -3163,30 +3163,30 @@ std::tuple<continuation_e> | |||||||
| vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, tu_builder& tu) { | vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, tu_builder& tu) { | ||||||
|     // we fetch at max 4 byte, alignment is 2 |     // we fetch at max 4 byte, alignment is 2 | ||||||
|     enum {TRAP_ID=1<<16}; |     enum {TRAP_ID=1<<16}; | ||||||
|     code_word_t insn = 0; |     code_word_t instr = 0; | ||||||
|     // const typename traits::addr_t upper_bits = ~traits::PGMASK; |  | ||||||
|     phys_addr_t paddr(pc); |     phys_addr_t paddr(pc); | ||||||
|     auto *const data = (uint8_t *)&insn; |     if(this->core.has_mmu()) | ||||||
|     paddr = this->core.v2p(pc); |         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 | //    if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary | ||||||
| //        auto res = this->core.read(paddr, 2, data); | //        auto res = this->core.read(paddr, 2, data); | ||||||
| //        if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); | //        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); | //            res = this->core.read(this->core.v2p(pc + 2), 2, data + 2); | ||||||
| //        } | //        } | ||||||
| //    } else { | //    } else { | ||||||
|         auto res = this->core.read(paddr, 4, data); |         auto res = this->core.read(paddr, 4, reinterpret_cast<uint8_t*>(&instr)); | ||||||
|         if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); |         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 |     // curr pc on stack | ||||||
|     ++inst_cnt; |     ++inst_cnt; | ||||||
|     auto lut_val = extract_fields(insn); |     auto lut_val = extract_fields(instr); | ||||||
|     auto f = qlut[insn & 0x3][lut_val]; |     auto f = qlut[instr & 0x3][lut_val]; | ||||||
|     if (f == nullptr) { |     if (f == nullptr) { | ||||||
|         f = &this_class::illegal_intruction; |         f = &this_class::illegal_intruction; | ||||||
|     } |     } | ||||||
|     return (this->*f)(pc, insn, tu); |     return (this->*f)(pc, instr, tu); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) { | template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user