Compare commits

...

16 Commits

Author SHA1 Message Date
4f5d9214ed adds newly generated instr.yaml 2024-07-18 14:31:36 +02:00
d42d2ce533 corrects illegal instruction for llvm 2024-07-18 14:04:23 +02:00
236d12d7f5 integrates gen_bool for Conditions (was truncation) into llvm 2024-07-18 13:30:42 +02:00
e1b6cab890 removes setting of NEXT_PC to max when trapping in llvm and asmjit, adds default disass to llvm 2024-07-18 12:02:40 +02:00
8361f88718 removes setting of NEXT_PC to max if trap 2024-07-18 11:37:53 +02:00
2ec7ea4b41 removes leftover gen_sync in asmjit 2024-07-17 22:39:12 +02:00
b24965d321 corrects gen_sync update order, improves illegal instruction 2024-07-17 20:52:01 +02:00
244bf6d2f2 corrects gen_sync before trap check, improves illegal_instruction 2024-07-17 20:25:49 +02:00
1a4465a371 changes template: adds correct illegal instruction, reorders gen_sync to allow correct instr id eve when trapping, adds newly generated vm 2024-07-17 19:59:01 +02:00
fa82a50824 fixes typo in templates 2024-07-17 17:24:17 +02:00
6dc17857da updates template 2024-07-17 15:36:08 +02:00
11a30caae8 integrates generator changes to canPrecompute 2024-07-17 15:14:13 +02:00
ac1a26a10c integrates new tval changes into llvm 2024-07-17 14:17:02 +02:00
7a199e122d integrates new tval changes into asmjit 2024-07-17 09:42:12 +02:00
d8c3d2e19c integrates new tval changes into tcc 2024-07-16 17:35:23 +02:00
375755999a integrates new tval changes 2024-07-16 15:32:35 +02:00
9 changed files with 1308 additions and 605 deletions

View File

