Compare commits
No commits in common. "051dd5e2d3da35b70b2af709cc86837fa70213bc" and "0432803d82e2604c2f08ed35dfae3b965ee45a9b" have entirely different histories.
051dd5e2d3
...
0432803d82
@ -20,7 +20,6 @@ set(LIB_SOURCES
|
|||||||
src/iss/arch/tgc5c.cpp
|
src/iss/arch/tgc5c.cpp
|
||||||
src/vm/interp/vm_tgc5c.cpp
|
src/vm/interp/vm_tgc5c.cpp
|
||||||
src/vm/fp_functions.cpp
|
src/vm/fp_functions.cpp
|
||||||
src/vm/instruction_decoder.cpp
|
|
||||||
src/iss/semihosting/semihosting.cpp
|
src/iss/semihosting/semihosting.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -37,7 +37,6 @@
|
|||||||
#include <iss/asmjit/vm_base.h>
|
#include <iss/asmjit/vm_base.h>
|
||||||
#include <asmjit/asmjit.h>
|
#include <asmjit/asmjit.h>
|
||||||
#include <util/logging.h>
|
#include <util/logging.h>
|
||||||
#include <vm/instruction_decoder.h>
|
|
||||||
|
|
||||||
#ifndef FMT_HEADER_ONLY
|
#ifndef FMT_HEADER_ONLY
|
||||||
#define FMT_HEADER_ONLY
|
#define FMT_HEADER_ONLY
|
||||||
@ -80,16 +79,22 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
using super::mov;
|
||||||
|
using super::cmp;
|
||||||
using super::get_ptr_for;
|
using super::get_ptr_for;
|
||||||
|
using super::get_reg;
|
||||||
|
using super::get_reg_Gp;
|
||||||
using super::get_reg_for;
|
using super::get_reg_for;
|
||||||
using super::get_reg_for_Gp;
|
using super::get_reg_for_Gp;
|
||||||
using super::load_reg_from_mem;
|
using super::load_reg_from_mem;
|
||||||
using super::load_reg_from_mem_Gp;
|
using super::load_reg_from_mem_Gp;
|
||||||
using super::write_reg_to_mem;
|
using super::write_reg_to_mem;
|
||||||
|
using super::gen_ext;
|
||||||
using super::gen_read_mem;
|
using super::gen_read_mem;
|
||||||
using super::gen_write_mem;
|
using super::gen_write_mem;
|
||||||
using super::gen_wait;
|
using super::gen_wait;
|
||||||
using super::gen_leave;
|
using super::gen_leave;
|
||||||
|
using super::gen_operation;
|
||||||
using super::gen_sync;
|
using super::gen_sync;
|
||||||
using super::gen_set_tval;
|
using super::gen_set_tval;
|
||||||
|
|
||||||
@ -116,11 +121,20 @@ private:
|
|||||||
* start opcode definitions
|
* start opcode definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
struct instruction_descriptor {
|
struct instruction_descriptor {
|
||||||
uint32_t length;
|
size_t length;
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
uint32_t mask;
|
uint32_t mask;
|
||||||
compile_func op;
|
compile_func 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){}
|
||||||
|
};
|
||||||
|
|
||||||
|
decoding_tree_node* root {nullptr};
|
||||||
|
|
||||||
const std::array<instruction_descriptor, ${instructions.size()}> instr_descr = {{
|
const std::array<instruction_descriptor, ${instructions.size()}> instr_descr = {{
|
||||||
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
||||||
@ -128,9 +142,6 @@ private:
|
|||||||
{${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
|
{${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
|
||||||
}};
|
}};
|
||||||
|
|
||||||
//needs to be declared after instr_descr
|
|
||||||
decoder instr_decoder;
|
|
||||||
|
|
||||||
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
|
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
|
||||||
/* instruction ${idx}: ${instr.name} */
|
/* instruction ${idx}: ${instr.name} */
|
||||||
continuation_e __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, jit_holder& jh){
|
continuation_e __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, jit_holder& jh){
|
||||||
@ -195,22 +206,72 @@ private:
|
|||||||
gen_instr_epilogue(jh);
|
gen_instr_epilogue(jh);
|
||||||
return BRANCH;
|
return BRANCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//decoding functionality
|
||||||
|
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compile_func 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 nullptr;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
|
template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
|
||||||
|
|
||||||
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) {
|
||||||
, instr_decoder([this]() {
|
root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
|
||||||
std::vector<generic_instruction_descriptor> g_instr_descr;
|
for(auto instr: instr_descr){
|
||||||
g_instr_descr.reserve(instr_descr.size());
|
root->instrs.push_back(instr);
|
||||||
for (uint32_t i = 0; i < instr_descr.size(); ++i) {
|
}
|
||||||
generic_instruction_descriptor new_instr_descr {instr_descr[i].value, instr_descr[i].mask, i};
|
populate_decoding_tree(root);
|
||||||
g_instr_descr.push_back(new_instr_descr);
|
}
|
||||||
}
|
|
||||||
return std::move(g_instr_descr);
|
|
||||||
}()) {}
|
|
||||||
|
|
||||||
template <typename ARCH>
|
template <typename ARCH>
|
||||||
continuation_e vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, jit_holder& jh) {
|
continuation_e vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, jit_holder& jh) {
|
||||||
@ -226,10 +287,7 @@ continuation_e vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned
|
|||||||
if (instr == 0x0000006f || (instr&0xffff)==0xa001)
|
if (instr == 0x0000006f || (instr&0xffff)==0xa001)
|
||||||
throw simulation_stopped(0); // 'J 0' or 'C.J 0'
|
throw simulation_stopped(0); // 'J 0' or 'C.J 0'
|
||||||
++inst_cnt;
|
++inst_cnt;
|
||||||
uint32_t inst_index = instr_decoder.decode_instr(instr);
|
auto f = decode_instr(root, instr);
|
||||||
compile_func f = nullptr;
|
|
||||||
if(inst_index < instr_descr.size())
|
|
||||||
f = instr_descr[inst_index].op;
|
|
||||||
if (f == nullptr)
|
if (f == nullptr)
|
||||||
f = &this_class::illegal_instruction;
|
f = &this_class::illegal_instruction;
|
||||||
return (this->*f)(pc, instr, jh);
|
return (this->*f)(pc, instr, jh);
|
||||||
|
@ -36,7 +36,6 @@
|
|||||||
#include <iss/iss.h>
|
#include <iss/iss.h>
|
||||||
#include <iss/llvm/vm_base.h>
|
#include <iss/llvm/vm_base.h>
|
||||||
#include <util/logging.h>
|
#include <util/logging.h>
|
||||||
#include <vm/instruction_decoder.h>
|
|
||||||
|
|
||||||
#ifndef FMT_HEADER_ONLY
|
#ifndef FMT_HEADER_ONLY
|
||||||
#define FMT_HEADER_ONLY
|
#define FMT_HEADER_ONLY
|
||||||
@ -137,11 +136,20 @@ private:
|
|||||||
* start opcode definitions
|
* start opcode definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
struct instruction_descriptor {
|
struct instruction_descriptor {
|
||||||
uint32_t length;
|
size_t length;
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
uint32_t mask;
|
uint32_t mask;
|
||||||
compile_func op;
|
compile_func 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){}
|
||||||
|
};
|
||||||
|
|
||||||
|
decoding_tree_node* root {nullptr};
|
||||||
|
|
||||||
const std::array<instruction_descriptor, ${instructions.size()}> instr_descr = {{
|
const std::array<instruction_descriptor, ${instructions.size()}> instr_descr = {{
|
||||||
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
||||||
@ -149,9 +157,6 @@ private:
|
|||||||
{${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
|
{${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
|
||||||
}};
|
}};
|
||||||
|
|
||||||
//needs to be declared after instr_descr
|
|
||||||
decoder instr_decoder;
|
|
||||||
|
|
||||||
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
|
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
|
||||||
/* instruction ${idx}: ${instr.name} */
|
/* instruction ${idx}: ${instr.name} */
|
||||||
std::tuple<continuation_e, BasicBlock*> __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){
|
std::tuple<continuation_e, BasicBlock*> __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){
|
||||||
@ -214,6 +219,58 @@ private:
|
|||||||
this->builder.CreateBr(bb);
|
this->builder.CreateBr(bb);
|
||||||
return std::make_tuple(BRANCH, nullptr);
|
return std::make_tuple(BRANCH, nullptr);
|
||||||
}
|
}
|
||||||
|
//decoding functionality
|
||||||
|
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compile_func 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 nullptr;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename CODE_WORD> void debug_fn(CODE_WORD instr) {
|
template <typename CODE_WORD> void debug_fn(CODE_WORD instr) {
|
||||||
@ -225,16 +282,13 @@ template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
|
|||||||
|
|
||||||
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) {
|
||||||
, instr_decoder([this]() {
|
root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
|
||||||
std::vector<generic_instruction_descriptor> g_instr_descr;
|
for(auto instr:instr_descr){
|
||||||
g_instr_descr.reserve(instr_descr.size());
|
root->instrs.push_back(instr);
|
||||||
for (uint32_t i = 0; i < instr_descr.size(); ++i) {
|
}
|
||||||
generic_instruction_descriptor new_instr_descr {instr_descr[i].value, instr_descr[i].mask, i};
|
populate_decoding_tree(root);
|
||||||
g_instr_descr.push_back(new_instr_descr);
|
}
|
||||||
}
|
|
||||||
return std::move(g_instr_descr);
|
|
||||||
}()) {}
|
|
||||||
|
|
||||||
template <typename ARCH>
|
template <typename ARCH>
|
||||||
std::tuple<continuation_e, BasicBlock *>
|
std::tuple<continuation_e, BasicBlock *>
|
||||||
@ -255,16 +309,13 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
|
|||||||
// 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, data);
|
||||||
if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
|
if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
|
||||||
// }
|
// }
|
||||||
if (instr == 0x0000006f || (instr&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;
|
||||||
uint32_t inst_index = instr_decoder.decode_instr(instr);
|
auto f = decode_instr(root, instr);
|
||||||
compile_func f = nullptr;
|
|
||||||
if(inst_index < instr_descr.size())
|
|
||||||
f = instr_descr[inst_index].op;
|
|
||||||
if (f == nullptr) {
|
if (f == nullptr) {
|
||||||
f = &this_class::illegal_instruction;
|
f = &this_class::illegal_instruction;
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,6 @@
|
|||||||
#include <iss/tcc/vm_base.h>
|
#include <iss/tcc/vm_base.h>
|
||||||
#include <util/logging.h>
|
#include <util/logging.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vm/instruction_decoder.h>
|
|
||||||
|
|
||||||
#ifndef FMT_HEADER_ONLY
|
#ifndef FMT_HEADER_ONLY
|
||||||
#define FMT_HEADER_ONLY
|
#define FMT_HEADER_ONLY
|
||||||
@ -138,11 +137,20 @@ private:
|
|||||||
* start opcode definitions
|
* start opcode definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
struct instruction_descriptor {
|
struct instruction_descriptor {
|
||||||
uint32_t length;
|
size_t length;
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
uint32_t mask;
|
uint32_t mask;
|
||||||
compile_func op;
|
compile_func 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){}
|
||||||
|
};
|
||||||
|
|
||||||
|
decoding_tree_node* root {nullptr};
|
||||||
|
|
||||||
const std::array<instruction_descriptor, ${instructions.size()}> instr_descr = {{
|
const std::array<instruction_descriptor, ${instructions.size()}> instr_descr = {{
|
||||||
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
||||||
@ -150,9 +158,6 @@ private:
|
|||||||
{${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
|
{${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
|
||||||
}};
|
}};
|
||||||
|
|
||||||
//needs to be declared after instr_descr
|
|
||||||
decoder instr_decoder;
|
|
||||||
|
|
||||||
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
|
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
|
||||||
/* instruction ${idx}: ${instr.name} */
|
/* instruction ${idx}: ${instr.name} */
|
||||||
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, tu_builder& tu){
|
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, tu_builder& tu){
|
||||||
@ -193,6 +198,59 @@ private:
|
|||||||
vm_impl::gen_trap_check(tu);
|
vm_impl::gen_trap_check(tu);
|
||||||
return BRANCH;
|
return BRANCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//decoding functionality
|
||||||
|
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compile_func 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 nullptr;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename CODE_WORD> void debug_fn(CODE_WORD instr) {
|
template <typename CODE_WORD> void debug_fn(CODE_WORD instr) {
|
||||||
@ -204,16 +262,13 @@ template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
|
|||||||
|
|
||||||
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) {
|
||||||
, instr_decoder([this]() {
|
root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
|
||||||
std::vector<generic_instruction_descriptor> g_instr_descr;
|
for(auto instr:instr_descr){
|
||||||
g_instr_descr.reserve(instr_descr.size());
|
root->instrs.push_back(instr);
|
||||||
for (uint32_t i = 0; i < instr_descr.size(); ++i) {
|
}
|
||||||
generic_instruction_descriptor new_instr_descr {instr_descr[i].value, instr_descr[i].mask, i};
|
populate_decoding_tree(root);
|
||||||
g_instr_descr.push_back(new_instr_descr);
|
}
|
||||||
}
|
|
||||||
return std::move(g_instr_descr);
|
|
||||||
}()) {}
|
|
||||||
|
|
||||||
template <typename ARCH>
|
template <typename ARCH>
|
||||||
std::tuple<continuation_e>
|
std::tuple<continuation_e>
|
||||||
@ -232,16 +287,13 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
|
|||||||
// 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, reinterpret_cast<uint8_t*>(&instr));
|
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 (instr == 0x0000006f || (instr&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;
|
||||||
uint32_t inst_index = instr_decoder.decode_instr(instr);
|
auto f = decode_instr(root, instr);
|
||||||
compile_func f = nullptr;
|
|
||||||
if(inst_index < instr_descr.size())
|
|
||||||
f = instr_descr[inst_index].op;
|
|
||||||
if (f == nullptr) {
|
if (f == nullptr) {
|
||||||
f = &this_class::illegal_instruction;
|
f = &this_class::illegal_instruction;
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,6 @@
|
|||||||
#include <iss/asmjit/vm_base.h>
|
#include <iss/asmjit/vm_base.h>
|
||||||
#include <asmjit/asmjit.h>
|
#include <asmjit/asmjit.h>
|
||||||
#include <util/logging.h>
|
#include <util/logging.h>
|
||||||
#include <vm/instruction_decoder.h>
|
|
||||||
|
|
||||||
#ifndef FMT_HEADER_ONLY
|
#ifndef FMT_HEADER_ONLY
|
||||||
#define FMT_HEADER_ONLY
|
#define FMT_HEADER_ONLY
|
||||||
@ -80,16 +79,22 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
using super::mov;
|
||||||
|
using super::cmp;
|
||||||
using super::get_ptr_for;
|
using super::get_ptr_for;
|
||||||
|
using super::get_reg;
|
||||||
|
using super::get_reg_Gp;
|
||||||
using super::get_reg_for;
|
using super::get_reg_for;
|
||||||
using super::get_reg_for_Gp;
|
using super::get_reg_for_Gp;
|
||||||
using super::load_reg_from_mem;
|
using super::load_reg_from_mem;
|
||||||
using super::load_reg_from_mem_Gp;
|
using super::load_reg_from_mem_Gp;
|
||||||
using super::write_reg_to_mem;
|
using super::write_reg_to_mem;
|
||||||
|
using super::gen_ext;
|
||||||
using super::gen_read_mem;
|
using super::gen_read_mem;
|
||||||
using super::gen_write_mem;
|
using super::gen_write_mem;
|
||||||
using super::gen_wait;
|
using super::gen_wait;
|
||||||
using super::gen_leave;
|
using super::gen_leave;
|
||||||
|
using super::gen_operation;
|
||||||
using super::gen_sync;
|
using super::gen_sync;
|
||||||
using super::gen_set_tval;
|
using super::gen_set_tval;
|
||||||
|
|
||||||
@ -116,11 +121,20 @@ private:
|
|||||||
* start opcode definitions
|
* start opcode definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
struct instruction_descriptor {
|
struct instruction_descriptor {
|
||||||
uint32_t length;
|
size_t length;
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
uint32_t mask;
|
uint32_t mask;
|
||||||
compile_func op;
|
compile_func 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){}
|
||||||
|
};
|
||||||
|
|
||||||
|
decoding_tree_node* root {nullptr};
|
||||||
|
|
||||||
const std::array<instruction_descriptor, 87> instr_descr = {{
|
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 */
|
||||||
@ -300,9 +314,6 @@ private:
|
|||||||
{16, 0b0000000000000000, 0b1111111111111111, &this_class::__dii},
|
{16, 0b0000000000000000, 0b1111111111111111, &this_class::__dii},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
//needs to be declared after instr_descr
|
|
||||||
decoder instr_decoder;
|
|
||||||
|
|
||||||
/* instruction definitions */
|
/* instruction definitions */
|
||||||
/* instruction 0: LUI */
|
/* instruction 0: LUI */
|
||||||
continuation_e __lui(virt_addr_t& pc, code_word_t instr, jit_holder& jh){
|
continuation_e __lui(virt_addr_t& pc, code_word_t instr, jit_holder& jh){
|
||||||
@ -4735,22 +4746,72 @@ private:
|
|||||||
gen_instr_epilogue(jh);
|
gen_instr_epilogue(jh);
|
||||||
return BRANCH;
|
return BRANCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//decoding functionality
|
||||||
|
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compile_func 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 nullptr;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
|
template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
|
||||||
|
|
||||||
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) {
|
||||||
, instr_decoder([this]() {
|
root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
|
||||||
std::vector<generic_instruction_descriptor> g_instr_descr;
|
for(auto instr: instr_descr){
|
||||||
g_instr_descr.reserve(instr_descr.size());
|
root->instrs.push_back(instr);
|
||||||
for (uint32_t i = 0; i < instr_descr.size(); ++i) {
|
}
|
||||||
generic_instruction_descriptor new_instr_descr {instr_descr[i].value, instr_descr[i].mask, i};
|
populate_decoding_tree(root);
|
||||||
g_instr_descr.push_back(new_instr_descr);
|
}
|
||||||
}
|
|
||||||
return std::move(g_instr_descr);
|
|
||||||
}()) {}
|
|
||||||
|
|
||||||
template <typename ARCH>
|
template <typename ARCH>
|
||||||
continuation_e vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, jit_holder& jh) {
|
continuation_e vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, jit_holder& jh) {
|
||||||
@ -4766,10 +4827,7 @@ continuation_e vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned
|
|||||||
if (instr == 0x0000006f || (instr&0xffff)==0xa001)
|
if (instr == 0x0000006f || (instr&0xffff)==0xa001)
|
||||||
throw simulation_stopped(0); // 'J 0' or 'C.J 0'
|
throw simulation_stopped(0); // 'J 0' or 'C.J 0'
|
||||||
++inst_cnt;
|
++inst_cnt;
|
||||||
uint32_t inst_index = instr_decoder.decode_instr(instr);
|
auto f = decode_instr(root, instr);
|
||||||
compile_func f = nullptr;
|
|
||||||
if(inst_index < instr_descr.size())
|
|
||||||
f = instr_descr[inst_index].op;
|
|
||||||
if (f == nullptr)
|
if (f == nullptr)
|
||||||
f = &this_class::illegal_instruction;
|
f = &this_class::illegal_instruction;
|
||||||
return (this->*f)(pc, instr, jh);
|
return (this->*f)(pc, instr, jh);
|
||||||
|
@ -1,103 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright (C) 2024 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:
|
|
||||||
* alex@minres.com - initial implementation
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cassert>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <limits>
|
|
||||||
#include <numeric>
|
|
||||||
#include <vector>
|
|
||||||
#include <vm/instruction_decoder.h>
|
|
||||||
|
|
||||||
decoder::decoder(std::vector<generic_instruction_descriptor> instr_list) {
|
|
||||||
for(auto instr : instr_list) {
|
|
||||||
root.instrs.push_back(instr);
|
|
||||||
}
|
|
||||||
populate_decoding_tree(root);
|
|
||||||
}
|
|
||||||
|
|
||||||
void decoder::populate_decoding_tree(decoding_tree_node& parent) {
|
|
||||||
// create submask
|
|
||||||
parent.submask =
|
|
||||||
std::accumulate(parent.instrs.begin(), parent.instrs.end(), std::numeric_limits<uint32_t>::max(),
|
|
||||||
[](int current_submask, const generic_instruction_descriptor& instr) { return current_submask & instr.mask; });
|
|
||||||
// put each instr according to submask&encoding into children
|
|
||||||
for(auto instr : parent.instrs) {
|
|
||||||
bool foundMatch = false;
|
|
||||||
for(auto& child : parent.children) {
|
|
||||||
// use value as identifying trait
|
|
||||||
if(child.value == (instr.value & parent.submask)) {
|
|
||||||
child.instrs.push_back(instr);
|
|
||||||
foundMatch = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!foundMatch) {
|
|
||||||
decoding_tree_node child = decoding_tree_node(instr.value & parent.submask);
|
|
||||||
child.instrs.push_back(instr);
|
|
||||||
parent.children.push_back(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parent.instrs.clear();
|
|
||||||
// call populate_decoding_tree for all children
|
|
||||||
if(parent.children.size() > 1)
|
|
||||||
for(auto& child : parent.children) {
|
|
||||||
populate_decoding_tree(child);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// sort instrs by value of the mask, so we have the least restrictive mask last
|
|
||||||
std::sort(parent.children[0].instrs.begin(), parent.children[0].instrs.end(),
|
|
||||||
[](const generic_instruction_descriptor& instr1, const generic_instruction_descriptor& instr2) {
|
|
||||||
return instr1.mask > instr2.mask;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uint32_t decoder::decode_instr(uint32_t word) { return _decode_instr(this->root, word); }
|
|
||||||
uint32_t decoder::_decode_instr(decoding_tree_node const& node, uint32_t word) {
|
|
||||||
if(!node.children.size()) {
|
|
||||||
if(node.instrs.size() == 1)
|
|
||||||
return node.instrs[0].index;
|
|
||||||
for(auto instr : node.instrs) {
|
|
||||||
if((instr.mask & word) == instr.value)
|
|
||||||
return instr.index;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for(auto child : node.children) {
|
|
||||||
if(child.value == (node.submask & word)) {
|
|
||||||
return _decode_instr(child, word);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return std::numeric_limits<uint32_t>::max();
|
|
||||||
}
|
|
@ -1,63 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* Copyright (C) 2024 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:
|
|
||||||
* alex@minres.com - initial implementation
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <limits>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
struct generic_instruction_descriptor {
|
|
||||||
uint32_t value;
|
|
||||||
uint32_t mask;
|
|
||||||
uint32_t index;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct decoding_tree_node {
|
|
||||||
std::vector<generic_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) {}
|
|
||||||
};
|
|
||||||
class decoder {
|
|
||||||
public:
|
|
||||||
decoder(std::vector<generic_instruction_descriptor> instr_list);
|
|
||||||
uint32_t decode_instr(uint32_t word);
|
|
||||||
|
|
||||||
private:
|
|
||||||
decoding_tree_node root{decoding_tree_node(std::numeric_limits<uint32_t>::max())};
|
|
||||||
void populate_decoding_tree(decoding_tree_node& root);
|
|
||||||
uint32_t _decode_instr(decoding_tree_node const& node, uint32_t word);
|
|
||||||
};
|
|
@ -31,7 +31,6 @@
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
#include <cstdint>
|
|
||||||
#include <iss/arch/tgc5c.h>
|
#include <iss/arch/tgc5c.h>
|
||||||
#include <iss/debugger/gdb_session.h>
|
#include <iss/debugger/gdb_session.h>
|
||||||
#include <iss/debugger/server.h>
|
#include <iss/debugger/server.h>
|
||||||
@ -44,7 +43,6 @@
|
|||||||
#include <exception>
|
#include <exception>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vm/instruction_decoder.h>
|
|
||||||
|
|
||||||
#ifndef FMT_HEADER_ONLY
|
#ifndef FMT_HEADER_ONLY
|
||||||
#define FMT_HEADER_ONLY
|
#define FMT_HEADER_ONLY
|
||||||
@ -148,11 +146,20 @@ private:
|
|||||||
* start opcode definitions
|
* start opcode definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
struct instruction_descriptor {
|
struct instruction_descriptor {
|
||||||
uint32_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){}
|
||||||
|
};
|
||||||
|
|
||||||
|
decoding_tree_node* root {nullptr};
|
||||||
const std::array<instruction_descriptor, 87> instr_descr = {{
|
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},
|
||||||
@ -243,8 +250,6 @@ private:
|
|||||||
{16, 0b1100000000000010, 0b1110000000000011, arch::traits<ARCH>::opcode_e::C__SWSP},
|
{16, 0b1100000000000010, 0b1110000000000011, arch::traits<ARCH>::opcode_e::C__SWSP},
|
||||||
{16, 0b0000000000000000, 0b1111111111111111, arch::traits<ARCH>::opcode_e::DII},
|
{16, 0b0000000000000000, 0b1111111111111111, arch::traits<ARCH>::opcode_e::DII},
|
||||||
}};
|
}};
|
||||||
//needs to be declared after instr_descr
|
|
||||||
decoder instr_decoder;
|
|
||||||
|
|
||||||
iss::status fetch_ins(virt_addr_t pc, uint8_t * data){
|
iss::status fetch_ins(virt_addr_t pc, uint8_t * data){
|
||||||
if(this->core.has_mmu()) {
|
if(this->core.has_mmu()) {
|
||||||
@ -265,6 +270,58 @@ private:
|
|||||||
}
|
}
|
||||||
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) {
|
||||||
@ -290,16 +347,13 @@ 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) {
|
||||||
, instr_decoder([this]() {
|
root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
|
||||||
std::vector<generic_instruction_descriptor> g_instr_descr;
|
for(auto instr:instr_descr){
|
||||||
g_instr_descr.reserve(instr_descr.size());
|
root->instrs.push_back(instr);
|
||||||
for (uint32_t i = 0; i < instr_descr.size(); ++i) {
|
}
|
||||||
generic_instruction_descriptor new_instr_descr {instr_descr[i].value, instr_descr[i].mask, i};
|
populate_decoding_tree(root);
|
||||||
g_instr_descr.push_back(new_instr_descr);
|
}
|
||||||
}
|
|
||||||
return std::move(g_instr_descr);
|
|
||||||
}()) {}
|
|
||||||
|
|
||||||
inline bool is_icount_limit_enabled(finish_cond_e cond){
|
inline bool is_icount_limit_enabled(finish_cond_e cond){
|
||||||
return (cond & finish_cond_e::ICOUNT_LIMIT) == finish_cond_e::ICOUNT_LIMIT;
|
return (cond & finish_cond_e::ICOUNT_LIMIT) == finish_cond_e::ICOUNT_LIMIT;
|
||||||
@ -336,13 +390,9 @@ 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'
|
||||||
uint32_t inst_index = instr_decoder.decode_instr(instr);
|
auto inst_id = decode_instr(root, instr);
|
||||||
opcode_e inst_id = arch::traits<ARCH>::opcode_e::MAX_OPCODE;;
|
|
||||||
if(inst_index <instr_descr.size())
|
|
||||||
inst_id = instr_descr.at(instr_decoder.decode_instr(instr)).op;
|
|
||||||
|
|
||||||
// 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));
|
||||||
try{
|
try{
|
||||||
switch(inst_id){
|
switch(inst_id){
|
||||||
|
@ -36,7 +36,6 @@
|
|||||||
#include <iss/iss.h>
|
#include <iss/iss.h>
|
||||||
#include <iss/llvm/vm_base.h>
|
#include <iss/llvm/vm_base.h>
|
||||||
#include <util/logging.h>
|
#include <util/logging.h>
|
||||||
#include <vm/instruction_decoder.h>
|
|
||||||
|
|
||||||
#ifndef FMT_HEADER_ONLY
|
#ifndef FMT_HEADER_ONLY
|
||||||
#define FMT_HEADER_ONLY
|
#define FMT_HEADER_ONLY
|
||||||
@ -137,11 +136,20 @@ private:
|
|||||||
* start opcode definitions
|
* start opcode definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
struct instruction_descriptor {
|
struct instruction_descriptor {
|
||||||
uint32_t length;
|
size_t length;
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
uint32_t mask;
|
uint32_t mask;
|
||||||
compile_func op;
|
compile_func 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){}
|
||||||
|
};
|
||||||
|
|
||||||
|
decoding_tree_node* root {nullptr};
|
||||||
|
|
||||||
const std::array<instruction_descriptor, 87> instr_descr = {{
|
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 */
|
||||||
@ -321,9 +329,6 @@ private:
|
|||||||
{16, 0b0000000000000000, 0b1111111111111111, &this_class::__dii},
|
{16, 0b0000000000000000, 0b1111111111111111, &this_class::__dii},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
//needs to be declared after instr_descr
|
|
||||||
decoder instr_decoder;
|
|
||||||
|
|
||||||
/* instruction definitions */
|
/* instruction definitions */
|
||||||
/* instruction 0: LUI */
|
/* instruction 0: LUI */
|
||||||
std::tuple<continuation_e, BasicBlock*> __lui(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){
|
std::tuple<continuation_e, BasicBlock*> __lui(virt_addr_t& pc, code_word_t instr, BasicBlock* bb){
|
||||||
@ -4880,6 +4885,58 @@ private:
|
|||||||
this->builder.CreateBr(bb);
|
this->builder.CreateBr(bb);
|
||||||
return std::make_tuple(BRANCH, nullptr);
|
return std::make_tuple(BRANCH, nullptr);
|
||||||
}
|
}
|
||||||
|
//decoding functionality
|
||||||
|
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compile_func 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 nullptr;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename CODE_WORD> void debug_fn(CODE_WORD instr) {
|
template <typename CODE_WORD> void debug_fn(CODE_WORD instr) {
|
||||||
@ -4891,16 +4948,13 @@ template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
|
|||||||
|
|
||||||
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) {
|
||||||
, instr_decoder([this]() {
|
root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
|
||||||
std::vector<generic_instruction_descriptor> g_instr_descr;
|
for(auto instr:instr_descr){
|
||||||
g_instr_descr.reserve(instr_descr.size());
|
root->instrs.push_back(instr);
|
||||||
for (uint32_t i = 0; i < instr_descr.size(); ++i) {
|
}
|
||||||
generic_instruction_descriptor new_instr_descr {instr_descr[i].value, instr_descr[i].mask, i};
|
populate_decoding_tree(root);
|
||||||
g_instr_descr.push_back(new_instr_descr);
|
}
|
||||||
}
|
|
||||||
return std::move(g_instr_descr);
|
|
||||||
}()) {}
|
|
||||||
|
|
||||||
template <typename ARCH>
|
template <typename ARCH>
|
||||||
std::tuple<continuation_e, BasicBlock *>
|
std::tuple<continuation_e, BasicBlock *>
|
||||||
@ -4921,16 +4975,13 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
|
|||||||
// 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, data);
|
||||||
if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
|
if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
|
||||||
// }
|
// }
|
||||||
if (instr == 0x0000006f || (instr&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;
|
||||||
uint32_t inst_index = instr_decoder.decode_instr(instr);
|
auto f = decode_instr(root, instr);
|
||||||
compile_func f = nullptr;
|
|
||||||
if(inst_index < instr_descr.size())
|
|
||||||
f = instr_descr[inst_index].op;
|
|
||||||
if (f == nullptr) {
|
if (f == nullptr) {
|
||||||
f = &this_class::illegal_instruction;
|
f = &this_class::illegal_instruction;
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,6 @@
|
|||||||
#include <iss/tcc/vm_base.h>
|
#include <iss/tcc/vm_base.h>
|
||||||
#include <util/logging.h>
|
#include <util/logging.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vm/instruction_decoder.h>
|
|
||||||
|
|
||||||
#ifndef FMT_HEADER_ONLY
|
#ifndef FMT_HEADER_ONLY
|
||||||
#define FMT_HEADER_ONLY
|
#define FMT_HEADER_ONLY
|
||||||
@ -138,11 +137,20 @@ private:
|
|||||||
* start opcode definitions
|
* start opcode definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
struct instruction_descriptor {
|
struct instruction_descriptor {
|
||||||
uint32_t length;
|
size_t length;
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
uint32_t mask;
|
uint32_t mask;
|
||||||
compile_func op;
|
compile_func 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){}
|
||||||
|
};
|
||||||
|
|
||||||
|
decoding_tree_node* root {nullptr};
|
||||||
|
|
||||||
const std::array<instruction_descriptor, 87> instr_descr = {{
|
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 */
|
||||||
@ -322,9 +330,6 @@ private:
|
|||||||
{16, 0b0000000000000000, 0b1111111111111111, &this_class::__dii},
|
{16, 0b0000000000000000, 0b1111111111111111, &this_class::__dii},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
//needs to be declared after instr_descr
|
|
||||||
decoder instr_decoder;
|
|
||||||
|
|
||||||
/* instruction definitions */
|
/* instruction definitions */
|
||||||
/* instruction 0: LUI */
|
/* instruction 0: LUI */
|
||||||
compile_ret_t __lui(virt_addr_t& pc, code_word_t instr, tu_builder& tu){
|
compile_ret_t __lui(virt_addr_t& pc, code_word_t instr, tu_builder& tu){
|
||||||
@ -3632,6 +3637,59 @@ private:
|
|||||||
vm_impl::gen_trap_check(tu);
|
vm_impl::gen_trap_check(tu);
|
||||||
return BRANCH;
|
return BRANCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//decoding functionality
|
||||||
|
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compile_func 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 nullptr;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename CODE_WORD> void debug_fn(CODE_WORD instr) {
|
template <typename CODE_WORD> void debug_fn(CODE_WORD instr) {
|
||||||
@ -3643,16 +3701,13 @@ template <typename ARCH> vm_impl<ARCH>::vm_impl() { this(new ARCH()); }
|
|||||||
|
|
||||||
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) {
|
||||||
, instr_decoder([this]() {
|
root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
|
||||||
std::vector<generic_instruction_descriptor> g_instr_descr;
|
for(auto instr:instr_descr){
|
||||||
g_instr_descr.reserve(instr_descr.size());
|
root->instrs.push_back(instr);
|
||||||
for (uint32_t i = 0; i < instr_descr.size(); ++i) {
|
}
|
||||||
generic_instruction_descriptor new_instr_descr {instr_descr[i].value, instr_descr[i].mask, i};
|
populate_decoding_tree(root);
|
||||||
g_instr_descr.push_back(new_instr_descr);
|
}
|
||||||
}
|
|
||||||
return std::move(g_instr_descr);
|
|
||||||
}()) {}
|
|
||||||
|
|
||||||
template <typename ARCH>
|
template <typename ARCH>
|
||||||
std::tuple<continuation_e>
|
std::tuple<continuation_e>
|
||||||
@ -3671,16 +3726,13 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
|
|||||||
// 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, reinterpret_cast<uint8_t*>(&instr));
|
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 (instr == 0x0000006f || (instr&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;
|
||||||
uint32_t inst_index = instr_decoder.decode_instr(instr);
|
auto f = decode_instr(root, instr);
|
||||||
compile_func f = nullptr;
|
|
||||||
if(inst_index < instr_descr.size())
|
|
||||||
f = instr_descr[inst_index].op;
|
|
||||||
if (f == nullptr) {
|
if (f == nullptr) {
|
||||||
f = &this_class::illegal_instruction;
|
f = &this_class::illegal_instruction;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user