|
|
|
@ -55,10 +55,12 @@ using namespace iss::debugger;
|
|
|
|
|
|
|
|
|
|
template <typename ARCH> class vm_impl : public iss::tcc::vm_base<ARCH> {
|
|
|
|
|
public:
|
|
|
|
|
using traits = arch::traits<ARCH>;
|
|
|
|
|
using super = typename iss::tcc::vm_base<ARCH>;
|
|
|
|
|
using virt_addr_t = typename super::virt_addr_t;
|
|
|
|
|
using phys_addr_t = typename super::phys_addr_t;
|
|
|
|
|
using code_word_t = typename super::code_word_t;
|
|
|
|
|
using mem_type_e = typename traits::mem_type_e;
|
|
|
|
|
using addr_t = typename super::addr_t;
|
|
|
|
|
using tu_builder = typename super::tu_builder;
|
|
|
|
|
|
|
|
|
@ -82,7 +84,7 @@ protected:
|
|
|
|
|
using compile_ret_t = std::tuple<continuation_e>;
|
|
|
|
|
using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, tu_builder&);
|
|
|
|
|
|
|
|
|
|
inline const char *name(size_t index){return traits<ARCH>::reg_aliases.at(index);}
|
|
|
|
|
inline const char *name(size_t index){return traits::reg_aliases.at(index);}
|
|
|
|
|
|
|
|
|
|
void setup_module(std::string m) override {
|
|
|
|
|
super::setup_module(m);
|
|
|
|
@ -104,10 +106,10 @@ protected:
|
|
|
|
|
|
|
|
|
|
inline void gen_set_pc(tu_builder& tu, virt_addr_t pc, unsigned reg_num) {
|
|
|
|
|
switch(reg_num){
|
|
|
|
|
case traits<ARCH>::NEXT_PC:
|
|
|
|
|
case traits::NEXT_PC:
|
|
|
|
|
tu("*next_pc = {:#x};", pc.val);
|
|
|
|
|
break;
|
|
|
|
|
case traits<ARCH>::PC:
|
|
|
|
|
case traits::PC:
|
|
|
|
|
tu("*pc = {:#x};", pc.val);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
@ -123,7 +125,7 @@ protected:
|
|
|
|
|
// enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 };
|
|
|
|
|
enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 };
|
|
|
|
|
enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 };
|
|
|
|
|
enum { LUT_SIZE = 1 << util::bit_count(EXTR_MASK32), LUT_SIZE_C = 1 << util::bit_count(EXTR_MASK16) };
|
|
|
|
|
enum { LUT_SIZE = 1 << util::bit_count(static_cast<uint32_t>(EXTR_MASK32)), LUT_SIZE_C = 1 << util::bit_count(static_cast<uint32_t>(EXTR_MASK16)) };
|
|
|
|
|
|
|
|
|
|
std::array<compile_func, LUT_SIZE> lut;
|
|
|
|
|
|
|
|
|
@ -170,6 +172,12 @@ protected:
|
|
|
|
|
}
|
|
|
|
|
return lut_val;
|
|
|
|
|
}
|
|
|
|
|
template<unsigned W, typename U, typename S = typename std::make_signed<U>::type>
|
|
|
|
|
inline S sext(U from) {
|
|
|
|
|
auto mask = (1ULL<<W) - 1;
|
|
|
|
|
auto sign_mask = 1ULL<<(W-1);
|
|
|
|
|
return (from & mask) | ((from & sign_mask) ? ~mask : 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
/****************************************************************************
|
|
|
|
@ -185,13 +193,26 @@ private:
|
|
|
|
|
const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
|
|
|
|
|
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
|
|
|
|
/* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */
|
|
|
|
|
{${instr.length}, 0b${instr.value}, 0b${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
|
|
|
|
|
{${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
|
|
|
|
|
}};
|
|
|
|
|
|
|
|
|
|
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
|
|
|
|
|
/* instruction ${idx}: ${instr.name} */
|
|
|
|
|
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, tu_builder& tu){<%instr.code.eachLine{%>
|
|
|
|
|
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, tu_builder& tu){
|
|
|
|
|
tu("${instr.name}_{:#010x}:", pc.val);
|
|
|
|
|
vm_base<ARCH>::gen_sync(tu, PRE_SYNC,${idx});
|
|
|
|
|
<%instr.fields.eachLine{%>${it}
|
|
|
|
|
<%}%>if(this->disass_enabled){
|
|
|
|
|
/* generate console output when executing the command */<%instr.disass.eachLine{%>
|
|
|
|
|
${it}<%}%>
|
|
|
|
|
}
|
|
|
|
|
auto cur_pc_val = tu.constant(pc.val, traits::reg_bit_widths[traits::PC]);
|
|
|
|
|
pc=pc+4;
|
|
|
|
|
tu.open_scope();<%instr.behavior.eachLine{%>
|
|
|
|
|
${it}<%}%>
|
|
|
|
|
vm_base<ARCH>::gen_sync(tu, POST_SYNC,${idx});
|
|
|
|
|
gen_trap_check(tu);
|
|
|
|
|
return returnValue;
|
|
|
|
|
}
|
|
|
|
|
<%}%>
|
|
|
|
|
/****************************************************************************
|
|
|
|
@ -233,7 +254,7 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
|
|
|
|
|
// we fetch at max 4 byte, alignment is 2
|
|
|
|
|
enum {TRAP_ID=1<<16};
|
|
|
|
|
code_word_t insn = 0;
|
|
|
|
|
const typename traits<ARCH>::addr_t upper_bits = ~traits<ARCH>::PGMASK;
|
|
|
|
|
const typename traits::addr_t upper_bits = ~traits::PGMASK;
|
|
|
|
|
phys_addr_t paddr(pc);
|
|
|
|
|
auto *const data = (uint8_t *)&insn;
|
|
|
|
|
paddr = this->core.v2p(pc);
|
|
|
|
@ -260,13 +281,13 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
|
|
|
|
|
|
|
|
|
|
template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) {
|
|
|
|
|
tu(" *trap_state = {:#x};", 0x80 << 24 | (cause << 16) | trap_id);
|
|
|
|
|
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32),traits<ARCH>::LAST_BRANCH);
|
|
|
|
|
tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(), 32));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(tu_builder& tu, unsigned lvl) {
|
|
|
|
|
tu("leave_trap(core_ptr, {});", lvl);
|
|
|
|
|
tu.store(tu.read_mem(traits<ARCH>::CSR, (lvl << 8) + 0x41, traits<ARCH>::XLEN),traits<ARCH>::NEXT_PC);
|
|
|
|
|
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32),traits<ARCH>::LAST_BRANCH);
|
|
|
|
|
tu.store(traits::NEXT_PC, tu.read_mem(traits::CSR, (lvl << 8) + 0x41, traits::XLEN));
|
|
|
|
|
tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(), 32));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned type) {
|
|
|
|
@ -274,8 +295,8 @@ template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned t
|
|
|
|
|
|
|
|
|
|
template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(tu_builder& tu) {
|
|
|
|
|
tu("trap_entry:");
|
|
|
|
|
tu("enter_trap(core_ptr, *trap_state, *pc);");
|
|
|
|
|
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(),32),traits<ARCH>::LAST_BRANCH);
|
|
|
|
|
tu("enter_trap(core_ptr, *trap_state, *pc, 0);");
|
|
|
|
|
tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(),32));
|
|
|
|
|
tu("return *next_pc;");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|