@ -96,6 +96,7 @@ protected:
using super::gen_leave; using super::gen_leave;
using super::gen_operation; using super::gen_operation;
using super::gen_sync; using super::gen_sync;
using super::gen_set_tval;
using this_class = vm_impl<ARCH>; using this_class = vm_impl<ARCH>;
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&);
@ -163,6 +164,7 @@ private:
cc.comment(fmt::format("${instr.name}_{:#x}:",pc.val).c_str()); cc.comment(fmt::format("${instr.name}_{:#x}:",pc.val).c_str());
gen_sync(jh, PRE_SYNC, ${idx}); gen_sync(jh, PRE_SYNC, ${idx});
mov(cc, jh.pc, pc.val); mov(cc, jh.pc, pc.val);
gen_set_tval(jh, instr);
pc = pc+${instr.length/8}; pc = pc+${instr.length/8};
mov(cc, jh.next_pc, pc.val); mov(cc, jh.next_pc, pc.val);
@ -171,23 +173,37 @@ private:
/*generate behavior*/ /*generate behavior*/
<%instr.behavior.eachLine{%>${it} <%instr.behavior.eachLine{%>${it}
<%}%> <%}%>
gen_instr_epilogue(jh);
gen_sync(jh, POST_SYNC, ${idx}); gen_sync(jh, POST_SYNC, ${idx});
gen_instr_epilogue(jh);
return returnValue; return returnValue;
} }
<%}%> <%}%>
/**************************************************************************** /****************************************************************************
* end opcode definitions * end opcode definitions
****************************************************************************/ ****************************************************************************/
continuation_e illegal_intruction(virt_addr_t &pc, code_word_t instr, jit_holder& jh ) { continuation_e illegal_instruction(virt_addr_t &pc, code_word_t instr, jit_holder& jh ) {
x86::Compiler& cc = jh.cc; x86::Compiler& cc = jh.cc;
cc.comment(fmt::format("illegal_intruction{:#x}:",pc.val).c_str()); if(this->disass_enabled){
auto mnemonic = std::string("illegal_instruction");
InvokeNode* call_print_disass;
char* mnemonic_ptr = strdup(mnemonic.c_str());
jh.disass_collection.push_back(mnemonic_ptr);
jh.cc.invoke(&call_print_disass, &print_disass, FuncSignature::build<void, void *, uint64_t, char *>());
call_print_disass->setArg(0, jh.arch_if_ptr);
call_print_disass->setArg(1, pc.val);
call_print_disass->setArg(2, mnemonic_ptr);
}
cc.comment(fmt::format("illegal_instruction{:#x}:",pc.val).c_str());
gen_sync(jh, PRE_SYNC, instr_descr.size()); gen_sync(jh, PRE_SYNC, instr_descr.size());
mov(cc, jh.pc, pc.val);
gen_set_tval(jh, instr);
pc = pc + ((instr & 3) == 3 ? 4 : 2); pc = pc + ((instr & 3) == 3 ? 4 : 2);
mov(cc, jh.next_pc, pc.val);
gen_instr_prologue(jh); gen_instr_prologue(jh);
cc.comment("//behavior:"); cc.comment("//behavior:");
gen_instr_epilogue(jh); gen_raise(jh, 0, 2);
gen_sync(jh, POST_SYNC, instr_descr.size()); gen_sync(jh, POST_SYNC, instr_descr.size());
gen_instr_epilogue(jh);
return BRANCH; return BRANCH;
} }
@ -273,7 +289,7 @@ continuation_e vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned
++inst_cnt; ++inst_cnt;
auto f = decode_instr(root, instr); auto f = decode_instr(root, instr);
if (f == nullptr) if (f == nullptr)
f = &this_class::illegal_intruction; f = &this_class::illegal_instruction;
return (this->*f)(pc, instr, jh); return (this->*f)(pc, instr, jh);
} }
template <typename ARCH> template <typename ARCH>
@ -281,7 +297,6 @@ void vm_impl<ARCH>::gen_instr_prologue(jit_holder& jh) {
auto& cc = jh.cc; auto& cc = jh.cc;
cc.comment("//gen_instr_prologue"); cc.comment("//gen_instr_prologue");
cc.inc(get_ptr_for(jh, traits::ICOUNT));
x86_reg_t current_trap_state = get_reg_for(cc, traits::TRAP_STATE); x86_reg_t current_trap_state = get_reg_for(cc, traits::TRAP_STATE);
mov(cc, current_trap_state, get_ptr_for(jh, traits::TRAP_STATE)); mov(cc, current_trap_state, get_ptr_for(jh, traits::TRAP_STATE));
@ -297,12 +312,13 @@ void vm_impl<ARCH>::gen_instr_epilogue(jit_holder& jh) {
mov(cc, current_trap_state, get_ptr_for(jh, traits::TRAP_STATE)); mov(cc, current_trap_state, get_ptr_for(jh, traits::TRAP_STATE));
cmp(cc, current_trap_state, 0); cmp(cc, current_trap_state, 0);
cc.jne(jh.trap_entry); cc.jne(jh.trap_entry);
cc.inc(get_ptr_for(jh, traits::ICOUNT));
} }
template <typename ARCH> 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.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){
@ -312,7 +328,6 @@ void vm_impl<ARCH>::gen_block_epilogue(jit_holder& jh){
cc.bind(jh.trap_entry); cc.bind(jh.trap_entry);
this->write_back(jh); this->write_back(jh);
this->gen_sync(jh, POST_SYNC, -1);
x86::Gp current_trap_state = get_reg_for_Gp(cc, traits::TRAP_STATE); x86::Gp current_trap_state = get_reg_for_Gp(cc, traits::TRAP_STATE);
mov(cc, current_trap_state, get_ptr_for(jh, traits::TRAP_STATE)); mov(cc, current_trap_state, get_ptr_for(jh, traits::TRAP_STATE));
@ -320,15 +335,13 @@ void vm_impl<ARCH>::gen_block_epilogue(jit_holder& jh){
x86::Gp current_pc = get_reg_for_Gp(cc, traits::PC); x86::Gp current_pc = get_reg_for_Gp(cc, traits::PC);
mov(cc, current_pc, get_ptr_for(jh, traits::PC)); mov(cc, current_pc, get_ptr_for(jh, traits::PC));
x86::Gp instr = cc.newInt32("instr");
mov(cc, instr, 0); // FIXME:this is not correct, should be instrId of trapping instr
cc.comment("//enter trap call;"); cc.comment("//enter trap call;");
InvokeNode* call_enter_trap; InvokeNode* call_enter_trap;
cc.invoke(&call_enter_trap, &enter_trap, FuncSignature::build<uint64_t, void*, uint64_t, uint64_t, uint64_t>()); cc.invoke(&call_enter_trap, &enter_trap, FuncSignature::build<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, jh.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));
@ -344,7 +357,6 @@ inline void vm_impl<ARCH>::gen_raise(jit_holder& jh, uint16_t trap_id, uint16_t
auto tmp1 = get_reg_for(cc, traits::TRAP_STATE); auto tmp1 = get_reg_for(cc, traits::TRAP_STATE);
mov(cc, tmp1, 0x80ULL << 24 | (cause << 16) | trap_id); mov(cc, tmp1, 0x80ULL << 24 | (cause << 16) | trap_id);
mov(cc, get_ptr_for(jh, traits::TRAP_STATE), tmp1); mov(cc, get_ptr_for(jh, traits::TRAP_STATE), tmp1);
mov(cc, jh.next_pc, std::numeric_limits<uint32_t>::max());
} }
} // namespace tgc5c } // namespace tgc5c

