Compare commits
3 Commits
86de536c8f
...
c6b99cd155
Author | SHA1 | Date | |
---|---|---|---|
c6b99cd155 | |||
b1306c3a47 | |||
0d6bf924ed |
@ -96,6 +96,7 @@ protected:
|
|||||||
using compile_func = continuation_e (this_class::*)(virt_addr_t&, code_word_t, jit_holder&);
|
using compile_func = continuation_e (this_class::*)(virt_addr_t&, code_word_t, jit_holder&);
|
||||||
|
|
||||||
continuation_e gen_single_inst_behavior(virt_addr_t&, unsigned int &, jit_holder&) override;
|
continuation_e gen_single_inst_behavior(virt_addr_t&, unsigned int &, jit_holder&) override;
|
||||||
|
enum globals_e {TVAL = 0, GLOBALS_SIZE};
|
||||||
void gen_block_prologue(jit_holder& jh) override;
|
void gen_block_prologue(jit_holder& jh) override;
|
||||||
void gen_block_epilogue(jit_holder& jh) override;
|
void gen_block_epilogue(jit_holder& jh) override;
|
||||||
inline const char *name(size_t index){return traits::reg_aliases.at(index);}
|
inline const char *name(size_t index){return traits::reg_aliases.at(index);}
|
||||||
@ -261,7 +262,8 @@ template <typename ARCH>
|
|||||||
void vm_impl<ARCH>::gen_block_prologue(jit_holder& jh){
|
void vm_impl<ARCH>::gen_block_prologue(jit_holder& jh){
|
||||||
jh.pc = load_reg_from_mem_Gp(jh, traits::PC);
|
jh.pc = load_reg_from_mem_Gp(jh, traits::PC);
|
||||||
jh.next_pc = load_reg_from_mem_Gp(jh, traits::NEXT_PC);
|
jh.next_pc = load_reg_from_mem_Gp(jh, traits::NEXT_PC);
|
||||||
jh.globals["tval"] = get_reg_Gp(jh.cc, 64, false);
|
jh.globals.resize(GLOBALS_SIZE);
|
||||||
|
jh.globals[TVAL] = get_reg_Gp(jh.cc, 64, false);
|
||||||
}
|
}
|
||||||
template <typename ARCH>
|
template <typename ARCH>
|
||||||
void vm_impl<ARCH>::gen_block_epilogue(jit_holder& jh){
|
void vm_impl<ARCH>::gen_block_epilogue(jit_holder& jh){
|
||||||
@ -284,7 +286,7 @@ void vm_impl<ARCH>::gen_block_epilogue(jit_holder& jh){
|
|||||||
call_enter_trap->setArg(0, jh.arch_if_ptr);
|
call_enter_trap->setArg(0, jh.arch_if_ptr);
|
||||||
call_enter_trap->setArg(1, current_trap_state);
|
call_enter_trap->setArg(1, current_trap_state);
|
||||||
call_enter_trap->setArg(2, current_pc);
|
call_enter_trap->setArg(2, current_pc);
|
||||||
call_enter_trap->setArg(3, jh.globals["tval"]);
|
call_enter_trap->setArg(3, jh.globals[TVAL]);
|
||||||
|
|
||||||
x86_reg_t current_next_pc = get_reg_for(cc, traits::NEXT_PC);
|
x86_reg_t current_next_pc = get_reg_for(cc, traits::NEXT_PC);
|
||||||
mov(cc, current_next_pc, get_ptr_for(jh, traits::NEXT_PC));
|
mov(cc, current_next_pc, get_ptr_for(jh, traits::NEXT_PC));
|
||||||
@ -304,7 +306,7 @@ inline void vm_impl<ARCH>::gen_raise(jit_holder& jh, uint16_t trap_id, uint16_t
|
|||||||
template <typename ARCH>
|
template <typename ARCH>
|
||||||
template <typename T, typename>
|
template <typename T, typename>
|
||||||
void vm_impl<ARCH>::gen_set_tval(jit_holder& jh, T new_tval) {
|
void vm_impl<ARCH>::gen_set_tval(jit_holder& jh, T new_tval) {
|
||||||
mov(jh.cc, jh.globals["tval"], new_tval);
|
mov(jh.cc, jh.globals[TVAL], new_tval);
|
||||||
}
|
}
|
||||||
template <typename ARCH>
|
template <typename ARCH>
|
||||||
void vm_impl<ARCH>::gen_set_tval(jit_holder& jh, x86_reg_t _new_tval) {
|
void vm_impl<ARCH>::gen_set_tval(jit_holder& jh, x86_reg_t _new_tval) {
|
||||||
@ -312,7 +314,7 @@ void vm_impl<ARCH>::gen_set_tval(jit_holder& jh, x86_reg_t _new_tval) {
|
|||||||
x86::Gp new_tval = std::get<x86::Gp>(_new_tval);
|
x86::Gp new_tval = std::get<x86::Gp>(_new_tval);
|
||||||
if(new_tval.size() < 8)
|
if(new_tval.size() < 8)
|
||||||
new_tval = gen_ext_Gp(jh.cc, new_tval, 64, false);
|
new_tval = gen_ext_Gp(jh.cc, new_tval, 64, false);
|
||||||
mov(jh.cc, jh.globals["tval"], new_tval);
|
mov(jh.cc, jh.globals[TVAL], new_tval);
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("Variant not supported in gen_set_tval");
|
throw std::runtime_error("Variant not supported in gen_set_tval");
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@ def nativeTypeSize(int size){
|
|||||||
}
|
}
|
||||||
%>
|
%>
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
#include <cstdint>
|
||||||
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
|
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
|
||||||
#include <iss/debugger/gdb_session.h>
|
#include <iss/debugger/gdb_session.h>
|
||||||
#include <iss/debugger/server.h>
|
#include <iss/debugger/server.h>
|
||||||
@ -47,6 +48,8 @@ def nativeTypeSize(int size){
|
|||||||
#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
|
||||||
@ -152,25 +155,20 @@ private:
|
|||||||
* start opcode definitions
|
* start opcode definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
struct instruction_descriptor {
|
struct instruction_descriptor {
|
||||||
size_t length;
|
uint32_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, ${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 -> %>
|
||||||
{${instr.length}, ${instr.encoding}, ${instr.mask}, arch::traits<ARCH>::opcode_e::${instr.instruction.name}},<%}%>
|
{${instr.length}, ${instr.encoding}, ${instr.mask}, arch::traits<ARCH>::opcode_e::${instr.instruction.name}},<%}%>
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
//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()) {
|
||||||
auto phys_pc = this->core.virt2phys(pc);
|
auto phys_pc = this->core.virt2phys(pc);
|
||||||
@ -190,58 +188,6 @@ 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) {
|
||||||
@ -267,13 +213,16 @@ 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)
|
||||||
root = new decoding_tree_node(std::numeric_limits<uint32_t>::max());
|
, instr_decoder([this]() {
|
||||||
for(auto instr:instr_descr){
|
std::vector<generic_instruction_descriptor> g_instr_descr;
|
||||||
root->instrs.push_back(instr);
|
g_instr_descr.reserve(instr_descr.size());
|
||||||
}
|
for (uint32_t i = 0; i < instr_descr.size(); ++i) {
|
||||||
populate_decoding_tree(root);
|
generic_instruction_descriptor new_instr_descr {instr_descr[i].value, instr_descr[i].mask, i};
|
||||||
}
|
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;
|
||||||
@ -310,9 +259,13 @@ 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_instr(root, instr);
|
uint32_t inst_index = instr_decoder.decode_instr(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){<%instructions.eachWithIndex{instr, idx -> %>
|
switch(inst_id){<%instructions.eachWithIndex{instr, idx -> %>
|
||||||
|
@ -96,6 +96,7 @@ protected:
|
|||||||
using compile_func = continuation_e (this_class::*)(virt_addr_t&, code_word_t, jit_holder&);
|
using compile_func = continuation_e (this_class::*)(virt_addr_t&, code_word_t, jit_holder&);
|
||||||
|
|
||||||
continuation_e gen_single_inst_behavior(virt_addr_t&, unsigned int &, jit_holder&) override;
|
continuation_e gen_single_inst_behavior(virt_addr_t&, unsigned int &, jit_holder&) override;
|
||||||
|
enum globals_e {TVAL = 0, GLOBALS_SIZE};
|
||||||
void gen_block_prologue(jit_holder& jh) override;
|
void gen_block_prologue(jit_holder& jh) override;
|
||||||
void gen_block_epilogue(jit_holder& jh) override;
|
void gen_block_epilogue(jit_holder& jh) override;
|
||||||
inline const char *name(size_t index){return traits::reg_aliases.at(index);}
|
inline const char *name(size_t index){return traits::reg_aliases.at(index);}
|
||||||
@ -4801,7 +4802,8 @@ template <typename ARCH>
|
|||||||
void vm_impl<ARCH>::gen_block_prologue(jit_holder& jh){
|
void vm_impl<ARCH>::gen_block_prologue(jit_holder& jh){
|
||||||
jh.pc = load_reg_from_mem_Gp(jh, traits::PC);
|
jh.pc = load_reg_from_mem_Gp(jh, traits::PC);
|
||||||
jh.next_pc = load_reg_from_mem_Gp(jh, traits::NEXT_PC);
|
jh.next_pc = load_reg_from_mem_Gp(jh, traits::NEXT_PC);
|
||||||
jh.globals["tval"] = get_reg_Gp(jh.cc, 64, false);
|
jh.globals.resize(GLOBALS_SIZE);
|
||||||
|
jh.globals[TVAL] = get_reg_Gp(jh.cc, 64, false);
|
||||||
}
|
}
|
||||||
template <typename ARCH>
|
template <typename ARCH>
|
||||||
void vm_impl<ARCH>::gen_block_epilogue(jit_holder& jh){
|
void vm_impl<ARCH>::gen_block_epilogue(jit_holder& jh){
|
||||||
@ -4824,7 +4826,7 @@ void vm_impl<ARCH>::gen_block_epilogue(jit_holder& jh){
|
|||||||
call_enter_trap->setArg(0, jh.arch_if_ptr);
|
call_enter_trap->setArg(0, jh.arch_if_ptr);
|
||||||
call_enter_trap->setArg(1, current_trap_state);
|
call_enter_trap->setArg(1, current_trap_state);
|
||||||
call_enter_trap->setArg(2, current_pc);
|
call_enter_trap->setArg(2, current_pc);
|
||||||
call_enter_trap->setArg(3, jh.globals["tval"]);
|
call_enter_trap->setArg(3, jh.globals[TVAL]);
|
||||||
|
|
||||||
x86_reg_t current_next_pc = get_reg_for(cc, traits::NEXT_PC);
|
x86_reg_t current_next_pc = get_reg_for(cc, traits::NEXT_PC);
|
||||||
mov(cc, current_next_pc, get_ptr_for(jh, traits::NEXT_PC));
|
mov(cc, current_next_pc, get_ptr_for(jh, traits::NEXT_PC));
|
||||||
@ -4844,7 +4846,7 @@ inline void vm_impl<ARCH>::gen_raise(jit_holder& jh, uint16_t trap_id, uint16_t
|
|||||||
template <typename ARCH>
|
template <typename ARCH>
|
||||||
template <typename T, typename>
|
template <typename T, typename>
|
||||||
void vm_impl<ARCH>::gen_set_tval(jit_holder& jh, T new_tval) {
|
void vm_impl<ARCH>::gen_set_tval(jit_holder& jh, T new_tval) {
|
||||||
mov(jh.cc, jh.globals["tval"], new_tval);
|
mov(jh.cc, jh.globals[TVAL], new_tval);
|
||||||
}
|
}
|
||||||
template <typename ARCH>
|
template <typename ARCH>
|
||||||
void vm_impl<ARCH>::gen_set_tval(jit_holder& jh, x86_reg_t _new_tval) {
|
void vm_impl<ARCH>::gen_set_tval(jit_holder& jh, x86_reg_t _new_tval) {
|
||||||
@ -4852,7 +4854,7 @@ void vm_impl<ARCH>::gen_set_tval(jit_holder& jh, x86_reg_t _new_tval) {
|
|||||||
x86::Gp new_tval = std::get<x86::Gp>(_new_tval);
|
x86::Gp new_tval = std::get<x86::Gp>(_new_tval);
|
||||||
if(new_tval.size() < 8)
|
if(new_tval.size() < 8)
|
||||||
new_tval = gen_ext_Gp(jh.cc, new_tval, 64, false);
|
new_tval = gen_ext_Gp(jh.cc, new_tval, 64, false);
|
||||||
mov(jh.cc, jh.globals["tval"], new_tval);
|
mov(jh.cc, jh.globals[TVAL], new_tval);
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("Variant not supported in gen_set_tval");
|
throw std::runtime_error("Variant not supported in gen_set_tval");
|
||||||
}
|
}
|
||||||
|
@ -85,15 +85,13 @@ void decoder::populate_decoding_tree(decoding_tree_node& parent) {
|
|||||||
}
|
}
|
||||||
uint32_t decoder::decode_instr(uint32_t word) { return _decode_instr(this->root, word); }
|
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) {
|
uint32_t decoder::_decode_instr(decoding_tree_node const& node, uint32_t word) {
|
||||||
if(!node.children.size()) {
|
if(!node.instrs.empty()) {
|
||||||
if(node.instrs.size() == 1)
|
for(auto& instr : node.instrs) {
|
||||||
return node.instrs[0].index;
|
|
||||||
for(auto instr : node.instrs) {
|
|
||||||
if((instr.mask & word) == instr.value)
|
if((instr.mask & word) == instr.value)
|
||||||
return instr.index;
|
return instr.index;
|
||||||
}
|
}
|
||||||
} else {
|
} else if(!node.children.empty()) {
|
||||||
for(auto child : node.children) {
|
for(auto& child : node.children) {
|
||||||
if(child.value == (node.submask & word)) {
|
if(child.value == (node.submask & word)) {
|
||||||
return _decode_instr(child, word);
|
return _decode_instr(child, word);
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vm/instruction_decoder.h>
|
#include <vm/instruction_decoder.h>
|
||||||
|
|
||||||
|
|
||||||
#ifndef FMT_HEADER_ONLY
|
#ifndef FMT_HEADER_ONLY
|
||||||
#define FMT_HEADER_ONLY
|
#define FMT_HEADER_ONLY
|
||||||
#endif
|
#endif
|
||||||
@ -153,6 +154,7 @@ private:
|
|||||||
uint32_t mask;
|
uint32_t mask;
|
||||||
typename arch::traits<ARCH>::opcode_e op;
|
typename arch::traits<ARCH>::opcode_e op;
|
||||||
};
|
};
|
||||||
|
|
||||||
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,6 +245,7 @@ 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
|
//needs to be declared after instr_descr
|
||||||
decoder instr_decoder;
|
decoder instr_decoder;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user