adds functionality, adds working asmjit

This commit is contained in:
Eyck-Alexander Jentzsch 2023-11-20 11:45:52 +01:00
parent e48597b2b7
commit 0eb1db0e7e
5 changed files with 2114 additions and 1883 deletions

View File

@ -320,6 +320,8 @@ protected:
unsigned get_reg_num() override { return traits<BASE>::NUM_REGS; } unsigned get_reg_num() override { return traits<BASE>::NUM_REGS; }
unsigned get_reg_size(unsigned num) override { return traits<BASE>::reg_bit_widths[num]; }
riscv_hart_m_p<BASE, FEAT>& arch; riscv_hart_m_p<BASE, FEAT>& arch;
}; };
@ -822,7 +824,8 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
x |= 0x80; // set pll lock upon writing x |= 0x80; // set pll lock upon writing
return iss::Ok; return iss::Ok;
} break; } break;
default: {} default: {
}
} }
} break; } break;
case traits<BASE>::CSR: { case traits<BASE>::CSR: {

View File

@ -371,6 +371,8 @@ protected:
unsigned get_reg_num() override { return traits<BASE>::NUM_REGS; } unsigned get_reg_num() override { return traits<BASE>::NUM_REGS; }
unsigned get_reg_size(unsigned num) override { return traits<BASE>::reg_bit_widths[num]; }
riscv_hart_msu_vp<BASE>& arch; riscv_hart_msu_vp<BASE>& arch;
}; };
@ -802,7 +804,8 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
x |= 0x80; // set pll lock upon writing x |= 0x80; // set pll lock upon writing
return iss::Ok; return iss::Ok;
} break; } break;
default: {} default: {
}
} }
} break; } break;
case traits<BASE>::CSR: { case traits<BASE>::CSR: {
@ -1225,9 +1228,9 @@ template <typename BASE> typename riscv_hart_msu_vp<BASE>::phys_addr_t riscv_har
break; break;
} else if(!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) { } else if(!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) {
break; break;
} else if(type == iss::access_type::FETCH ? !(pte & PTE_X) } else if(type == iss::access_type::FETCH ? !(pte & PTE_X)
: type == iss::access_type::READ ? !(pte & PTE_R) && !(mxr && (pte & PTE_X)) : type == iss::access_type::READ ? !(pte & PTE_R) && !(mxr && (pte & PTE_X))
: !((pte & PTE_R) && (pte & PTE_W))) { : !((pte & PTE_R) && (pte & PTE_W))) {
break; break;
} else if((ppn & ((reg_t(1) << ptshift) - 1)) != 0) { } else if((ppn & ((reg_t(1) << ptshift) - 1)) != 0) {
break; break;

View File

@ -347,6 +347,8 @@ protected:
unsigned get_reg_num() override { return traits<BASE>::NUM_REGS; } unsigned get_reg_num() override { return traits<BASE>::NUM_REGS; }
unsigned get_reg_size(unsigned num) override { return traits<BASE>::reg_bit_widths[num]; }
riscv_hart_mu_p<BASE, FEAT>& arch; riscv_hart_mu_p<BASE, FEAT>& arch;
}; };
@ -1005,7 +1007,8 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
x |= 0x80; // set pll lock upon writing x |= 0x80; // set pll lock upon writing
return iss::Ok; return iss::Ok;
} break; } break;
default: {} default: {
}
} }
} break; } break;
case traits<BASE>::CSR: { case traits<BASE>::CSR: {

View File

@ -19,7 +19,7 @@ x86::Mem get_reg_ptr(jit_holder& jh, unsigned idx) {
} }
} }
x86::Gp get_reg_for(jit_holder& jh, unsigned idx) { x86::Gp get_reg_for(jit_holder& jh, unsigned idx) {
// can check for regs in jh and return them instead of creating new ones // TODO can check for regs in jh and return them instead of creating new ones
switch(traits::reg_bit_widths[idx]) { switch(traits::reg_bit_widths[idx]) {
case 8: case 8:
return jh.cc.newInt8(); return jh.cc.newInt8();
@ -82,7 +82,9 @@ void gen_instr_prologue(jit_holder& jh, addr_t pc) {
cc.mov(get_reg_ptr(jh, traits::PC), jh.next_pc); cc.mov(get_reg_ptr(jh, traits::PC), jh.next_pc);
cc.comment("\n//*trap_state=*pending_trap;"); cc.comment("\n//*trap_state=*pending_trap;");
cc.mov(get_reg_ptr(jh, traits::PENDING_TRAP), jh.trap_state); x86::Gp current_trap_state = get_reg_for(jh, traits::TRAP_STATE);
cc.mov(current_trap_state, get_reg_ptr(jh, traits::TRAP_STATE));
cc.mov(get_reg_ptr(jh, traits::PENDING_TRAP), current_trap_state);
cc.comment("\n//increment *next_pc"); cc.comment("\n//increment *next_pc");
cc.mov(jh.next_pc, pc); cc.mov(jh.next_pc, pc);
@ -91,20 +93,20 @@ void gen_instr_epilogue(jit_holder& jh) {
auto& cc = jh.cc; auto& cc = jh.cc;
cc.comment("\n//if(*trap_state!=0) goto trap_entry;"); cc.comment("\n//if(*trap_state!=0) goto trap_entry;");
cc.test(jh.trap_state, jh.trap_state); x86::Gp current_trap_state = get_reg_for(jh, traits::TRAP_STATE);
cc.jnz(jh.trap_entry); cc.mov(current_trap_state, get_reg_ptr(jh, traits::TRAP_STATE));
cc.cmp(current_trap_state, 0);
cc.jne(jh.trap_entry);
// Does this need to be done after every single instruction? // TODO: Does not need to be done for every instruction, only when needed
cc.comment("\n//write back regs to mem"); cc.comment("\n//write back regs to mem");
write_reg_to_mem(jh, jh.pc, traits::PC); write_reg_to_mem(jh, jh.pc, traits::PC);
write_reg_to_mem(jh, jh.next_pc, traits::NEXT_PC); write_reg_to_mem(jh, jh.next_pc, traits::NEXT_PC);
write_reg_to_mem(jh, jh.trap_state, traits::TRAP_STATE);
} }
void gen_block_prologue(jit_holder& jh) override { void gen_block_prologue(jit_holder& jh) override {
jh.pc = load_reg_from_mem(jh, traits::PC); jh.pc = load_reg_from_mem(jh, traits::PC);
jh.next_pc = load_reg_from_mem(jh, traits::NEXT_PC); jh.next_pc = load_reg_from_mem(jh, traits::NEXT_PC);
jh.trap_state = load_reg_from_mem(jh, traits::TRAP_STATE);
} }
void gen_block_epilogue(jit_holder& jh) override { void gen_block_epilogue(jit_holder& jh) override {
x86::Compiler& cc = jh.cc; x86::Compiler& cc = jh.cc;
@ -112,7 +114,12 @@ void gen_block_epilogue(jit_holder& jh) override {
cc.ret(jh.next_pc); cc.ret(jh.next_pc);
cc.bind(jh.trap_entry); cc.bind(jh.trap_entry);
cc.comment("\n//enter_trap(core_ptr, *trap_state, *pc, 0);"); cc.comment("\n//Prepare for enter_trap;");
// Make sure cached values are written back
cc.comment("\n//write back regs to mem");
write_reg_to_mem(jh, jh.pc, traits::PC);
write_reg_to_mem(jh, jh.next_pc, traits::NEXT_PC);
this->gen_sync(jh, POST_SYNC, -1);
x86::Gp current_trap_state = get_reg_for(jh, traits::TRAP_STATE); x86::Gp current_trap_state = get_reg_for(jh, traits::TRAP_STATE);
cc.mov(current_trap_state, get_reg_ptr(jh, traits::TRAP_STATE)); cc.mov(current_trap_state, get_reg_ptr(jh, traits::TRAP_STATE));
@ -121,23 +128,43 @@ void gen_block_epilogue(jit_holder& jh) override {
cc.mov(current_pc, get_reg_ptr(jh, traits::PC)); cc.mov(current_pc, get_reg_ptr(jh, traits::PC));
x86::Gp instr = cc.newInt32("instr"); x86::Gp instr = cc.newInt32("instr");
cc.mov(instr, 0); cc.mov(instr, 0); // this is not correct
cc.comment("\n//enter trap call;");
InvokeNode* call_enter_trap; InvokeNode* call_enter_trap;
cc.invoke(&call_enter_trap, &enter_trap, FuncSignatureT<uint64_t, void*, uint64_t, uint64_t, uint64_t>()); cc.invoke(&call_enter_trap, &enter_trap, FuncSignatureT<uint64_t, void*, uint64_t, uint64_t, uint64_t>());
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, instr); call_enter_trap->setArg(3, instr);
x86::Gp current_next_pc = get_reg_for(jh, traits::NEXT_PC);
cc.mov(current_next_pc, get_reg_ptr(jh, traits::NEXT_PC));
cc.mov(jh.next_pc, current_next_pc);
cc.comment("\n//*last_branch = std::numeric_limits<uint32_t>::max();"); cc.comment("\n//*last_branch = std::numeric_limits<uint32_t>::max();");
cc.mov(get_reg_ptr(jh, traits::LAST_BRANCH), std::numeric_limits<uint32_t>::max()); cc.mov(get_reg_ptr(jh, traits::LAST_BRANCH), std::numeric_limits<uint32_t>::max());
cc.comment("\n//return *next_pc;"); cc.comment("\n//return *next_pc;");
cc.ret(jh.next_pc); cc.ret(jh.next_pc);
} }
// TODO implement /*
inline void raise(uint16_t trap_id, uint16_t cause){
void gen_raise(jit_holder& jh, uint16_t trap_id, uint16_t cause) { jh.cc.comment("//gen_raise"); } auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id;
void gen_wait(jit_holder& jh, unsigned type) { jh.cc.comment("//gen_wait"); } this->core.reg.trap_state = trap_val;
void gen_leave(jit_holder& jh, unsigned lvl) { jh.cc.comment("//gen_leave"); } this->template get_reg<uint32_t>(traits::NEXT_PC) = std::numeric_limits<uint32_t>::max();
}
*/
inline void gen_raise(jit_holder& jh, uint16_t trap_id, uint16_t cause) {
auto& cc = jh.cc;
cc.comment("//gen_raise");
auto tmp1 = get_reg_for(jh, traits::TRAP_STATE);
cc.mov(tmp1, 0x80ULL << 24 | (cause << 16) | trap_id);
cc.mov(get_reg_ptr(jh, traits::TRAP_STATE), tmp1);
auto tmp2 = get_reg_for(jh, traits::NEXT_PC);
cc.mov(tmp2, std::numeric_limits<uint32_t>::max());
cc.mov(get_reg_ptr(jh, traits::NEXT_PC), tmp2);
}
inline void gen_wait(jit_holder& jh, unsigned type) { jh.cc.comment("//gen_wait"); }
inline void gen_leave(jit_holder& jh, unsigned lvl) { jh.cc.comment("//gen_leave"); }
enum operation { add, sub, band, bor, bxor, shl, sar, shr }; enum operation { add, sub, band, bor, bxor, shl, sar, shr };
@ -342,24 +369,12 @@ x86::Gp gen_operation(jit_holder& jh, binary_operation op, x86::Gp a) {
return a; return a;
} }
/* template <typename T>
inline typename std::enable_if_t<std::is_unsigned<T>::value, x86::Gp> gen_ext(jit_holder& jh, T val, unsigned size, bool
is_signed) const { auto val_reg = get_reg_for(jh, sizeof(val)*8); auto tmp = get_reg_for(jh, size); jh.cc.mov(val_reg,
val); if(is_signed) jh.cc.movsx(tmp, val_reg); else jh.cc.movzx(tmp,val_reg); return tmp;
}
template <typename T>
inline typename std::enable_if_t<std::is_signed<T>::value, x86::Gp> gen_ext(jit_holder& jh, T val, unsigned size, bool
is_signed) const { auto val_reg = get_reg_for(jh, sizeof(val)*8); auto tmp = get_reg_for(jh, size); jh.cc.mov(val_reg,
val); if(is_signed) jh.cc.movsx(tmp, val_reg); else jh.cc.movzx(tmp,val_reg); return tmp;
} */
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>> template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
inline x86::Gp gen_ext(jit_holder& jh, T val, unsigned size, bool is_signed) { inline x86::Gp gen_ext(jit_holder& jh, T val, unsigned size, bool is_signed) {
auto val_reg = get_reg_for(jh, sizeof(val) * 8); auto val_reg = get_reg_for(jh, sizeof(val) * 8, is_signed);
jh.cc.mov(val_reg, val); jh.cc.mov(val_reg, val);
return gen_ext(jh, val_reg, size, is_signed); return gen_ext(jh, val_reg, size, is_signed);
} }
// explicit Gp size cast
inline x86::Gp gen_ext(jit_holder& jh, x86::Gp val, unsigned size, bool is_signed) { inline x86::Gp gen_ext(jit_holder& jh, x86::Gp val, unsigned size, bool is_signed) {
auto& cc = jh.cc; auto& cc = jh.cc;
if(is_signed) { if(is_signed) {
@ -398,7 +413,6 @@ inline x86::Gp gen_ext(jit_holder& jh, x86::Gp val, unsigned size, bool is_signe
throw std::runtime_error("Invalid size in gen_ext"); throw std::runtime_error("Invalid size in gen_ext");
} }
} }
inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, uint32_t length) { inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, uint32_t length) {
x86::Compiler& cc = jh.cc; x86::Compiler& cc = jh.cc;
auto ret_reg = cc.newInt32(); auto ret_reg = cc.newInt32();
@ -447,31 +461,18 @@ inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, uint3
invokeNode->setArg(2, mem_type_reg); invokeNode->setArg(2, mem_type_reg);
invokeNode->setArg(3, addr); invokeNode->setArg(3, addr);
invokeNode->setArg(4, val_ptr); invokeNode->setArg(4, val_ptr);
cc.cmp(ret_reg, 0);
cc.jne(jh.trap_entry);
cc.mov(val_reg, x86::ptr_64(val_ptr)); cc.mov(val_reg, x86::ptr_64(val_ptr));
cc.and_(val_reg, mask); cc.and_(val_reg, mask);
cc.cmp(ret_reg, 0);
cc.jne(jh.trap_entry);
return val_reg; return val_reg;
} }
inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, x86::Gp length) { inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, x86::Gp length) {
uint32_t length_val = 0; throw std::runtime_error("Invalid gen_read_mem");
auto length_ptr = jh.cc.newIntPtr();
jh.cc.mov(length_ptr, &length_val);
jh.cc.mov(x86::ptr_32(length_ptr), length);
return gen_read_mem(jh, type, addr, length);
} }
inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, uint64_t addr, x86::Gp length) { inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, uint64_t addr, x86::Gp length) {
auto addr_reg = jh.cc.newInt64(); throw std::runtime_error("Invalid gen_read_mem");
jh.cc.mov(addr_reg, addr);
uint32_t length_val = 0;
auto length_ptr = jh.cc.newIntPtr();
jh.cc.mov(length_ptr, &length_val);
jh.cc.mov(x86::ptr_32(length_ptr), length);
return gen_read_mem(jh, type, addr_reg, length_val);
} }
inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, uint64_t addr, uint32_t length) { inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, uint64_t addr, uint32_t length) {
auto addr_reg = jh.cc.newInt64(); auto addr_reg = jh.cc.newInt64();
@ -479,32 +480,38 @@ inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, uint64_t addr, uint
return gen_read_mem(jh, type, addr_reg, length); return gen_read_mem(jh, type, addr_reg, length);
} }
inline void gen_write_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, int64_t val) { inline void gen_write_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, int64_t val, uint32_t length) {
auto val_reg = jh.cc.newInt64(); auto val_reg = get_reg_for(jh, length * 8, true);
jh.cc.mov(val_reg, val); jh.cc.mov(val_reg, val);
gen_write_mem(jh, type, addr, val_reg); gen_write_mem(jh, type, addr, val_reg, length);
} }
inline void gen_write_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, x86::Gp val) { inline void gen_write_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, x86::Gp val, uint32_t length) {
x86::Compiler& cc = jh.cc; x86::Compiler& cc = jh.cc;
assert(val.size() == length);
auto mem_type_reg = cc.newInt32(); auto mem_type_reg = cc.newInt32();
jh.cc.mov(mem_type_reg, type); jh.cc.mov(mem_type_reg, type);
auto space_reg = cc.newInt32(); auto space_reg = cc.newInt32();
jh.cc.mov(space_reg, static_cast<uint16_t>(iss::address_type::VIRTUAL)); jh.cc.mov(space_reg, static_cast<uint16_t>(iss::address_type::VIRTUAL));
auto ret_reg = cc.newInt32(); auto ret_reg = cc.newInt32();
InvokeNode* invokeNode; InvokeNode* invokeNode;
switch(length) {
if(val.isGpb()) { case 1:
cc.invoke(&invokeNode, &write_mem1, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint8_t>()); cc.invoke(&invokeNode, &write_mem1, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint8_t>());
} else if(val.isGpw()) {
cc.invoke(&invokeNode, &write_mem2, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint16_t>());
} else if(val.isGpd()) {
cc.invoke(&invokeNode, &write_mem4, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint32_t>());
} else if(val.isGpq()) {
cc.invoke(&invokeNode, &write_mem8, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint64_t>());
} else
throw std::runtime_error("Invalid register size in gen_write_mem");
break;
case 2:
cc.invoke(&invokeNode, &write_mem2, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint16_t>());
break;
case 4:
cc.invoke(&invokeNode, &write_mem4, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint32_t>());
break;
case 8:
cc.invoke(&invokeNode, &write_mem8, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint64_t>());
break;
default:
throw std::runtime_error("Invalid register size in gen_ext");
}
invokeNode->setRet(0, ret_reg); invokeNode->setRet(0, ret_reg);
invokeNode->setArg(0, jh.arch_if_ptr); invokeNode->setArg(0, jh.arch_if_ptr);
invokeNode->setArg(1, space_reg); invokeNode->setArg(1, space_reg);
@ -515,16 +522,16 @@ inline void gen_write_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, x86::Gp
cc.cmp(ret_reg, 0); cc.cmp(ret_reg, 0);
cc.jne(jh.trap_entry); cc.jne(jh.trap_entry);
} }
inline void gen_write_mem(jit_holder& jh, mem_type_e type, uint64_t addr, x86::Gp val) { inline void gen_write_mem(jit_holder& jh, mem_type_e type, uint64_t addr, x86::Gp val, uint32_t length) {
auto addr_reg = jh.cc.newInt64(); auto addr_reg = jh.cc.newUInt64();
jh.cc.mov(addr_reg, addr); jh.cc.mov(addr_reg, addr);
gen_write_mem(jh, type, addr_reg, val); gen_write_mem(jh, type, addr_reg, val, length);
} }
inline void gen_write_mem(jit_holder& jh, mem_type_e type, uint64_t addr, int64_t val) { inline void gen_write_mem(jit_holder& jh, mem_type_e type, uint64_t addr, int64_t val, uint32_t length) {
auto val_reg = jh.cc.newInt64(); auto val_reg = get_reg_for(jh, length * 8, true);
jh.cc.mov(val_reg, val); jh.cc.mov(val_reg, val);
auto addr_reg = jh.cc.newInt64(); auto addr_reg = jh.cc.newUInt64();
jh.cc.mov(addr_reg, addr); jh.cc.mov(addr_reg, addr);
gen_write_mem(jh, type, addr_reg, val_reg); gen_write_mem(jh, type, addr_reg, val_reg, length);
} }

File diff suppressed because it is too large Load Diff