View File

@ -106,7 +106,6 @@ protected:
inline void raise(uint16_t trap_id, uint16_t cause){ inline void raise(uint16_t trap_id, uint16_t cause){
auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id; auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id;
this->core.reg.trap_state = trap_val; this->core.reg.trap_state = trap_val;
this->template get_reg<uint${addrDataWidth}_t>(traits::NEXT_PC) = std::numeric_limits<uint${addrDataWidth}_t>::max();
} }
inline void leave(unsigned lvl){ inline void leave(unsigned lvl){
@ -117,7 +116,12 @@ protected:
this->core.wait_until(type); this->core.wait_until(type);
} }
inline void set_tval(uint64_t new_tval){
tval = new_tval;
}
uint64_t fetch_count{0}; uint64_t fetch_count{0};
uint64_t tval{0};
using yield_t = boost::coroutines2::coroutine<void>::push_type; using yield_t = boost::coroutines2::coroutine<void>::push_type;
using coro_t = boost::coroutines2::coroutine<void>::pull_type; using coro_t = boost::coroutines2::coroutine<void>::pull_type;
@ -341,7 +345,9 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
// this->core.reg.trap_state = this->core.reg.pending_trap; // this->core.reg.trap_state = this->core.reg.pending_trap;
// trap check // trap check
if(trap_state!=0){ if(trap_state!=0){
super::core.enter_trap(trap_state, pc.val, instr); //In case of Instruction address misaligned (cause = 0 and trapid = 0) need the targeted addr (in tval)
auto mcause = (trap_state>>16) & 0xff;
super::core.enter_trap(trap_state, pc.val, mcause ? instr:tval);
} else { } else {
icount++; icount++;
instret++; instret++;

View File

@ -102,7 +102,10 @@ protected:
void gen_raise_trap(uint16_t trap_id, uint16_t cause); void gen_raise_trap(uint16_t trap_id, uint16_t cause);
void gen_leave_trap(unsigned lvl); void gen_leave_trap(unsigned lvl);
void gen_wait(unsigned type); void gen_wait(unsigned type);
void set_tval(uint64_t new_tval);
void set_tval(Value* new_tval);
void gen_trap_behavior(BasicBlock *) override; void gen_trap_behavior(BasicBlock *) override;
void gen_instr_prologue();
void gen_instr_epilogue(BasicBlock *bb); void gen_instr_epilogue(BasicBlock *bb);
inline Value *gen_reg_load(unsigned i, unsigned level = 0) { inline Value *gen_reg_load(unsigned i, unsigned level = 0) {
@ -162,18 +165,27 @@ private:
<%}%>if(this->disass_enabled){ <%}%>if(this->disass_enabled){
/* generate console output when executing the command */<%instr.disass.eachLine{%> /* generate console output when executing the command */<%instr.disass.eachLine{%>
${it}<%}%> ${it}<%}%>
std::vector<Value*> args {
this->core_ptr,
this->gen_const(64, pc.val),
this->builder.CreateGlobalStringPtr(mnemonic),
};
this->builder.CreateCall(this->mod->getFunction("print_disass"), args);
} }
bb->setName(fmt::format("${instr.name}_0x{:X}",pc.val)); bb->setName(fmt::format("${instr.name}_0x{:X}",pc.val));
this->gen_sync(PRE_SYNC,${idx}); this->gen_sync(PRE_SYNC,${idx});
auto cur_pc_val = this->gen_const(32,pc.val);
this->gen_set_pc(pc, traits::PC);
this->set_tval(instr);
pc=pc+ ${instr.length/8}; pc=pc+ ${instr.length/8};
this->gen_set_pc(pc, traits::NEXT_PC); this->gen_set_pc(pc, traits::NEXT_PC);
this->gen_instr_prologue();
/*generate behavior*/ /*generate behavior*/
<%instr.behavior.eachLine{%>${it} <%instr.behavior.eachLine{%>${it}
<%}%> <%}%>
this->gen_sync(POST_SYNC, ${idx});
this->gen_instr_epilogue(bb); this->gen_instr_epilogue(bb);
this->gen_sync(POST_SYNC, ${idx});
this->builder.CreateBr(bb); this->builder.CreateBr(bb);
return returnValue; return returnValue;
} }
@ -181,7 +193,16 @@ private:
/**************************************************************************** /****************************************************************************
* end opcode definitions * end opcode definitions
****************************************************************************/ ****************************************************************************/
std::tuple<continuation_e, BasicBlock *> illegal_intruction(virt_addr_t &pc, code_word_t instr, BasicBlock *bb) { std::tuple<continuation_e, BasicBlock *> illegal_instruction(virt_addr_t &pc, code_word_t instr, BasicBlock *bb) {
if(this->disass_enabled){
auto mnemonic = std::string("illegal_instruction");
std::vector<Value*> args {
this->core_ptr,
this->gen_const(64, pc.val),
this->builder.CreateGlobalStringPtr(mnemonic),
};
this->builder.CreateCall(this->mod->getFunction("print_disass"), args);
}
this->gen_sync(iss::PRE_SYNC, instr_descr.size()); this->gen_sync(iss::PRE_SYNC, instr_descr.size());
this->builder.CreateStore(this->builder.CreateLoad(this->get_typeptr(traits::NEXT_PC), get_reg_ptr(traits::NEXT_PC), true), this->builder.CreateStore(this->builder.CreateLoad(this->get_typeptr(traits::NEXT_PC), get_reg_ptr(traits::NEXT_PC), true),
get_reg_ptr(traits::PC), true); get_reg_ptr(traits::PC), true);
@ -190,9 +211,12 @@ private:
this->gen_const(64U, 1)), this->gen_const(64U, 1)),
get_reg_ptr(traits::ICOUNT), true); get_reg_ptr(traits::ICOUNT), true);
pc = pc + ((instr & 3) == 3 ? 4 : 2); pc = pc + ((instr & 3) == 3 ? 4 : 2);
this->set_tval(instr);
this->gen_raise_trap(0, 2); // illegal instruction trap this->gen_raise_trap(0, 2); // illegal instruction trap
this->gen_sync(iss::POST_SYNC, instr_descr.size()); this->gen_sync(iss::POST_SYNC, instr_descr.size());
this->gen_instr_epilogue(this->leave_blk); bb = this->leave_blk;
this->gen_instr_epilogue(bb);
this->builder.CreateBr(bb);
return std::make_tuple(BRANCH, nullptr); return std::make_tuple(BRANCH, nullptr);
} }
//decoding functionality //decoding functionality
@ -293,7 +317,7 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
++inst_cnt; ++inst_cnt;
auto f = decode_instr(root, instr); auto f = decode_instr(root, instr);
if (f == nullptr) { if (f == nullptr) {
f = &this_class::illegal_intruction; f = &this_class::illegal_instruction;
} }
return (this->*f)(pc, instr, this_block); return (this->*f)(pc, instr, this_block);
} }
@ -308,15 +332,12 @@ template <typename ARCH>
void vm_impl<ARCH>::gen_raise_trap(uint16_t trap_id, uint16_t cause) { void vm_impl<ARCH>::gen_raise_trap(uint16_t trap_id, uint16_t cause) {
auto *TRAP_val = this->gen_const(32, 0x80 << 24 | (cause << 16) | trap_id); auto *TRAP_val = this->gen_const(32, 0x80 << 24 | (cause << 16) | trap_id);
this->builder.CreateStore(TRAP_val, get_reg_ptr(traits::TRAP_STATE), true); this->builder.CreateStore(TRAP_val, get_reg_ptr(traits::TRAP_STATE), true);
this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits::LAST_BRANCH), false);
} }
template <typename ARCH> template <typename ARCH>
void vm_impl<ARCH>::gen_leave_trap(unsigned lvl) { void vm_impl<ARCH>::gen_leave_trap(unsigned lvl) {
std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, lvl)) }; std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, lvl)) };
this->builder.CreateCall(this->mod->getFunction("leave_trap"), args); this->builder.CreateCall(this->mod->getFunction("leave_trap"), args);
auto *PC_val = this->gen_read_mem(traits::CSR, (lvl << 8) + 0x41, traits::XLEN / 8);
this->builder.CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false);
this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits::LAST_BRANCH), false); this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits::LAST_BRANCH), false);
} }
@ -326,19 +347,37 @@ void vm_impl<ARCH>::gen_wait(unsigned type) {
this->builder.CreateCall(this->mod->getFunction("wait"), args); this->builder.CreateCall(this->mod->getFunction("wait"), args);
} }
template <typename ARCH>
inline void vm_impl<ARCH>::set_tval(uint64_t tval) {
auto tmp_tval = this->gen_const(64, tval);
this->set_tval(tmp_tval);
}
template <typename ARCH>
inline void vm_impl<ARCH>::set_tval(Value* new_tval) {
this->builder.CreateStore(this->gen_ext(new_tval, 64, false), this->tval);
}
template <typename ARCH> template <typename ARCH>
void vm_impl<ARCH>::gen_trap_behavior(BasicBlock *trap_blk) { void vm_impl<ARCH>::gen_trap_behavior(BasicBlock *trap_blk) {
this->builder.SetInsertPoint(trap_blk); this->builder.SetInsertPoint(trap_blk);
this->gen_sync(POST_SYNC, -1); //TODO get right InstrId
auto *trap_state_val = this->builder.CreateLoad(this->get_typeptr(traits::TRAP_STATE), get_reg_ptr(traits::TRAP_STATE), true); auto *trap_state_val = this->builder.CreateLoad(this->get_typeptr(traits::TRAP_STATE), get_reg_ptr(traits::TRAP_STATE), true);
this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), auto *cur_pc_val = this->builder.CreateLoad(this->get_typeptr(traits::PC), get_reg_ptr(traits::PC), true);
get_reg_ptr(traits::LAST_BRANCH), false); std::vector<Value *> args{this->core_ptr,
std::vector<Value *> args{this->core_ptr, this->adj_to64(trap_state_val), this->adj_to64(trap_state_val),
this->adj_to64(this->builder.CreateLoad(this->get_typeptr(traits::PC), get_reg_ptr(traits::PC), false))}; this->adj_to64(cur_pc_val),
this->adj_to64(this->builder.CreateLoad(this->get_type(64),this->tval))};
this->builder.CreateCall(this->mod->getFunction("enter_trap"), args); this->builder.CreateCall(this->mod->getFunction("enter_trap"), args);
this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits::LAST_BRANCH), false);
auto *trap_addr_val = this->builder.CreateLoad(this->get_typeptr(traits::NEXT_PC), get_reg_ptr(traits::NEXT_PC), false); auto *trap_addr_val = this->builder.CreateLoad(this->get_typeptr(traits::NEXT_PC), get_reg_ptr(traits::NEXT_PC), false);
this->builder.CreateRet(trap_addr_val); this->builder.CreateRet(trap_addr_val);
} }
template <typename ARCH>
void vm_impl<ARCH>::gen_instr_prologue() {
auto* trap_val =
this->builder.CreateLoad(this->get_typeptr(arch::traits<ARCH>::PENDING_TRAP), get_reg_ptr(arch::traits<ARCH>::PENDING_TRAP));
this->builder.CreateStore(trap_val, get_reg_ptr(arch::traits<ARCH>::TRAP_STATE), false);
}
template <typename ARCH> template <typename ARCH>
void vm_impl<ARCH>::gen_instr_epilogue(BasicBlock *bb) { void vm_impl<ARCH>::gen_instr_epilogue(BasicBlock *bb) {
@ -349,6 +388,10 @@ void vm_impl<ARCH>::gen_instr_epilogue(BasicBlock *bb) {
ConstantInt::get(getContext(), APInt(v->getType()->getIntegerBitWidth(), 0))), ConstantInt::get(getContext(), APInt(v->getType()->getIntegerBitWidth(), 0))),
target_bb, this->trap_blk, 1); target_bb, this->trap_blk, 1);
this->builder.SetInsertPoint(target_bb); this->builder.SetInsertPoint(target_bb);
// update icount
auto* icount_val = this->builder.CreateAdd(
this->builder.CreateLoad(this->get_typeptr(arch::traits<ARCH>::ICOUNT), get_reg_ptr(arch::traits<ARCH>::ICOUNT)), this->gen_const(64U, 1));
this->builder.CreateStore(icount_val, get_reg_ptr(arch::traits<ARCH>::ICOUNT), false);
} }
} // namespace ${coreDef.name.toLowerCase()} } // namespace ${coreDef.name.toLowerCase()}

