fixes compile issues from merge
This commit is contained in:
parent
813b40409d
commit
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()) {
|
||||||
|
auto phys_pc = this->core.virt2phys(pc);
|
||||||
// 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
|
||||||
// if (this->core.read(phys_pc, 2, data) != iss::Ok) return iss::Err;
|
// if (this->core.read(phys_pc, 2, data) != iss::Ok) return iss::Err;
|
||||||
// if ((data[0] & 0x3) == 0x3) // this is a 32bit instruction
|
// 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;
|
// if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok)
|
||||||
|
// return iss::Err;
|
||||||
// } else {
|
// } else {
|
||||||
if (this->core.read(phys_pc, 4, data) != iss::Ok) return iss::Err;
|
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) {
|
||||||
|
|
Loading…
Reference in New Issue