View File

@ -99,6 +99,10 @@ protected:
void gen_wait(tu_builder& tu, unsigned type); void gen_wait(tu_builder& tu, unsigned type);
inline void gen_set_tval(tu_builder& tu, uint64_t new_tval);
inline void gen_set_tval(tu_builder& tu, value new_tval);
inline void gen_trap_check(tu_builder& tu) { inline void gen_trap_check(tu_builder& tu) {
tu("if(*trap_state!=0) goto trap_entry;"); tu("if(*trap_state!=0) goto trap_entry;");
} }
@ -169,21 +173,27 @@ private:
pc=pc+ ${instr.length/8}; pc=pc+ ${instr.length/8};
gen_set_pc(tu, pc, traits::NEXT_PC); gen_set_pc(tu, pc, traits::NEXT_PC);
tu.open_scope(); tu.open_scope();
this->gen_set_tval(tu, instr);
<%instr.behavior.eachLine{%>${it} <%instr.behavior.eachLine{%>${it}
<%}%> <%}%>
tu.close_scope(); tu.close_scope();
gen_trap_check(tu);
vm_base<ARCH>::gen_sync(tu, POST_SYNC,${idx}); vm_base<ARCH>::gen_sync(tu, POST_SYNC,${idx});
gen_trap_check(tu);
return returnValue; return returnValue;
} }
<%}%> <%}%>
/**************************************************************************** /****************************************************************************
* end opcode definitions * end opcode definitions
****************************************************************************/ ****************************************************************************/
compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr, tu_builder& tu) { compile_ret_t illegal_instruction(virt_addr_t &pc, code_word_t instr, tu_builder& tu) {
vm_impl::gen_sync(tu, iss::PRE_SYNC, instr_descr.size()); vm_impl::gen_sync(tu, iss::PRE_SYNC, instr_descr.size());
if(this->disass_enabled){
/* generate console output when executing the command */
tu("print_disass(core_ptr, {:#x}, \"{}\");", pc.val, std::string("illegal_instruction"));
}
pc = pc + ((instr & 3) == 3 ? 4 : 2); pc = pc + ((instr & 3) == 3 ? 4 : 2);
gen_raise_trap(tu, 0, 2); // illegal instruction trap gen_raise_trap(tu, 0, 2); // illegal instruction trap
this->gen_set_tval(tu, instr);
vm_impl::gen_sync(tu, iss::POST_SYNC, instr_descr.size()); vm_impl::gen_sync(tu, iss::POST_SYNC, instr_descr.size());
vm_impl::gen_trap_check(tu); vm_impl::gen_trap_check(tu);
return BRANCH; return BRANCH;
@ -285,7 +295,7 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
++inst_cnt; ++inst_cnt;
auto f = decode_instr(root, instr); auto f = decode_instr(root, instr);
if (f == nullptr) { if (f == nullptr) {
f = &this_class::illegal_intruction; f = &this_class::illegal_instruction;
} }
return (this->*f)(pc, instr, tu); return (this->*f)(pc, instr, tu);
} }
@ -304,10 +314,17 @@ template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(tu_builder& tu, unsi
template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned type) { template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned type) {
} }
template <typename ARCH> void vm_impl<ARCH>::gen_set_tval(tu_builder& tu, uint64_t new_tval) {
tu(fmt::format("tval = {};", new_tval));
}
template <typename ARCH> void vm_impl<ARCH>::gen_set_tval(tu_builder& tu, value new_tval) {
tu(fmt::format("tval = {};", new_tval.str));
}
template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(tu_builder& tu) { template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(tu_builder& tu) {
tu("trap_entry:"); tu("trap_entry:");
this->gen_sync(tu, POST_SYNC, -1); this->gen_sync(tu, POST_SYNC, -1);
tu("enter_trap(core_ptr, *trap_state, *pc, 0);"); tu("enter_trap(core_ptr, *trap_state, *pc, tval);");
tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(),32)); tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(),32));
tu("return *next_pc;"); tu("return *next_pc;");
} }

View File

@ -1207,7 +1207,7 @@ template <typename BASE, features_e FEAT> void riscv_hart_m_p<BASE, FEAT>::check
} }
} }
template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) { template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::enter_trap(uint64_t flags, uint64_t addr, uint64_t tval) {
// flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0] // flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0]
// calculate and write mcause val // calculate and write mcause val
auto const trap_id = bit_sub<0, 16>(flags); auto const trap_id = bit_sub<0, 16>(flags);
@ -1228,10 +1228,10 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::e
*/ */
switch(cause) { switch(cause) {
case 0: case 0:
csr[mtval] = static_cast<reg_t>(addr); csr[mtval] = static_cast<reg_t>(tval);
break; break;
case 2: case 2:
csr[mtval] = (!has_compressed() || (instr & 0x3) == 3) ? instr : instr & 0xffff; csr[mtval] = (!has_compressed() || (tval & 0x3) == 3) ? tval : tval & 0xffff;
break; break;
case 3: case 3:
if((FEAT & FEAT_DEBUG) && (csr[dcsr] & 0x8000)) { if((FEAT & FEAT_DEBUG) && (csr[dcsr] & 0x8000)) {

File diff suppressed because it is too large Load Diff

View File

@ -102,7 +102,6 @@ protected:
inline void raise(uint16_t trap_id, uint16_t cause){ inline void raise(uint16_t trap_id, uint16_t cause){
auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id; auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id;
this->core.reg.trap_state = trap_val; this->core.reg.trap_state = trap_val;
this->template get_reg<uint32_t>(traits::NEXT_PC) = std::numeric_limits<uint32_t>::max();
} }
inline void leave(unsigned lvl){ inline void leave(unsigned lvl){
@ -113,7 +112,12 @@ protected:
this->core.wait_until(type); this->core.wait_until(type);
} }
inline void set_tval(uint64_t new_tval){
tval = new_tval;
}
uint64_t fetch_count{0}; uint64_t fetch_count{0};
uint64_t tval{0};
using yield_t = boost::coroutines2::coroutine<void>::push_type; using yield_t = boost::coroutines2::coroutine<void>::push_type;
using coro_t = boost::coroutines2::coroutine<void>::pull_type; using coro_t = boost::coroutines2::coroutine<void>::pull_type;
@ -463,14 +467,16 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, traits::RV_CAUSE_ILLEGAL_INSTRUCTION); raise(0, traits::RV_CAUSE_ILLEGAL_INSTRUCTION);
} }
else { else {
if(imm % traits::INSTR_ALIGNMENT) { uint32_t new_pc = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int32_t)sext<21>(imm) ));
if(new_pc % traits::INSTR_ALIGNMENT) {
set_tval(new_pc);
raise(0, 0); raise(0, 0);
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)((uint64_t)(*PC ) + (uint64_t)(4 )); *(X+rd) = (uint32_t)((uint64_t)(*PC ) + (uint64_t)(4 ));
} }
*NEXT_PC = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int32_t)sext<21>(imm) )); *NEXT_PC = new_pc;
this->core.reg.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
@ -500,6 +506,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
uint32_t addr_mask = (uint32_t)- 2; uint32_t addr_mask = (uint32_t)- 2;
uint32_t new_pc = (uint32_t)(((uint64_t)(*(X+rs1) ) + (uint64_t)((int16_t)sext<12>(imm) )) & (int64_t)(addr_mask )); uint32_t new_pc = (uint32_t)(((uint64_t)(*(X+rs1) ) + (uint64_t)((int16_t)sext<12>(imm) )) & (int64_t)(addr_mask ));
if(new_pc % traits::INSTR_ALIGNMENT) { if(new_pc % traits::INSTR_ALIGNMENT) {
set_tval(new_pc);
raise(0, 0); raise(0, 0);
} }
else { else {
@ -534,11 +541,13 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(*(X+rs1) == *(X+rs2)) { if(*(X+rs1) == *(X+rs2)) {
if((uint32_t)(imm ) % traits::INSTR_ALIGNMENT) { uint32_t new_pc = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int16_t)sext<13>(imm) ));
if(new_pc % traits::INSTR_ALIGNMENT) {
set_tval(new_pc);
raise(0, 0); raise(0, 0);
} }
else { else {
*NEXT_PC = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int16_t)sext<13>(imm) )); *NEXT_PC = new_pc;
this->core.reg.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
@ -567,11 +576,13 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(*(X+rs1) != *(X+rs2)) { if(*(X+rs1) != *(X+rs2)) {
if((uint32_t)(imm ) % traits::INSTR_ALIGNMENT) { uint32_t new_pc = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int16_t)sext<13>(imm) ));
if(new_pc % traits::INSTR_ALIGNMENT) {
set_tval(new_pc);
raise(0, 0); raise(0, 0);
} }
else { else {
*NEXT_PC = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int16_t)sext<13>(imm) )); *NEXT_PC = new_pc;
this->core.reg.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
@ -600,11 +611,13 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if((int32_t)*(X+rs1) < (int32_t)*(X+rs2)) { if((int32_t)*(X+rs1) < (int32_t)*(X+rs2)) {
if((uint32_t)(imm ) % traits::INSTR_ALIGNMENT) { uint32_t new_pc = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int16_t)sext<13>(imm) ));
if(new_pc % traits::INSTR_ALIGNMENT) {
set_tval(new_pc);
raise(0, 0); raise(0, 0);
} }
else { else {
*NEXT_PC = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int16_t)sext<13>(imm) )); *NEXT_PC = new_pc;
this->core.reg.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
@ -633,11 +646,13 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if((int32_t)*(X+rs1) >= (int32_t)*(X+rs2)) { if((int32_t)*(X+rs1) >= (int32_t)*(X+rs2)) {
if((uint32_t)(imm ) % traits::INSTR_ALIGNMENT) { uint32_t new_pc = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int16_t)sext<13>(imm) ));
if(new_pc % traits::INSTR_ALIGNMENT) {
set_tval(new_pc);
raise(0, 0); raise(0, 0);
} }
else { else {
*NEXT_PC = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int16_t)sext<13>(imm) )); *NEXT_PC = new_pc;
this->core.reg.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
@ -666,11 +681,13 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(*(X+rs1) < *(X+rs2)) { if(*(X+rs1) < *(X+rs2)) {
if((uint32_t)(imm ) % traits::INSTR_ALIGNMENT) { uint32_t new_pc = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int16_t)sext<13>(imm) ));
if(new_pc % traits::INSTR_ALIGNMENT) {
set_tval(new_pc);
raise(0, 0); raise(0, 0);
} }
else { else {
*NEXT_PC = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int16_t)sext<13>(imm) )); *NEXT_PC = new_pc;
this->core.reg.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
@ -699,11 +716,13 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(*(X+rs1) >= *(X+rs2)) { if(*(X+rs1) >= *(X+rs2)) {
if((uint32_t)(imm ) % traits::INSTR_ALIGNMENT) { uint32_t new_pc = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int16_t)sext<13>(imm) ));
if(new_pc % traits::INSTR_ALIGNMENT) {
set_tval(new_pc);
raise(0, 0); raise(0, 0);
} }
else { else {
*NEXT_PC = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int16_t)sext<13>(imm) )); *NEXT_PC = new_pc;
this->core.reg.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
@ -2675,7 +2694,9 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
// this->core.reg.trap_state = this->core.reg.pending_trap; // this->core.reg.trap_state = this->core.reg.pending_trap;
// trap check // trap check
if(trap_state!=0){ if(trap_state!=0){
super::core.enter_trap(trap_state, pc.val, instr); //In case of Instruction address misaligned (cause = 0 and trapid = 0) need the targeted addr (in tval)
auto mcause = (trap_state>>16) & 0xff;
super::core.enter_trap(trap_state, pc.val, mcause ? instr:tval);
} else { } else {
icount++; icount++;
instret++; instret++;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff