Merge branch 'develop' of https://git.minres.com/DBT-RISE/DBT-RISE-TGC into develop

This commit is contained in:
gabriel 2024-05-31 09:42:13 +02:00
commit a6c48ceaac
18 changed files with 3310 additions and 2405 deletions

View File

@ -349,7 +349,7 @@ Zifencei:
size: 32 size: 32
branch: false branch: false
delay: 1 delay: 1
RV32M: RVM:
MUL: MUL:
index: 49 index: 49
encoding: 0b00000010000000000000000000110011 encoding: 0b00000010000000000000000000110011

View File

@ -79,21 +79,36 @@ public:
} }
protected: protected:
using vm_base<ARCH>::get_reg_ptr; using super::get_ptr_for;
using super::get_reg;
using super::get_reg_for;
using super::load_reg_from_mem;
using super::write_reg_to_mem;
using super::gen_ext;
using super::gen_read_mem;
using super::gen_write_mem;
using super::gen_wait;
using super::gen_leave;
using super::gen_operation;
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&);
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;
void gen_block_prologue(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);}
void gen_instr_prologue(jit_holder& jh);
void gen_instr_epilogue(jit_holder& jh);
inline void gen_raise(jit_holder& jh, uint16_t trap_id, uint16_t cause);
template<unsigned W, typename U, typename S = typename std::make_signed<U>::type> template<unsigned W, typename U, typename S = typename std::make_signed<U>::type>
inline S sext(U from) { inline S sext(U from) {
auto mask = (1ULL<<W) - 1; auto mask = (1ULL<<W) - 1;
auto sign_mask = 1ULL<<(W-1); auto sign_mask = 1ULL<<(W-1);
return (from & mask) | ((from & sign_mask) ? ~mask : 0); return (from & mask) | ((from & sign_mask) ? ~mask : 0);
} }
#include <vm/asmjit/helper_func.h>
private: private:
/**************************************************************************** /****************************************************************************
* start opcode definitions * start opcode definitions
@ -127,16 +142,26 @@ private:
<%instr.fields.eachLine{%>${it} <%instr.fields.eachLine{%>${it}
<%}%>if(this->disass_enabled){ <%}%>if(this->disass_enabled){
/* generate disass */ /* generate disass */
<%instr.disass.eachLine{%>
${it}<%}%>
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, FuncSignatureT<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);
} }
x86::Compiler& cc = jh.cc; x86::Compiler& cc = jh.cc;
//ideally only do this if necessary (someone / plugin needs it) cc.comment(fmt::format("${instr.name}_{:#x}:",pc.val).c_str());
cc.mov(jh.pc,PC);
cc.comment(fmt::format("\\n${instr.name}_{:#x}:",pc.val).c_str());
this->gen_sync(jh, PRE_SYNC, ${idx}); this->gen_sync(jh, PRE_SYNC, ${idx});
pc=pc+ ${instr.length/8}; cc.mov(jh.pc, pc.val);
pc = pc+${instr.length/8};
gen_instr_prologue(jh, pc.val); cc.mov(jh.next_pc, pc.val);
cc.comment("\\n//behavior:");
gen_instr_prologue(jh);
cc.comment("//behavior:");
/*generate behavior*/ /*generate behavior*/
<%instr.behavior.eachLine{%>${it} <%instr.behavior.eachLine{%>${it}
<%}%> <%}%>
@ -149,9 +174,17 @@ private:
* end opcode definitions * end opcode definitions
****************************************************************************/ ****************************************************************************/
continuation_e illegal_intruction(virt_addr_t &pc, code_word_t instr, jit_holder& jh ) { continuation_e illegal_intruction(virt_addr_t &pc, code_word_t instr, jit_holder& jh ) {
x86::Compiler& cc = jh.cc;
cc.comment(fmt::format("illegal_intruction{:#x}:",pc.val).c_str());
this->gen_sync(jh, PRE_SYNC, instr_descr.size());
pc = pc + ((instr & 3) == 3 ? 4 : 2);
gen_instr_prologue(jh);
cc.comment("//behavior:");
gen_instr_epilogue(jh);
this->gen_sync(jh, POST_SYNC, instr_descr.size());
return BRANCH; return BRANCH;
} }
//decoding functionality //decoding functionality
void populate_decoding_tree(decoding_tree_node* root){ void populate_decoding_tree(decoding_tree_node* root){
@ -206,11 +239,6 @@ private:
} }
}; };
template <typename CODE_WORD> void debug_fn(CODE_WORD instr) {
volatile CODE_WORD x = instr;
instr = 2 * x;
}
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>
@ -224,8 +252,7 @@ vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
} }
template <typename ARCH> template <typename ARCH>
continuation_e continuation_e vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, jit_holder& jh) {
vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt, jit_holder& jh) {
enum {TRAP_ID=1<<16}; enum {TRAP_ID=1<<16};
code_word_t instr = 0; code_word_t instr = 0;
phys_addr_t paddr(pc); phys_addr_t paddr(pc);
@ -243,10 +270,78 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
f = &this_class::illegal_intruction; f = &this_class::illegal_intruction;
return (this->*f)(pc, instr, jh); return (this->*f)(pc, instr, jh);
} }
template <typename ARCH>
void vm_impl<ARCH>::gen_instr_prologue(jit_holder& jh) {
auto& cc = jh.cc;
cc.comment("//gen_instr_prologue");
cc.inc(get_ptr_for(jh, traits::ICOUNT));
x86::Gp current_trap_state = get_reg_for(jh, traits::TRAP_STATE);
cc.mov(current_trap_state, get_ptr_for(jh, traits::TRAP_STATE));
cc.mov(get_ptr_for(jh, traits::PENDING_TRAP), current_trap_state);
} // namespace ${coreDef.name.toLowerCase()} }
template <typename ARCH>
void vm_impl<ARCH>::gen_instr_epilogue(jit_holder& jh) {
auto& cc = jh.cc;
cc.comment("//gen_instr_epilogue");
x86::Gp current_trap_state = get_reg_for(jh, traits::TRAP_STATE);
cc.mov(current_trap_state, get_ptr_for(jh, traits::TRAP_STATE));
cc.cmp(current_trap_state, 0);
cc.jne(jh.trap_entry);
}
template <typename ARCH>
void vm_impl<ARCH>::gen_block_prologue(jit_holder& jh){
jh.pc = load_reg_from_mem(jh, traits::PC);
jh.next_pc = load_reg_from_mem(jh, traits::NEXT_PC);
}
template <typename ARCH>
void vm_impl<ARCH>::gen_block_epilogue(jit_holder& jh){
x86::Compiler& cc = jh.cc;
cc.comment("//gen_block_epilogue");
cc.ret(jh.next_pc);
cc.bind(jh.trap_entry);
this->write_back(jh);
this->gen_sync(jh, POST_SYNC, -1);
x86::Gp current_trap_state = get_reg_for(jh, traits::TRAP_STATE);
cc.mov(current_trap_state, get_ptr_for(jh, traits::TRAP_STATE));
x86::Gp current_pc = get_reg_for(jh, traits::PC);
cc.mov(current_pc, get_ptr_for(jh, traits::PC));
x86::Gp instr = cc.newInt32("instr");
cc.mov(instr, 0); // FIXME:this is not correct
cc.comment("//enter trap call;");
InvokeNode* call_enter_trap;
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(1, current_trap_state);
call_enter_trap->setArg(2, current_pc);
call_enter_trap->setArg(3, instr);
x86::Gp current_next_pc = get_reg_for(jh, traits::NEXT_PC);
cc.mov(current_next_pc, get_ptr_for(jh, traits::NEXT_PC));
cc.mov(jh.next_pc, current_next_pc);
cc.mov(get_ptr_for(jh, traits::LAST_BRANCH), std::numeric_limits<uint32_t>::max());
cc.ret(jh.next_pc);
}
template <typename ARCH>
inline void vm_impl<ARCH>::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_ptr_for(jh, traits::TRAP_STATE), tmp1);
cc.mov(jh.next_pc, std::numeric_limits<uint32_t>::max());
}
} // namespace tgc5c
template <> template <>
std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) { std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {
@ -257,9 +352,9 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
} // namespace asmjit } // namespace asmjit
} // namespace iss } // namespace iss
#include <iss/factory.h>
#include <iss/arch/riscv_hart_m_p.h> #include <iss/arch/riscv_hart_m_p.h>
#include <iss/arch/riscv_hart_mu_p.h> #include <iss/arch/riscv_hart_mu_p.h>
#include <iss/factory.h>
namespace iss { namespace iss {
namespace { namespace {
volatile std::array<bool, 2> dummy = { volatile std::array<bool, 2> dummy = {

View File

@ -99,16 +99,11 @@ protected:
std::tuple<continuation_e, BasicBlock *> gen_single_inst_behavior(virt_addr_t &, unsigned int &, BasicBlock *) override; std::tuple<continuation_e, BasicBlock *> gen_single_inst_behavior(virt_addr_t &, unsigned int &, BasicBlock *) override;
void gen_leave_behavior(BasicBlock *leave_blk) override; void gen_leave_behavior(BasicBlock *leave_blk) override;
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 gen_trap_behavior(BasicBlock *) override; void gen_trap_behavior(BasicBlock *) override;
void gen_instr_epilogue(BasicBlock *bb);
void gen_trap_check(BasicBlock *bb);
inline Value *gen_reg_load(unsigned i, unsigned level = 0) { inline Value *gen_reg_load(unsigned i, unsigned level = 0) {
return this->builder.CreateLoad(this->get_typeptr(i), get_reg_ptr(i), false); return this->builder.CreateLoad(this->get_typeptr(i), get_reg_ptr(i), false);
@ -162,20 +157,22 @@ private:
/* 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){
bb->setName(fmt::format("${instr.name}_0x{:X}",pc.val));
this->gen_sync(PRE_SYNC,${idx});
uint64_t PC = pc.val; uint64_t PC = pc.val;
<%instr.fields.eachLine{%>${it} <%instr.fields.eachLine{%>${it}
<%}%>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}<%}%>
} }
bb->setName(fmt::format("${instr.name}_0x{:X}",pc.val));
this->gen_sync(PRE_SYNC,${idx});
auto cur_pc_val = this->gen_const(32,pc.val); auto cur_pc_val = this->gen_const(32,pc.val);
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);
/*generate behavior*/
<%instr.behavior.eachLine{%>${it} <%instr.behavior.eachLine{%>${it}
<%}%> <%}%>
this->gen_trap_check(bb); this->gen_instr_epilogue(bb);
this->gen_sync(POST_SYNC, ${idx}); this->gen_sync(POST_SYNC, ${idx});
this->builder.CreateBr(bb); this->builder.CreateBr(bb);
return returnValue; return returnValue;
@ -195,7 +192,7 @@ private:
pc = pc + ((instr & 3) == 3 ? 4 : 2); pc = pc + ((instr & 3) == 3 ? 4 : 2);
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_trap_check(this->leave_blk); this->gen_instr_epilogue(this->leave_blk);
return std::make_tuple(BRANCH, nullptr); return std::make_tuple(BRANCH, nullptr);
} }
//decoding functionality //decoding functionality
@ -301,18 +298,21 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
return (this->*f)(pc, instr, this_block); return (this->*f)(pc, instr, this_block);
} }
template <typename ARCH> void vm_impl<ARCH>::gen_leave_behavior(BasicBlock *leave_blk) { template <typename ARCH>
void vm_impl<ARCH>::gen_leave_behavior(BasicBlock *leave_blk) {
this->builder.SetInsertPoint(leave_blk); this->builder.SetInsertPoint(leave_blk);
this->builder.CreateRet(this->builder.CreateLoad(this->get_typeptr(traits::NEXT_PC),get_reg_ptr(traits::NEXT_PC), false)); this->builder.CreateRet(this->builder.CreateLoad(this->get_typeptr(traits::NEXT_PC),get_reg_ptr(traits::NEXT_PC), false));
} }
template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(uint16_t trap_id, uint16_t cause) { template <typename ARCH>
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); this->builder.CreateStore(this->gen_const(32U, std::numeric_limits<uint32_t>::max()), get_reg_ptr(traits::LAST_BRANCH), false);
} }
template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(unsigned lvl) { template <typename ARCH>
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); auto *PC_val = this->gen_read_mem(traits::CSR, (lvl << 8) + 0x41, traits::XLEN / 8);
@ -320,12 +320,14 @@ template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(unsigned lvl) {
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);
} }
template <typename ARCH> void vm_impl<ARCH>::gen_wait(unsigned type) { template <typename ARCH>
void vm_impl<ARCH>::gen_wait(unsigned type) {
std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, type)) }; std::vector<Value *> args{ this->core_ptr, ConstantInt::get(getContext(), APInt(64, type)) };
this->builder.CreateCall(this->mod->getFunction("wait"), args); this->builder.CreateCall(this->mod->getFunction("wait"), args);
} }
template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(BasicBlock *trap_blk) { template <typename ARCH>
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 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);
@ -338,7 +340,8 @@ template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(BasicBlock *trap_
this->builder.CreateRet(trap_addr_val); this->builder.CreateRet(trap_addr_val);
} }
template <typename ARCH> inline void vm_impl<ARCH>::gen_trap_check(BasicBlock *bb) { template <typename ARCH>
void vm_impl<ARCH>::gen_instr_epilogue(BasicBlock *bb) {
auto* target_bb = BasicBlock::Create(this->mod->getContext(), "", this->func, bb); auto* target_bb = BasicBlock::Create(this->mod->getContext(), "", this->func, bb);
auto *v = this->builder.CreateLoad(this->get_typeptr(traits::TRAP_STATE), get_reg_ptr(traits::TRAP_STATE), true); auto *v = this->builder.CreateLoad(this->get_typeptr(traits::TRAP_STATE), get_reg_ptr(traits::TRAP_STATE), true);
this->gen_cond_branch(this->builder.CreateICmp( this->gen_cond_branch(this->builder.CreateICmp(

View File

@ -292,7 +292,7 @@ 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) { 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(" *trap_state = {:#x};", 0x80 << 24 | (cause << 16) | trap_id);
tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(), 32)); tu.store(traits::NEXT_PC, tu.constant(std::numeric_limits<uint32_t>::max(), 32));
} }
template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(tu_builder& tu, unsigned lvl) { template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(tu_builder& tu, unsigned lvl) {

View File

@ -35,8 +35,14 @@
#ifndef _RISCV_HART_COMMON #ifndef _RISCV_HART_COMMON
#define _RISCV_HART_COMMON #define _RISCV_HART_COMMON
#include "iss/arch_if.h"
#include <cstdint> #include <cstdint>
#include <elfio/elfio.hpp>
#include <fmt/format.h>
#include <iss/arch_if.h>
#include <iss/log_categories.h>
#include <string>
#include <unordered_map>
#include <util/logging.h>
namespace iss { namespace iss {
namespace arch { namespace arch {
@ -296,6 +302,61 @@ inline void write_reg_uint32(uint64_t offs, uint32_t& reg, const uint8_t* const
break; break;
} }
} }
struct riscv_hart_common {
riscv_hart_common(){};
~riscv_hart_common(){};
std::unordered_map<std::string, uint64_t> symbol_table;
std::unordered_map<std::string, uint64_t> get_sym_table(std::string name) {
if(!symbol_table.empty())
return symbol_table;
FILE* fp = fopen(name.c_str(), "r");
if(fp) {
std::array<char, 5> buf;
auto n = fread(buf.data(), 1, 4, fp);
fclose(fp);
if(n != 4)
throw std::runtime_error("input file has insufficient size");
buf[4] = 0;
if(strcmp(buf.data() + 1, "ELF") == 0) {
// Create elfio reader
ELFIO::elfio reader;
// Load ELF data
if(!reader.load(name))
throw std::runtime_error("could not process elf file");
// check elf properties
if(reader.get_type() != ET_EXEC)
throw std::runtime_error("wrong elf type in file");
if(reader.get_machine() != EM_RISCV)
throw std::runtime_error("wrong elf machine in file");
const auto sym_sec = reader.sections[".symtab"];
if(SHT_SYMTAB == sym_sec->get_type() || SHT_DYNSYM == sym_sec->get_type()) {
ELFIO::symbol_section_accessor symbols(reader, sym_sec);
auto sym_no = symbols.get_symbols_num();
std::string name;
ELFIO::Elf64_Addr value = 0;
ELFIO::Elf_Xword size = 0;
unsigned char bind = 0;
unsigned char type = 0;
ELFIO::Elf_Half section = 0;
unsigned char other = 0;
for(auto i = 0U; i < sym_no; ++i) {
symbols.get_symbol(i, name, value, size, bind, type, section, other);
if(name != "") {
this->symbol_table[name] = value;
#ifndef NDEBUG
CPPLOG(DEBUG) << "Found Symbol " << name;
#endif
}
}
}
return symbol_table;
}
throw std::runtime_error(fmt::format("memory load file {} is not a valid elf file", name));
} else
throw std::runtime_error(fmt::format("memory load file not found, check if {} is a valid file", name));
};
};
} // namespace arch } // namespace arch
} // namespace iss } // namespace iss

View File

@ -40,6 +40,7 @@
#include "iss/log_categories.h" #include "iss/log_categories.h"
#include "iss/vm_if.h" #include "iss/vm_if.h"
#include "riscv_hart_common.h" #include "riscv_hart_common.h"
#include <stdexcept>
#ifndef FMT_HEADER_ONLY #ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY #define FMT_HEADER_ONLY
#endif #endif
@ -68,7 +69,7 @@
namespace iss { namespace iss {
namespace arch { namespace arch {
template <typename BASE, features_e FEAT = FEAT_NONE> class riscv_hart_m_p : public BASE { template <typename BASE, features_e FEAT = FEAT_NONE> class riscv_hart_m_p : public BASE, public riscv_hart_common {
protected: protected:
const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}}; const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
const std::array<const char*, 16> trap_str = {{"" const std::array<const char*, 16> trap_str = {{""
@ -326,6 +327,8 @@ protected:
unsigned get_reg_size(unsigned num) override { return traits<BASE>::reg_bit_widths[num]; } unsigned get_reg_size(unsigned num) override { return traits<BASE>::reg_bit_widths[num]; }
std::unordered_map<std::string, uint64_t> get_symbol_table(std::string name) override { return arch.get_sym_table(name); }
riscv_hart_m_p<BASE, FEAT>& arch; riscv_hart_m_p<BASE, FEAT>& arch;
}; };
@ -570,6 +573,12 @@ riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p(feature_config cfg)
} }
template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m_p<BASE, FEAT>::load_file(std::string name, int type) { template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m_p<BASE, FEAT>::load_file(std::string name, int type) {
get_sym_table(name);
try {
tohost = symbol_table.at("tohost");
fromhost = symbol_table.at("fromhost");
} catch(std::out_of_range& e) {
}
FILE* fp = fopen(name.c_str(), "r"); FILE* fp = fopen(name.c_str(), "r");
if(fp) { if(fp) {
std::array<char, 5> buf; std::array<char, 5> buf;
@ -600,31 +609,11 @@ template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m
auto res = this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits<BASE>::MEM, auto res = this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits<BASE>::MEM,
pseg->get_physical_address(), fsize, reinterpret_cast<const uint8_t* const>(seg_data)); pseg->get_physical_address(), fsize, reinterpret_cast<const uint8_t* const>(seg_data));
if(res != iss::Ok) if(res != iss::Ok)
LOG(ERR) << "problem writing " << fsize << "bytes to 0x" << std::hex << pseg->get_physical_address(); CPPLOG(ERR) << "problem writing " << fsize << "bytes to 0x" << std::hex << pseg->get_physical_address();
} }
} }
for(const auto sec : reader.sections) { for(const auto sec : reader.sections) {
if(sec->get_name() == ".symtab") { if(sec->get_name() == ".tohost") {
if(SHT_SYMTAB == sec->get_type() || SHT_DYNSYM == sec->get_type()) {
ELFIO::symbol_section_accessor symbols(reader, sec);
auto sym_no = symbols.get_symbols_num();
std::string name;
ELFIO::Elf64_Addr value = 0;
ELFIO::Elf_Xword size = 0;
unsigned char bind = 0;
unsigned char type = 0;
ELFIO::Elf_Half section = 0;
unsigned char other = 0;
for(auto i = 0U; i < sym_no; ++i) {
symbols.get_symbol(i, name, value, size, bind, type, section, other);
if(name == "tohost") {
tohost = value;
} else if(name == "fromhost") {
fromhost = value;
}
}
}
} else if(sec->get_name() == ".tohost") {
tohost = sec->get_address(); tohost = sec->get_address();
fromhost = tohost + 0x40; fromhost = tohost + 0x40;
} }
@ -654,11 +643,11 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
const unsigned length, uint8_t* const data) { const unsigned length, uint8_t* const data) {
#ifndef NDEBUG #ifndef NDEBUG
if(access && iss::access_type::DEBUG) { if(access && iss::access_type::DEBUG) {
LOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr; CPPLOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr;
} else if(access && iss::access_type::FETCH) { } else if(access && iss::access_type::FETCH) {
LOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr; CPPLOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr;
} else { } else {
LOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr; CPPLOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr;
} }
#endif #endif
try { try {
@ -740,23 +729,23 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
const char* prefix = (access && iss::access_type::DEBUG) ? "debug " : ""; const char* prefix = (access && iss::access_type::DEBUG) ? "debug " : "";
switch(length) { switch(length) {
case 8: case 8:
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t*)&data[0] << std::dec << ") @addr 0x" CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t*)&data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
case 4: case 4:
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t*)&data[0] << std::dec << ") @addr 0x" CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t*)&data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
case 2: case 2:
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t*)&data[0] << std::dec << ") @addr 0x" CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t*)&data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
case 1: case 1:
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec << ") @addr 0x" CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
default: default:
LOG(TRACE) << prefix << "write of " << length << " bytes @addr " << addr; CPPLOG(TRACE) << prefix << "write of " << length << " bytes @addr " << addr;
} }
#endif #endif
try { try {
@ -808,7 +797,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
case 0x10023000: // UART1 base, TXFIFO reg case 0x10023000: // UART1 base, TXFIFO reg
uart_buf << (char)data[0]; uart_buf << (char)data[0];
if(((char)data[0]) == '\n' || data[0] == 0) { if(((char)data[0]) == '\n' || data[0] == 0) {
// LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send // CPPLOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send
// '"<<uart_buf.str()<<"'"; // '"<<uart_buf.str()<<"'";
std::cout << uart_buf.str(); std::cout << uart_buf.str();
uart_buf.str(""); uart_buf.str("");
@ -1108,7 +1097,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned le
// TODO remove UART, Peripherals should not be part of the ISS // TODO remove UART, Peripherals should not be part of the ISS
case 0xFFFF0000: // UART0 base, TXFIFO reg case 0xFFFF0000: // UART0 base, TXFIFO reg
if(((char)data[0]) == '\n' || data[0] == 0) { if(((char)data[0]) == '\n' || data[0] == 0) {
LOG(INFO) << "UART" << ((paddr.val >> 12) & 0x3) << " send '" << uart_buf.str() << "'"; CPPLOG(INFO) << "UART" << ((paddr.val >> 12) & 0x3) << " send '" << uart_buf.str() << "'";
uart_buf.str(""); uart_buf.str("");
} else if(((char)data[0]) != '\r') } else if(((char)data[0]) != '\r')
uart_buf << (char)data[0]; uart_buf << (char)data[0];
@ -1128,22 +1117,22 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned le
switch(hostvar >> 48) { switch(hostvar >> 48) {
case 0: case 0:
if(hostvar != 0x1) { if(hostvar != 0x1) {
LOG(FATAL) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar CPPLOG(FATAL) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
<< "), stopping simulation"; << "), stopping simulation";
} else { } else {
LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar CPPLOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
<< "), stopping simulation"; << "), stopping simulation";
} }
this->reg.trap_state = std::numeric_limits<uint32_t>::max(); this->reg.trap_state = std::numeric_limits<uint32_t>::max();
this->interrupt_sim = hostvar; this->interrupt_sim = hostvar;
#ifndef WITH_TCC #ifndef WITH_TCC
throw(iss::simulation_stopped(hostvar)); // throw(iss::simulation_stopped(hostvar));
#endif #endif
break; break;
case 0x0101: { case 0x0101: {
char c = static_cast<char>(hostvar & 0xff); char c = static_cast<char>(hostvar & 0xff);
if(c == '\n' || c == 0) { if(c == '\n' || c == 0) {
LOG(INFO) << "tohost send '" << uart_buf.str() << "'"; CPPLOG(INFO) << "tohost send '" << uart_buf.str() << "'";
uart_buf.str(""); uart_buf.str("");
} else } else
uart_buf << c; uart_buf << c;

View File

@ -68,7 +68,7 @@
namespace iss { namespace iss {
namespace arch { namespace arch {
template <typename BASE> class riscv_hart_msu_vp : public BASE { template <typename BASE> class riscv_hart_msu_vp : public BASE, public riscv_hart_common {
protected: protected:
const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}}; const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
const std::array<const char*, 16> trap_str = {{"" const std::array<const char*, 16> trap_str = {{""
@ -377,6 +377,8 @@ protected:
unsigned get_reg_size(unsigned num) override { return traits<BASE>::reg_bit_widths[num]; } unsigned get_reg_size(unsigned num) override { return traits<BASE>::reg_bit_widths[num]; }
std::unordered_map<std::string, uint64_t> get_symbol_table(std::string name) override { return arch.get_sym_table(name); }
riscv_hart_msu_vp<BASE>& arch; riscv_hart_msu_vp<BASE>& arch;
}; };
@ -591,7 +593,7 @@ template <typename BASE> std::pair<uint64_t, bool> riscv_hart_msu_vp<BASE>::load
auto res = this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits<BASE>::MEM, auto res = this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits<BASE>::MEM,
pseg->get_physical_address(), fsize, reinterpret_cast<const uint8_t* const>(seg_data)); pseg->get_physical_address(), fsize, reinterpret_cast<const uint8_t* const>(seg_data));
if(res != iss::Ok) if(res != iss::Ok)
LOG(ERR) << "problem writing " << fsize << "bytes to 0x" << std::hex << pseg->get_physical_address(); CPPLOG(ERR) << "problem writing " << fsize << "bytes to 0x" << std::hex << pseg->get_physical_address();
} }
} }
for(const auto sec : reader.sections) { for(const auto sec : reader.sections) {
@ -632,11 +634,11 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
const unsigned length, uint8_t* const data) { const unsigned length, uint8_t* const data) {
#ifndef NDEBUG #ifndef NDEBUG
if(access && iss::access_type::DEBUG) { if(access && iss::access_type::DEBUG) {
LOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr; CPPLOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr;
} else if(access && iss::access_type::FETCH) { } else if(access && iss::access_type::FETCH) {
LOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr; CPPLOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr;
} else { } else {
LOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr; CPPLOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr;
} }
#endif #endif
try { try {
@ -726,23 +728,23 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
const char* prefix = (access && iss::access_type::DEBUG) ? "debug " : ""; const char* prefix = (access && iss::access_type::DEBUG) ? "debug " : "";
switch(length) { switch(length) {
case 8: case 8:
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t*)&data[0] << std::dec << ") @addr 0x" CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t*)&data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
case 4: case 4:
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t*)&data[0] << std::dec << ") @addr 0x" CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t*)&data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
case 2: case 2:
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t*)&data[0] << std::dec << ") @addr 0x" CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t*)&data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
case 1: case 1:
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec << ") @addr 0x" CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
default: default:
LOG(TRACE) << prefix << "write of " << length << " bytes @addr " << addr; CPPLOG(TRACE) << prefix << "write of " << length << " bytes @addr " << addr;
} }
#endif #endif
try { try {
@ -787,7 +789,7 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
case 0x10023000: // UART1 base, TXFIFO reg case 0x10023000: // UART1 base, TXFIFO reg
uart_buf << (char)data[0]; uart_buf << (char)data[0];
if(((char)data[0]) == '\n' || data[0] == 0) { if(((char)data[0]) == '\n' || data[0] == 0) {
// LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send // CPPLOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send
// '"<<uart_buf.str()<<"'"; // '"<<uart_buf.str()<<"'";
std::cout << uart_buf.str(); std::cout << uart_buf.str();
uart_buf.str(""); uart_buf.str("");
@ -1083,7 +1085,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_add
switch(paddr.val) { switch(paddr.val) {
case 0xFFFF0000: // UART0 base, TXFIFO reg case 0xFFFF0000: // UART0 base, TXFIFO reg
if(((char)data[0]) == '\n' || data[0] == 0) { if(((char)data[0]) == '\n' || data[0] == 0) {
LOG(INFO) << "UART" << ((paddr.val >> 12) & 0x3) << " send '" << uart_buf.str() << "'"; CPPLOG(INFO) << "UART" << ((paddr.val >> 12) & 0x3) << " send '" << uart_buf.str() << "'";
uart_buf.str(""); uart_buf.str("");
} else if(((char)data[0]) != '\r') } else if(((char)data[0]) != '\r')
uart_buf << (char)data[0]; uart_buf << (char)data[0];
@ -1103,11 +1105,11 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_add
switch(hostvar >> 48) { switch(hostvar >> 48) {
case 0: case 0:
if(hostvar != 0x1) { if(hostvar != 0x1) {
LOG(FATAL) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar CPPLOG(FATAL) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
<< "), stopping simulation"; << "), stopping simulation";
} else { } else {
LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar CPPLOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
<< "), stopping simulation"; << "), stopping simulation";
} }
this->reg.trap_state = std::numeric_limits<uint32_t>::max(); this->reg.trap_state = std::numeric_limits<uint32_t>::max();
this->interrupt_sim = hostvar; this->interrupt_sim = hostvar;
@ -1118,7 +1120,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_add
case 0x0101: { case 0x0101: {
char c = static_cast<char>(hostvar & 0xff); char c = static_cast<char>(hostvar & 0xff);
if(c == '\n' || c == 0) { if(c == '\n' || c == 0) {
LOG(INFO) << "tohost send '" << uart_buf.str() << "'"; CPPLOG(INFO) << "tohost send '" << uart_buf.str() << "'";
uart_buf.str(""); uart_buf.str("");
} else } else
uart_buf << c; uart_buf << c;

View File

@ -68,7 +68,7 @@
namespace iss { namespace iss {
namespace arch { namespace arch {
template <typename BASE, features_e FEAT = FEAT_NONE> class riscv_hart_mu_p : public BASE { template <typename BASE, features_e FEAT = FEAT_NONE> class riscv_hart_mu_p : public BASE, public riscv_hart_common {
protected: protected:
const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}}; const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
const std::array<const char*, 16> trap_str = {{"" const std::array<const char*, 16> trap_str = {{""
@ -353,6 +353,8 @@ protected:
unsigned get_reg_size(unsigned num) override { return traits<BASE>::reg_bit_widths[num]; } unsigned get_reg_size(unsigned num) override { return traits<BASE>::reg_bit_widths[num]; }
std::unordered_map<std::string, uint64_t> get_symbol_table(std::string name) override { return arch.get_sym_table(name); }
riscv_hart_mu_p<BASE, FEAT>& arch; riscv_hart_mu_p<BASE, FEAT>& arch;
}; };
@ -678,7 +680,7 @@ template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m
auto res = this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits<BASE>::MEM, auto res = this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits<BASE>::MEM,
pseg->get_physical_address(), fsize, reinterpret_cast<const uint8_t* const>(seg_data)); pseg->get_physical_address(), fsize, reinterpret_cast<const uint8_t* const>(seg_data));
if(res != iss::Ok) if(res != iss::Ok)
LOG(ERR) << "problem writing " << fsize << "bytes to 0x" << std::hex << pseg->get_physical_address(); CPPLOG(ERR) << "problem writing " << fsize << "bytes to 0x" << std::hex << pseg->get_physical_address();
} }
} }
for(const auto sec : reader.sections) { for(const auto sec : reader.sections) {
@ -818,11 +820,11 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
const unsigned length, uint8_t* const data) { const unsigned length, uint8_t* const data) {
#ifndef NDEBUG #ifndef NDEBUG
if(access && iss::access_type::DEBUG) { if(access && iss::access_type::DEBUG) {
LOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr; CPPLOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr;
} else if(is_fetch(access)) { } else if(is_fetch(access)) {
LOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr; CPPLOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr;
} else { } else {
LOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr; CPPLOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr;
} }
#endif #endif
try { try {
@ -913,23 +915,23 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
const char* prefix = (access && iss::access_type::DEBUG) ? "debug " : ""; const char* prefix = (access && iss::access_type::DEBUG) ? "debug " : "";
switch(length) { switch(length) {
case 8: case 8:
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t*)&data[0] << std::dec << ") @addr 0x" CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t*)&data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
case 4: case 4:
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t*)&data[0] << std::dec << ") @addr 0x" CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t*)&data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
case 2: case 2:
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t*)&data[0] << std::dec << ") @addr 0x" CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t*)&data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
case 1: case 1:
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec << ") @addr 0x" CPPLOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec << ") @addr 0x"
<< std::hex << addr; << std::hex << addr;
break; break;
default: default:
LOG(TRACE) << prefix << "write of " << length << " bytes @addr " << addr; CPPLOG(TRACE) << prefix << "write of " << length << " bytes @addr " << addr;
} }
#endif #endif
try { try {
@ -990,7 +992,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
case 0x10023000: // UART1 base, TXFIFO reg case 0x10023000: // UART1 base, TXFIFO reg
uart_buf << (char)data[0]; uart_buf << (char)data[0];
if(((char)data[0]) == '\n' || data[0] == 0) { if(((char)data[0]) == '\n' || data[0] == 0) {
// LOG(INFO)<<"UART"<<((addr>>16)&0x3)<<" send // CPPLOG(INFO)<<"UART"<<((addr>>16)&0x3)<<" send
// '"<<uart_buf.str()<<"'"; // '"<<uart_buf.str()<<"'";
std::cout << uart_buf.str(); std::cout << uart_buf.str();
uart_buf.str(""); uart_buf.str("");
@ -1326,7 +1328,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned l
// TODO remove UART, Peripherals should not be part of the ISS // TODO remove UART, Peripherals should not be part of the ISS
case 0xFFFF0000: // UART0 base, TXFIFO reg case 0xFFFF0000: // UART0 base, TXFIFO reg
if(((char)data[0]) == '\n' || data[0] == 0) { if(((char)data[0]) == '\n' || data[0] == 0) {
LOG(INFO) << "UART" << ((paddr.val >> 12) & 0x3) << " send '" << uart_buf.str() << "'"; CPPLOG(INFO) << "UART" << ((paddr.val >> 12) & 0x3) << " send '" << uart_buf.str() << "'";
uart_buf.str(""); uart_buf.str("");
} else if(((char)data[0]) != '\r') } else if(((char)data[0]) != '\r')
uart_buf << (char)data[0]; uart_buf << (char)data[0];
@ -1346,11 +1348,11 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned l
switch(hostvar >> 48) { switch(hostvar >> 48) {
case 0: case 0:
if(hostvar != 0x1) { if(hostvar != 0x1) {
LOG(FATAL) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar CPPLOG(FATAL) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
<< "), stopping simulation"; << "), stopping simulation";
} else { } else {
LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar CPPLOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
<< "), stopping simulation"; << "), stopping simulation";
} }
this->reg.trap_state = std::numeric_limits<uint32_t>::max(); this->reg.trap_state = std::numeric_limits<uint32_t>::max();
this->interrupt_sim = hostvar; this->interrupt_sim = hostvar;
@ -1361,7 +1363,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned l
case 0x0101: { case 0x0101: {
char c = static_cast<char>(hostvar & 0xff); char c = static_cast<char>(hostvar & 0xff);
if(c == '\n' || c == 0) { if(c == '\n' || c == 0) {
LOG(INFO) << "tohost send '" << uart_buf.str() << "'"; CPPLOG(INFO) << "tohost send '" << uart_buf.str() << "'";
uart_buf.str(""); uart_buf.str("");
} else } else
uart_buf << c; uart_buf << c;

View File

@ -76,7 +76,53 @@ template <> struct traits<tgc5c> {
static constexpr std::array<const uint32_t, 43> reg_byte_offsets{ static constexpr std::array<const uint32_t, 43> reg_byte_offsets{
{0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,137,141,145,149,157,165,173,177}}; {0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,137,141,145,149,157,165,173,177}};
/*
For easy lookup:
X0 (zero): 0x0000
X1 (ra) : 0x0004
X2 (sp) : 0x0008
X3 (gp) : 0x000c
X4 (tp) : 0x0010
X5 (t0) : 0x0014
X6 (t1) : 0x0018
X7 (t2) : 0x001c
X8 (s0/fp): 0x0020
X9 (s1) : 0x0024
X10 (a0) : 0x0028
X11 (a1) : 0x002c
X12 (a2) : 0x0030
X13 (a3) : 0x0034
X14 (a4) : 0x0038
X15 (a5) : 0x003c
X16 (a6) : 0x0040
X17 (a7) : 0x0044
X18 (s2) : 0x0048
X19 (s3) : 0x004c
X20 (s4) : 0x0050
X21 (s5) : 0x0054
X22 (s6) : 0x0058
X23 (s7) : 0x005c
X24 (s8) : 0x0060
X25 (s9) : 0x0064
X26 (s10) : 0x0068
X27 (s11) : 0x006c
X28 (t3) : 0x0070
X29 (t4) : 0x0074
X30 (t5) : 0x0078
X31 (t6) : 0x007c
PC : 0x0080
NEXT_PC : 0x0084
PRIV : 0x0085
DPC : 0x0089
trap_state : 0x008d
pending_trap : 0x0091
icount : 0x0095
cycle : 0x009d
instret : 0x00a5
instruction : 0x00ad
last_branch : 0x00b1
*/
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1); static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
enum sreg_flag_e { FLAGS }; enum sreg_flag_e { FLAGS };

View File

@ -174,7 +174,7 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::current_thread_query
} }
template <typename ARCH> status riscv_target_adapter<ARCH>::read_registers(std::vector<uint8_t>& data, std::vector<uint8_t>& avail) { template <typename ARCH> status riscv_target_adapter<ARCH>::read_registers(std::vector<uint8_t>& data, std::vector<uint8_t>& avail) {
LOG(TRACE) << "reading target registers"; CPPLOG(TRACE) << "reading target registers";
// return idx<0?:; // return idx<0?:;
data.clear(); data.clear();
avail.clear(); avail.clear();
@ -328,9 +328,9 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::add_break(break_type
auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr}); auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr});
auto eaddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr + length}); auto eaddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr + length});
target_adapter_base::bp_lut.addEntry(++target_adapter_base::bp_count, saddr.val, eaddr.val - saddr.val); target_adapter_base::bp_lut.addEntry(++target_adapter_base::bp_count, saddr.val, eaddr.val - saddr.val);
LOG(TRACE) << "Adding breakpoint with handle " << target_adapter_base::bp_count << " for addr 0x" << std::hex << saddr.val CPPLOG(TRACE) << "Adding breakpoint with handle " << target_adapter_base::bp_count << " for addr 0x" << std::hex << saddr.val
<< std::dec; << std::dec;
LOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints"; CPPLOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
return Ok; return Ok;
} }
} }
@ -345,13 +345,13 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::remove_break(break_t
auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr}); auto saddr = map_addr({iss::access_type::FETCH, iss::address_type::PHYSICAL, 0, addr});
unsigned handle = target_adapter_base::bp_lut.getEntry(saddr.val); unsigned handle = target_adapter_base::bp_lut.getEntry(saddr.val);
if(handle) { if(handle) {
LOG(TRACE) << "Removing breakpoint with handle " << handle << " for addr 0x" << std::hex << saddr.val << std::dec; CPPLOG(TRACE) << "Removing breakpoint with handle " << handle << " for addr 0x" << std::hex << saddr.val << std::dec;
// TODO: check length of addr range // TODO: check length of addr range
target_adapter_base::bp_lut.removeEntry(handle); target_adapter_base::bp_lut.removeEntry(handle);
LOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints"; CPPLOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
return Ok; return Ok;
} }
LOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints"; CPPLOG(TRACE) << "Now having " << target_adapter_base::bp_lut.size() << " breakpoints";
return Err; return Err;
} }
} }

View File

@ -61,7 +61,7 @@ bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if&
try { try {
auto root = YAML::LoadAll(is); auto root = YAML::LoadAll(is);
if(root.size() != 1) { if(root.size() != 1) {
LOG(ERR) << "Too many root nodes in YAML file " << config_file_name; CPPLOG(ERR) << "Too many root nodes in YAML file " << config_file_name;
} }
for(auto p : root[0]) { for(auto p : root[0]) {
auto isa_subset = p.first; auto isa_subset = p.first;
@ -87,11 +87,11 @@ bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if&
} }
} }
} catch(YAML::ParserException& e) { } catch(YAML::ParserException& e) {
LOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what(); CPPLOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
return false; return false;
} }
} else { } else {
LOG(ERR) << "Could not open input file " << config_file_name; CPPLOG(ERR) << "Could not open input file " << config_file_name;
return false; return false;
} }
} }

View File

@ -47,7 +47,7 @@ iss::plugin::instruction_count::instruction_count(std::string config_file_name)
try { try {
auto root = YAML::LoadAll(is); auto root = YAML::LoadAll(is);
if(root.size() != 1) { if(root.size() != 1) {
LOG(ERR) << "Too many rro nodes in YAML file " << config_file_name; CPPLOG(ERR) << "Too many rro nodes in YAML file " << config_file_name;
} }
for(auto p : root[0]) { for(auto p : root[0]) {
auto isa_subset = p.first; auto isa_subset = p.first;
@ -69,10 +69,10 @@ iss::plugin::instruction_count::instruction_count(std::string config_file_name)
} }
rep_counts.resize(delays.size()); rep_counts.resize(delays.size());
} catch(YAML::ParserException& e) { } catch(YAML::ParserException& e) {
LOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what(); CPPLOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
} }
} else { } else {
LOG(ERR) << "Could not open input file " << config_file_name; CPPLOG(ERR) << "Could not open input file " << config_file_name;
} }
} }
} }
@ -81,7 +81,7 @@ iss::plugin::instruction_count::~instruction_count() {
size_t idx = 0; size_t idx = 0;
for(auto it : delays) { for(auto it : delays) {
if(rep_counts[idx] > 0 && it.instr_name.find("__" != 0)) if(rep_counts[idx] > 0 && it.instr_name.find("__" != 0))
LOG(INFO) << it.instr_name << ";" << rep_counts[idx]; CPPLOG(INFO) << it.instr_name << ";" << rep_counts[idx];
idx++; idx++;
} }
} }

View File

@ -35,6 +35,8 @@
#include <iostream> #include <iostream>
#include <iss/factory.h> #include <iss/factory.h>
#include <iss/semihosting/semihosting.h> #include <iss/semihosting/semihosting.h>
#include <string>
#include <unordered_map>
#include <vector> #include <vector>
#include "iss/arch/tgc_mapper.h" #include "iss/arch/tgc_mapper.h"
@ -73,7 +75,7 @@ int main(int argc, char* argv[]) {
("elf,f", po::value<std::vector<std::string>>(), "ELF file(s) to load") ("elf,f", po::value<std::vector<std::string>>(), "ELF file(s) to load")
("mem,m", po::value<std::string>(), "the memory input file") ("mem,m", po::value<std::string>(), "the memory input file")
("plugin,p", po::value<std::vector<std::string>>(), "plugin to activate") ("plugin,p", po::value<std::vector<std::string>>(), "plugin to activate")
("backend", po::value<std::string>()->default_value("interp"), "the ISS backend to use, options are: interp, tcc") ("backend", po::value<std::string>()->default_value("interp"), "the ISS backend to use, options are: interp, llvm, tcc, asmjit")
("isa", po::value<std::string>()->default_value("tgc5c"), "core or isa name to use for simulation, use '?' to get list"); ("isa", po::value<std::string>()->default_value("tgc5c"), "core or isa name to use for simulation, use '?' to get list");
// clang-format on // clang-format on
auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run(); auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
@ -138,11 +140,11 @@ int main(int argc, char* argv[]) {
std::tie(cpu, vm) = f.create(isa_opt, clim["gdb-port"].as<unsigned>(), &semihosting_cb); std::tie(cpu, vm) = f.create(isa_opt, clim["gdb-port"].as<unsigned>(), &semihosting_cb);
} }
if(!cpu) { if(!cpu) {
LOG(ERR) << "Could not create cpu for isa " << isa_opt << " and backend " << clim["backend"].as<std::string>() << std::endl; CPPLOG(ERR) << "Could not create cpu for isa " << isa_opt << " and backend " << clim["backend"].as<std::string>() << std::endl;
return 127; return 127;
} }
if(!vm) { if(!vm) {
LOG(ERR) << "Could not create vm for isa " << isa_opt << " and backend " << clim["backend"].as<std::string>() << std::endl; CPPLOG(ERR) << "Could not create vm for isa " << isa_opt << " and backend " << clim["backend"].as<std::string>() << std::endl;
return 127; return 127;
} }
if(clim.count("plugin")) { if(clim.count("plugin")) {
@ -178,7 +180,7 @@ int main(int argc, char* argv[]) {
} else } else
#endif #endif
{ {
LOG(ERR) << "Unknown plugin name: " << plugin_name << ", valid names are 'ce', 'ic'" << std::endl; CPPLOG(ERR) << "Unknown plugin name: " << plugin_name << ", valid names are 'ce', 'ic'" << std::endl;
return 127; return 127;
} }
} }
@ -200,12 +202,12 @@ int main(int argc, char* argv[]) {
if(clim.count("elf")) if(clim.count("elf"))
for(std::string input : clim["elf"].as<std::vector<std::string>>()) { for(std::string input : clim["elf"].as<std::vector<std::string>>()) {
auto start_addr = vm->get_arch()->load_file(input); auto start_addr = vm->get_arch()->load_file(input);
if(start_addr.second) if(start_addr.second) // FIXME: this always evaluates to true as load file always returns <sth, true>
start_address = start_addr.first; start_address = start_addr.first;
} }
for(std::string input : args) { for(std::string input : args) {
auto start_addr = vm->get_arch()->load_file(input); // treat remaining arguments as elf files auto start_addr = vm->get_arch()->load_file(input); // treat remaining arguments as elf files
if(start_addr.second) if(start_addr.second) // FIXME: this always evaluates to true as load file always returns <sth, true>
start_address = start_addr.first; start_address = start_addr.first;
} }
if(clim.count("reset")) { if(clim.count("reset")) {
@ -215,11 +217,42 @@ int main(int argc, char* argv[]) {
vm->reset(start_address); vm->reset(start_address);
auto cycles = clim["instructions"].as<uint64_t>(); auto cycles = clim["instructions"].as<uint64_t>();
res = vm->start(cycles, dump); res = vm->start(cycles, dump);
auto instr_if = vm->get_arch()->get_instrumentation_if();
// this assumes a single input file
std::unordered_map<std::string, uint64_t> sym_table;
if(args.empty())
sym_table = instr_if->get_symbol_table(clim["elf"].as<std::vector<std::string>>()[0]);
else
sym_table = instr_if->get_symbol_table(args[0]);
if(sym_table.find("begin_signature") != std::end(sym_table) && sym_table.find("end_signature") != std::end(sym_table)) {
auto start_addr = sym_table["begin_signature"];
auto end_addr = sym_table["end_signature"];
std::array<uint8_t, 4> data;
std::ofstream file;
std::string filename = fmt::format("{}.signature", isa_opt);
std::replace(std::begin(filename), std::end(filename), '|', '_');
// default riscof requires this filename
filename = "DUT-tgc.signature";
file.open(filename, std::ios::out);
if(!file.is_open()) {
LOG(ERR) << "Error opening file " << filename << std::endl;
return 1;
}
for(auto addr = start_addr; addr < end_addr; addr += data.size()) {
vm->get_arch()->read(iss::address_type::PHYSICAL, iss::access_type::DEBUG_READ, 0 /*MEM*/, addr, data.size(),
data.data()); // FIXME: get space from iss::arch::traits<ARCH>::mem_type_e::MEM
// TODO : obey Target endianess
uint32_t to_print = (data[3] << 24) + (data[2] << 16) + (data[1] << 8) + data[0];
file << std::hex << fmt::format("{:08x}", to_print) << std::dec << std::endl;
}
}
} catch(std::exception& e) { } catch(std::exception& e) {
LOG(ERR) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit" << std::endl; CPPLOG(ERR) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit" << std::endl;
res = 2; res = 2;
} }
// cleanup to let plugins report of needed // cleanup to let plugins report if needed
for(auto* p : plugin_list) { for(auto* p : plugin_list) {
delete p; delete p;
} }

View File

@ -1,537 +0,0 @@
x86::Mem get_reg_ptr(jit_holder& jh, unsigned idx) {
x86::Gp tmp_ptr = jh.cc.newUIntPtr("tmp_ptr");
jh.cc.mov(tmp_ptr, jh.regs_base_ptr);
jh.cc.add(tmp_ptr, traits::reg_byte_offsets[idx]);
switch(traits::reg_bit_widths[idx]) {
case 8:
return x86::ptr_8(tmp_ptr);
case 16:
return x86::ptr_16(tmp_ptr);
case 32:
return x86::ptr_32(tmp_ptr);
case 64:
return x86::ptr_64(tmp_ptr);
default:
throw std::runtime_error("Invalid reg size in get_reg_ptr");
}
}
x86::Gp get_reg_for(jit_holder& jh, unsigned idx) {
// TODO can check for regs in jh and return them instead of creating new ones
switch(traits::reg_bit_widths[idx]) {
case 8:
return jh.cc.newInt8();
case 16:
return jh.cc.newInt16();
case 32:
return jh.cc.newInt32();
case 64:
return jh.cc.newInt64();
default:
throw std::runtime_error("Invalid reg size in get_reg_ptr");
}
}
x86::Gp get_reg_for(jit_holder& jh, unsigned size, bool is_signed) {
if(is_signed)
switch(size) {
case 8:
return jh.cc.newInt8();
case 16:
return jh.cc.newInt16();
case 32:
return jh.cc.newInt32();
case 64:
return jh.cc.newInt64();
default:
throw std::runtime_error("Invalid reg size in get_reg_ptr");
}
else
switch(size) {
case 8:
return jh.cc.newUInt8();
case 16:
return jh.cc.newUInt16();
case 32:
return jh.cc.newUInt32();
case 64:
return jh.cc.newUInt64();
default:
throw std::runtime_error("Invalid reg size in get_reg_ptr");
}
}
inline x86::Gp load_reg_from_mem(jit_holder& jh, unsigned idx) {
auto ptr = get_reg_ptr(jh, idx);
auto reg = get_reg_for(jh, idx);
jh.cc.mov(reg, ptr);
return reg;
}
inline void write_reg_to_mem(jit_holder& jh, x86::Gp reg, unsigned idx) {
auto ptr = get_reg_ptr(jh, idx);
jh.cc.mov(ptr, reg);
}
void gen_instr_prologue(jit_holder& jh, addr_t pc) {
auto& cc = jh.cc;
cc.comment("\n//(*icount)++;");
cc.inc(get_reg_ptr(jh, traits::ICOUNT));
cc.comment("\n//*pc=*next_pc;");
cc.mov(get_reg_ptr(jh, traits::PC), jh.next_pc);
cc.comment("\n//*trap_state=*pending_trap;");
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.mov(jh.next_pc, pc);
}
void gen_instr_epilogue(jit_holder& jh) {
auto& cc = jh.cc;
cc.comment("\n//if(*trap_state!=0) goto trap_entry;");
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.cmp(current_trap_state, 0);
cc.jne(jh.trap_entry);
// TODO: Does not need to be done for every instruction, only when needed
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);
}
void gen_block_prologue(jit_holder& jh) override {
jh.pc = load_reg_from_mem(jh, traits::PC);
jh.next_pc = load_reg_from_mem(jh, traits::NEXT_PC);
}
void gen_block_epilogue(jit_holder& jh) override {
x86::Compiler& cc = jh.cc;
cc.comment("\n//return *next_pc;");
cc.ret(jh.next_pc);
cc.bind(jh.trap_entry);
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);
cc.mov(current_trap_state, get_reg_ptr(jh, traits::TRAP_STATE));
x86::Gp current_pc = get_reg_for(jh, traits::PC);
cc.mov(current_pc, get_reg_ptr(jh, traits::PC));
x86::Gp instr = cc.newInt32("instr");
cc.mov(instr, 0); // this is not correct
cc.comment("\n//enter trap call;");
InvokeNode* call_enter_trap;
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(1, current_trap_state);
call_enter_trap->setArg(2, current_pc);
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.mov(get_reg_ptr(jh, traits::LAST_BRANCH), std::numeric_limits<uint32_t>::max());
cc.comment("\n//return *next_pc;");
cc.ret(jh.next_pc);
}
/*
inline void raise(uint16_t trap_id, uint16_t cause){
auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id;
this->core.reg.trap_state = trap_val;
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 };
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value || std::is_same<T, x86::Gp>::value>>
x86::Gp gen_operation(jit_holder& jh, operation op, x86::Gp a, T b) {
x86::Compiler& cc = jh.cc;
switch(op) {
case add: {
cc.add(a, b);
break;
}
case sub: {
cc.sub(a, b);
break;
}
case band: {
cc.and_(a, b);
break;
}
case bor: {
cc.or_(a, b);
break;
}
case bxor: {
cc.xor_(a, b);
break;
}
case shl: {
cc.shl(a, b);
break;
}
case sar: {
cc.sar(a, b);
break;
}
case shr: {
cc.shr(a, b);
break;
}
default:
throw std::runtime_error(fmt::format("Current operation {} not supported in gen_operation (operation)", op));
}
return a;
}
enum three_operand_operation { imul, mul, idiv, div, srem, urem };
x86::Gp gen_operation(jit_holder& jh, three_operand_operation op, x86::Gp a, x86::Gp b) {
x86::Compiler& cc = jh.cc;
switch(op) {
case imul: {
x86::Gp dummy = cc.newInt64();
cc.imul(dummy, a.r64(), b.r64());
return a;
}
case mul: {
x86::Gp dummy = cc.newInt64();
cc.mul(dummy, a.r64(), b.r64());
return a;
}
case idiv: {
x86::Gp dummy = cc.newInt64();
cc.mov(dummy, 0);
cc.idiv(dummy, a.r64(), b.r64());
return a;
}
case div: {
x86::Gp dummy = cc.newInt64();
cc.mov(dummy, 0);
cc.div(dummy, a.r64(), b.r64());
return a;
}
case srem: {
x86::Gp rem = cc.newInt32();
cc.mov(rem, 0);
auto a_reg = cc.newInt32();
cc.mov(a_reg, a.r32());
cc.idiv(rem, a_reg, b.r32());
return rem;
}
case urem: {
x86::Gp rem = cc.newInt32();
cc.mov(rem, 0);
auto a_reg = cc.newInt32();
cc.mov(a_reg, a.r32());
cc.div(rem, a_reg, b.r32());
return rem;
}
default:
throw std::runtime_error(fmt::format("Current operation {} not supported in gen_operation (three_operand)", op));
}
return a;
}
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
x86::Gp gen_operation(jit_holder& jh, three_operand_operation op, x86::Gp a, T b) {
x86::Gp b_reg = jh.cc.newInt32();
/* switch(a.size()){
case 1: b_reg = jh.cc.newInt8(); break;
case 2: b_reg = jh.cc.newInt16(); break;
case 4: b_reg = jh.cc.newInt32(); break;
case 8: b_reg = jh.cc.newInt64(); break;
default: throw std::runtime_error(fmt::format("Invalid size ({}) in gen operation", a.size()));
} */
jh.cc.mov(b_reg, b);
return gen_operation(jh, op, a, b_reg);
}
enum comparison_operation { land, lor, eq, ne, lt, ltu, gt, gtu, lte, lteu, gte, gteu };
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value || std::is_same<T, x86::Gp>::value>>
x86::Gp gen_operation(jit_holder& jh, comparison_operation op, x86::Gp a, T b) {
x86::Compiler& cc = jh.cc;
x86::Gp tmp = cc.newInt8();
cc.mov(tmp, 1);
Label label_then = cc.newLabel();
cc.cmp(a, b);
switch(op) {
case eq:
cc.je(label_then);
break;
case ne:
cc.jne(label_then);
break;
case lt:
cc.jl(label_then);
break;
case ltu:
cc.jb(label_then);
break;
case gt:
cc.jg(label_then);
break;
case gtu:
cc.ja(label_then);
break;
case lte:
cc.jle(label_then);
break;
case lteu:
cc.jbe(label_then);
break;
case gte:
cc.jge(label_then);
break;
case gteu:
cc.jae(label_then);
break;
case land: {
Label label_false = cc.newLabel();
cc.cmp(a, 0);
cc.je(label_false);
auto b_reg = cc.newInt8();
cc.mov(b_reg, b);
cc.cmp(b_reg, 0);
cc.je(label_false);
cc.jmp(label_then);
cc.bind(label_false);
break;
}
case lor: {
cc.cmp(a, 0);
cc.jne(label_then);
auto b_reg = cc.newInt8();
cc.mov(b_reg, b);
cc.cmp(b_reg, 0);
cc.jne(label_then);
break;
}
default:
throw std::runtime_error(fmt::format("Current operation {} not supported in gen_operation (comparison)", op));
}
cc.mov(tmp, 0);
cc.bind(label_then);
return tmp;
}
enum binary_operation { lnot, inc, dec, bnot, neg };
x86::Gp gen_operation(jit_holder& jh, binary_operation op, x86::Gp a) {
x86::Compiler& cc = jh.cc;
switch(op) {
case lnot:
throw std::runtime_error("Current operation not supported in gen_operation(lnot)");
case inc: {
cc.inc(a);
break;
}
case dec: {
cc.dec(a);
break;
}
case bnot: {
cc.not_(a);
break;
}
case neg: {
cc.neg(a);
break;
}
default:
throw std::runtime_error(fmt::format("Current operation {} not supported in gen_operation (unary)", op));
}
return a;
}
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) {
auto val_reg = get_reg_for(jh, sizeof(val) * 8, is_signed);
jh.cc.mov(val_reg, val);
return gen_ext(jh, val_reg, size, is_signed);
}
inline x86::Gp gen_ext(jit_holder& jh, x86::Gp val, unsigned size, bool is_signed) {
auto& cc = jh.cc;
if(is_signed) {
switch(val.size()) {
case 1:
cc.cbw(val);
break;
case 2:
cc.cwde(val);
break;
case 4:
cc.cdqe(val);
break;
case 8:
break;
default:
throw std::runtime_error("Invalid register size in gen_ext");
}
}
switch(size) {
case 8:
cc.and_(val, std::numeric_limits<uint8_t>::max());
return val.r8();
case 16:
cc.and_(val, std::numeric_limits<uint16_t>::max());
return val.r16();
case 32:
cc.and_(val, std::numeric_limits<uint32_t>::max());
return val.r32();
case 64:
cc.and_(val, std::numeric_limits<uint64_t>::max());
return val.r64();
case 128:
return val.r64();
default:
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) {
x86::Compiler& cc = jh.cc;
auto ret_reg = cc.newInt32();
auto mem_type_reg = cc.newInt32();
cc.mov(mem_type_reg, type);
auto space_reg = cc.newInt32();
cc.mov(space_reg, static_cast<uint16_t>(iss::address_type::VIRTUAL));
auto val_ptr = cc.newUIntPtr();
cc.mov(val_ptr, read_mem_buf);
InvokeNode* invokeNode;
uint64_t mask = 0;
x86::Gp val_reg = cc.newInt64();
switch(length) {
case 1: {
cc.invoke(&invokeNode, &read_mem1, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uintptr_t>());
mask = std::numeric_limits<uint8_t>::max();
break;
}
case 2: {
cc.invoke(&invokeNode, &read_mem2, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uintptr_t>());
mask = std::numeric_limits<uint16_t>::max();
break;
}
case 4: {
cc.invoke(&invokeNode, &read_mem4, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uintptr_t>());
mask = std::numeric_limits<uint32_t>::max();
break;
}
case 8: {
cc.invoke(&invokeNode, &read_mem8, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uintptr_t>());
mask = std::numeric_limits<uint64_t>::max();
break;
}
default:
throw std::runtime_error(fmt::format("Invalid length ({}) in gen_read_mem", length));
}
invokeNode->setRet(0, ret_reg);
invokeNode->setArg(0, jh.arch_if_ptr);
invokeNode->setArg(1, space_reg);
invokeNode->setArg(2, mem_type_reg);
invokeNode->setArg(3, addr);
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.and_(val_reg, mask);
return val_reg;
}
inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, x86::Gp length) {
throw std::runtime_error("Invalid gen_read_mem");
}
inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, uint64_t addr, x86::Gp length) {
throw std::runtime_error("Invalid gen_read_mem");
}
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();
jh.cc.mov(addr_reg, addr);
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, uint32_t length) {
auto val_reg = get_reg_for(jh, length * 8, true);
jh.cc.mov(val_reg, val);
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, uint32_t length) {
x86::Compiler& cc = jh.cc;
assert(val.size() == length);
auto mem_type_reg = cc.newInt32();
jh.cc.mov(mem_type_reg, type);
auto space_reg = cc.newInt32();
jh.cc.mov(space_reg, static_cast<uint16_t>(iss::address_type::VIRTUAL));
auto ret_reg = cc.newInt32();
InvokeNode* invokeNode;
switch(length) {
case 1:
cc.invoke(&invokeNode, &write_mem1, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint8_t>());
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->setArg(0, jh.arch_if_ptr);
invokeNode->setArg(1, space_reg);
invokeNode->setArg(2, mem_type_reg);
invokeNode->setArg(3, addr);
invokeNode->setArg(4, val);
cc.cmp(ret_reg, 0);
cc.jne(jh.trap_entry);
}
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.newUInt64();
jh.cc.mov(addr_reg, addr);
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, uint32_t length) {
auto val_reg = get_reg_for(jh, length * 8, true);
jh.cc.mov(val_reg, val);
auto addr_reg = jh.cc.newUInt64();
jh.cc.mov(addr_reg, addr);
gen_write_mem(jh, type, addr_reg, val_reg, length);
}

File diff suppressed because it is too large Load Diff

View File

@ -429,7 +429,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)(*PC + (int32_t)imm); *(X+rd) = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int32_t)imm ));
} }
} }
} }
@ -459,9 +459,9 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)(*PC + 4); *(X+rd) = (uint32_t)((uint64_t)(*PC ) + (uint64_t)( 4 ));
} }
*NEXT_PC = (uint32_t)(*PC + (int32_t)sext<21>(imm)); *NEXT_PC = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int32_t)sext<21>(imm) ));
this->core.reg.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
@ -489,13 +489,13 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
uint32_t addr_mask = (uint32_t)- 2; uint32_t addr_mask = (uint32_t)- 2;
uint32_t new_pc = (uint32_t)((*(X+rs1) + (int16_t)sext<12>(imm)) & 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) {
raise(0, 0); raise(0, 0);
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)(*PC + 4); *(X+rd) = (uint32_t)((uint64_t)(*PC ) + (uint64_t)( 4 ));
} }
*NEXT_PC = new_pc; *NEXT_PC = new_pc;
this->core.reg.last_branch = 1; this->core.reg.last_branch = 1;
@ -525,11 +525,11 @@ 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(imm % traits::INSTR_ALIGNMENT) { if((uint32_t)(imm ) % traits::INSTR_ALIGNMENT) {
raise(0, 0); raise(0, 0);
} }
else { else {
*NEXT_PC = (uint32_t)(*PC + (int16_t)sext<13>(imm)); *NEXT_PC = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int16_t)sext<13>(imm) ));
this->core.reg.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
@ -558,11 +558,11 @@ 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(imm % traits::INSTR_ALIGNMENT) { if((uint32_t)(imm ) % traits::INSTR_ALIGNMENT) {
raise(0, 0); raise(0, 0);
} }
else { else {
*NEXT_PC = (uint32_t)(*PC + (int16_t)sext<13>(imm)); *NEXT_PC = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int16_t)sext<13>(imm) ));
this->core.reg.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
@ -591,11 +591,11 @@ 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(imm % traits::INSTR_ALIGNMENT) { if((uint32_t)(imm ) % traits::INSTR_ALIGNMENT) {
raise(0, 0); raise(0, 0);
} }
else { else {
*NEXT_PC = (uint32_t)(*PC + (int16_t)sext<13>(imm)); *NEXT_PC = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int16_t)sext<13>(imm) ));
this->core.reg.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
@ -624,11 +624,11 @@ 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(imm % traits::INSTR_ALIGNMENT) { if((uint32_t)(imm ) % traits::INSTR_ALIGNMENT) {
raise(0, 0); raise(0, 0);
} }
else { else {
*NEXT_PC = (uint32_t)(*PC + (int16_t)sext<13>(imm)); *NEXT_PC = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int16_t)sext<13>(imm) ));
this->core.reg.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
@ -657,11 +657,11 @@ 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(imm % traits::INSTR_ALIGNMENT) { if((uint32_t)(imm ) % traits::INSTR_ALIGNMENT) {
raise(0, 0); raise(0, 0);
} }
else { else {
*NEXT_PC = (uint32_t)(*PC + (int16_t)sext<13>(imm)); *NEXT_PC = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int16_t)sext<13>(imm) ));
this->core.reg.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
@ -690,11 +690,11 @@ 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(imm % traits::INSTR_ALIGNMENT) { if((uint32_t)(imm ) % traits::INSTR_ALIGNMENT) {
raise(0, 0); raise(0, 0);
} }
else { else {
*NEXT_PC = (uint32_t)(*PC + (int16_t)sext<13>(imm)); *NEXT_PC = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int16_t)sext<13>(imm) ));
this->core.reg.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
@ -722,7 +722,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
uint32_t load_address = (uint32_t)(*(X+rs1) + (int16_t)sext<12>(imm)); uint32_t load_address = (uint32_t)((uint64_t)(*(X+rs1) ) + (uint64_t)((int16_t)sext<12>(imm) ));
int8_t res_27 = super::template read_mem<int8_t>(traits::MEM, load_address); int8_t res_27 = super::template read_mem<int8_t>(traits::MEM, load_address);
if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception(); if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception();
int8_t res = (int8_t)res_27; int8_t res = (int8_t)res_27;
@ -753,7 +753,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
uint32_t load_address = (uint32_t)(*(X+rs1) + (int16_t)sext<12>(imm)); uint32_t load_address = (uint32_t)((uint64_t)(*(X+rs1) ) + (uint64_t)((int16_t)sext<12>(imm) ));
int16_t res_28 = super::template read_mem<int16_t>(traits::MEM, load_address); int16_t res_28 = super::template read_mem<int16_t>(traits::MEM, load_address);
if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception(); if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception();
int16_t res = (int16_t)res_28; int16_t res = (int16_t)res_28;
@ -784,7 +784,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
uint32_t load_address = (uint32_t)(*(X+rs1) + (int16_t)sext<12>(imm)); uint32_t load_address = (uint32_t)((uint64_t)(*(X+rs1) ) + (uint64_t)((int16_t)sext<12>(imm) ));
int32_t res_29 = super::template read_mem<int32_t>(traits::MEM, load_address); int32_t res_29 = super::template read_mem<int32_t>(traits::MEM, load_address);
if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception(); if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception();
int32_t res = (int32_t)res_29; int32_t res = (int32_t)res_29;
@ -815,7 +815,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
uint32_t load_address = (uint32_t)(*(X+rs1) + (int16_t)sext<12>(imm)); uint32_t load_address = (uint32_t)((uint64_t)(*(X+rs1) ) + (uint64_t)((int16_t)sext<12>(imm) ));
uint8_t res_30 = super::template read_mem<uint8_t>(traits::MEM, load_address); uint8_t res_30 = super::template read_mem<uint8_t>(traits::MEM, load_address);
if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception(); if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception();
uint8_t res = res_30; uint8_t res = res_30;
@ -846,7 +846,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
uint32_t load_address = (uint32_t)(*(X+rs1) + (int16_t)sext<12>(imm)); uint32_t load_address = (uint32_t)((uint64_t)(*(X+rs1) ) + (uint64_t)((int16_t)sext<12>(imm) ));
uint16_t res_31 = super::template read_mem<uint16_t>(traits::MEM, load_address); uint16_t res_31 = super::template read_mem<uint16_t>(traits::MEM, load_address);
if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception(); if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception();
uint16_t res = res_31; uint16_t res = res_31;
@ -877,7 +877,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
uint32_t store_address = (uint32_t)(*(X+rs1) + (int16_t)sext<12>(imm)); uint32_t store_address = (uint32_t)((uint64_t)(*(X+rs1) ) + (uint64_t)((int16_t)sext<12>(imm) ));
super::template write_mem<uint8_t>(traits::MEM, store_address, (uint8_t)*(X+rs2)); super::template write_mem<uint8_t>(traits::MEM, store_address, (uint8_t)*(X+rs2));
if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception(); if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception();
} }
@ -904,7 +904,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
uint32_t store_address = (uint32_t)(*(X+rs1) + (int16_t)sext<12>(imm)); uint32_t store_address = (uint32_t)((uint64_t)(*(X+rs1) ) + (uint64_t)((int16_t)sext<12>(imm) ));
super::template write_mem<uint16_t>(traits::MEM, store_address, (uint16_t)*(X+rs2)); super::template write_mem<uint16_t>(traits::MEM, store_address, (uint16_t)*(X+rs2));
if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception(); if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception();
} }
@ -931,7 +931,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
uint32_t store_address = (uint32_t)(*(X+rs1) + (int16_t)sext<12>(imm)); uint32_t store_address = (uint32_t)((uint64_t)(*(X+rs1) ) + (uint64_t)((int16_t)sext<12>(imm) ));
super::template write_mem<uint32_t>(traits::MEM, store_address, (uint32_t)*(X+rs2)); super::template write_mem<uint32_t>(traits::MEM, store_address, (uint32_t)*(X+rs2));
if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception(); if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception();
} }
@ -959,7 +959,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)(*(X+rs1) + (int16_t)sext<12>(imm)); *(X+rd) = (uint32_t)((uint64_t)(*(X+rs1) ) + (uint64_t)((int16_t)sext<12>(imm) ));
} }
} }
} }
@ -1202,7 +1202,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)(*(X+rs1) + *(X+rs2)); *(X+rd) = (uint32_t)((uint64_t)(*(X+rs1) ) + (uint64_t)(*(X+rs2) ));
} }
} }
} }
@ -1229,7 +1229,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)(*(X+rs1) - *(X+rs2)); *(X+rd) = (uint32_t)((uint64_t)(*(X+rs1) ) - (uint64_t)(*(X+rs2) ));
} }
} }
} }
@ -1256,7 +1256,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = *(X+rs1) << (*(X+rs2) & (traits::XLEN - 1)); *(X+rd) = *(X+rs1) << ((uint64_t)(*(X+rs2) ) & ((uint64_t)(traits::XLEN ) - (uint64_t)( 1 )));
} }
} }
} }
@ -1364,7 +1364,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = *(X+rs1) >> (*(X+rs2) & (traits::XLEN - 1)); *(X+rd) = *(X+rs1) >> ((uint64_t)(*(X+rs2) ) & ((uint64_t)(traits::XLEN ) - (uint64_t)( 1 )));
} }
} }
} }
@ -1391,7 +1391,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)((int32_t)*(X+rs1) >> (*(X+rs2) & (traits::XLEN - 1))); *(X+rd) = (uint32_t)((int32_t)*(X+rs1) >> ((uint64_t)(*(X+rs2) ) & ((uint64_t)(traits::XLEN ) - (uint64_t)( 1 ))));
} }
} }
} }
@ -1772,7 +1772,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
int64_t res = (int64_t)((int64_t)(int32_t)*(X+rs1) * (int64_t)(int32_t)*(X+rs2)); int64_t res = (int64_t)((int32_t)*(X+rs1) ) * (int64_t)((int32_t)*(X+rs2) );
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)res; *(X+rd) = (uint32_t)res;
} }
@ -1800,7 +1800,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
int64_t res = (int64_t)((int64_t)(int32_t)*(X+rs1) * (int64_t)(int32_t)*(X+rs2)); int64_t res = (int64_t)((int32_t)*(X+rs1) ) * (int64_t)((int32_t)*(X+rs2) );
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)(res >> traits::XLEN); *(X+rd) = (uint32_t)(res >> traits::XLEN);
} }
@ -1828,7 +1828,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
int64_t res = (int64_t)((int64_t)(int32_t)*(X+rs1) * (uint64_t)*(X+rs2)); int64_t res = (int64_t)((int32_t)*(X+rs1) ) * (int64_t)(*(X+rs2) );
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)(res >> traits::XLEN); *(X+rd) = (uint32_t)(res >> traits::XLEN);
} }
@ -1856,7 +1856,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
uint64_t res = (uint64_t)((uint64_t)*(X+rs1) * (uint64_t)*(X+rs2)); uint64_t res = (uint64_t)(*(X+rs1) ) * (uint64_t)(*(X+rs2) );
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)(res >> traits::XLEN); *(X+rd) = (uint32_t)(res >> traits::XLEN);
} }
@ -1888,7 +1888,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
int32_t divisor = (int32_t)*(X+rs2); int32_t divisor = (int32_t)*(X+rs2);
if(rd != 0) { if(rd != 0) {
if(divisor != 0) { if(divisor != 0) {
uint32_t MMIN = ((uint32_t)1) << (traits::XLEN - 1); uint32_t MMIN = ((uint32_t)1) << ((uint64_t)(traits::XLEN ) - (uint64_t)(1 ));
if(*(X+rs1) == MMIN && divisor == - 1) { if(*(X+rs1) == MMIN && divisor == - 1) {
*(X+rd) = MMIN; *(X+rd) = MMIN;
} }
@ -1926,7 +1926,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
else { else {
if(*(X+rs2) != 0) { if(*(X+rs2) != 0) {
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)(*(X+rs1) / *(X+rs2)); *(X+rd) = *(X+rs1) / *(X+rs2);
} }
} }
else { else {
@ -1959,7 +1959,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(*(X+rs2) != 0) { if(*(X+rs2) != 0) {
uint32_t MMIN = (uint32_t)1 << (traits::XLEN - 1); uint32_t MMIN = (uint32_t)1 << ((uint64_t)(traits::XLEN ) - (uint64_t)(1 ));
if(*(X+rs1) == MMIN && (int32_t)*(X+rs2) == - 1) { if(*(X+rs1) == MMIN && (int32_t)*(X+rs2) == - 1) {
if(rd != 0) { if(rd != 0) {
*(X+rd) = 0; *(X+rd) = 0;
@ -1967,7 +1967,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)((int32_t)*(X+rs1) % (int32_t)*(X+rs2)); *(X+rd) = ((uint32_t)((int32_t)*(X+rs1) % (int32_t)*(X+rs2)));
} }
} }
} }
@ -2030,7 +2030,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
// execute instruction // execute instruction
{ {
if(imm) { if(imm) {
*(X+rd + 8) = (uint32_t)(*(X+2) + imm); *(X+rd + 8) = (uint32_t)((uint64_t)(*(X+2) ) + (uint64_t)(imm ));
} }
else { else {
raise(0, 2); raise(0, 2);
@ -2054,7 +2054,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
*NEXT_PC = *PC + 2; *NEXT_PC = *PC + 2;
// execute instruction // execute instruction
{ {
uint32_t offs = (uint32_t)(*(X+rs1 + 8) + uimm); uint32_t offs = (uint32_t)((uint64_t)(*(X+rs1 + 8) ) + (uint64_t)(uimm ));
int32_t res_38 = super::template read_mem<int32_t>(traits::MEM, offs); int32_t res_38 = super::template read_mem<int32_t>(traits::MEM, offs);
if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception(); if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception();
*(X+rd + 8) = (uint32_t)(int32_t)res_38; *(X+rd + 8) = (uint32_t)(int32_t)res_38;
@ -2077,7 +2077,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
*NEXT_PC = *PC + 2; *NEXT_PC = *PC + 2;
// execute instruction // execute instruction
{ {
uint32_t offs = (uint32_t)(*(X+rs1 + 8) + uimm); uint32_t offs = (uint32_t)((uint64_t)(*(X+rs1 + 8) ) + (uint64_t)(uimm ));
super::template write_mem<uint32_t>(traits::MEM, offs, (uint32_t)*(X+rs2 + 8)); super::template write_mem<uint32_t>(traits::MEM, offs, (uint32_t)*(X+rs2 + 8));
if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception(); if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception();
} }
@ -2103,7 +2103,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(rs1 != 0) { if(rs1 != 0) {
*(X+rs1) = (uint32_t)(*(X+rs1) + (int8_t)sext<6>(imm)); *(X+rs1) = (uint32_t)((uint64_t)(*(X+rs1) ) + (uint64_t)((int8_t)sext<6>(imm) ));
} }
} }
} }
@ -2136,8 +2136,8 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
*NEXT_PC = *PC + 2; *NEXT_PC = *PC + 2;
// execute instruction // execute instruction
{ {
*(X+1) = (uint32_t)(*PC + 2); *(X+1) = (uint32_t)((uint64_t)(*PC ) + (uint64_t)( 2 ));
*NEXT_PC = (uint32_t)(*PC + (int16_t)sext<12>(imm)); *NEXT_PC = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int16_t)sext<12>(imm) ));
this->core.reg.last_branch = 1; this->core.reg.last_branch = 1;
} }
break; break;
@ -2207,7 +2207,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
// execute instruction // execute instruction
{ {
if(nzimm) { if(nzimm) {
*(X+2) = (uint32_t)(*(X+2) + (int16_t)sext<10>(nzimm)); *(X+2) = (uint32_t)((uint64_t)(*(X+2) ) + (uint64_t)((int16_t)sext<10>(nzimm) ));
} }
else { else {
raise(0, 2); raise(0, 2);
@ -2289,7 +2289,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
*NEXT_PC = *PC + 2; *NEXT_PC = *PC + 2;
// execute instruction // execute instruction
{ {
*(X+rs1 + 8) = (uint32_t)(*(X+rs1 + 8) & (int8_t)sext<6>(imm)); *(X+rs1 + 8) = (uint32_t)(*(X+rs1 + 8) & (uint32_t)((int8_t)sext<6>(imm) ));
} }
break; break;
}// @suppress("No break at end of case") }// @suppress("No break at end of case")
@ -2308,7 +2308,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
*NEXT_PC = *PC + 2; *NEXT_PC = *PC + 2;
// execute instruction // execute instruction
{ {
*(X+rd + 8) = (uint32_t)(*(X+rd + 8) - *(X+rs2 + 8)); *(X+rd + 8) = (uint32_t)((uint64_t)(*(X+rd + 8) ) - (uint64_t)(*(X+rs2 + 8) ));
} }
break; break;
}// @suppress("No break at end of case") }// @suppress("No break at end of case")
@ -2382,7 +2382,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
*NEXT_PC = *PC + 2; *NEXT_PC = *PC + 2;
// execute instruction // execute instruction
{ {
*NEXT_PC = (uint32_t)(*PC + (int16_t)sext<12>(imm)); *NEXT_PC = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int16_t)sext<12>(imm) ));
this->core.reg.last_branch = 1; this->core.reg.last_branch = 1;
} }
break; break;
@ -2403,7 +2403,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
// execute instruction // execute instruction
{ {
if(*(X+rs1 + 8) == 0) { if(*(X+rs1 + 8) == 0) {
*NEXT_PC = (uint32_t)(*PC + (int16_t)sext<9>(imm)); *NEXT_PC = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int16_t)sext<9>(imm) ));
this->core.reg.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
@ -2425,7 +2425,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
// execute instruction // execute instruction
{ {
if(*(X+rs1 + 8) != 0) { if(*(X+rs1 + 8) != 0) {
*NEXT_PC = (uint32_t)(*PC + (int16_t)sext<9>(imm)); *NEXT_PC = (uint32_t)((uint64_t)(*PC ) + (uint64_t)((int16_t)sext<9>(imm) ));
this->core.reg.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
@ -2476,7 +2476,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
uint32_t offs = (uint32_t)(*(X+2) + uimm); uint32_t offs = (uint32_t)((uint64_t)(*(X+2) ) + (uint64_t)(uimm ));
int32_t res_39 = super::template read_mem<int32_t>(traits::MEM, offs); int32_t res_39 = super::template read_mem<int32_t>(traits::MEM, offs);
if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception(); if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception();
*(X+rd) = (uint32_t)(int32_t)res_39; *(X+rd) = (uint32_t)(int32_t)res_39;
@ -2525,7 +2525,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
// execute instruction // execute instruction
{ {
if(rs1 && rs1 < traits::RFS) { if(rs1 && rs1 < traits::RFS) {
*NEXT_PC = *(X+rs1 % traits::RFS) & ~ 0x1; *NEXT_PC = *(X+(uint32_t)(rs1 ) % traits::RFS) & (uint32_t)(~ 0x1 );
this->core.reg.last_branch = 1; this->core.reg.last_branch = 1;
} }
else { else {
@ -2567,7 +2567,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)(*(X+rd) + *(X+rs2)); *(X+rd) = (uint32_t)((uint64_t)(*(X+rd) ) + (uint64_t)(*(X+rs2) ));
} }
} }
} }
@ -2592,8 +2592,8 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
uint32_t new_pc = *(X+rs1); uint32_t new_pc = *(X+rs1);
*(X+1) = (uint32_t)(*PC + 2); *(X+1) = (uint32_t)((uint64_t)(*PC ) + (uint64_t)( 2 ));
*NEXT_PC = new_pc & ~ 0x1; *NEXT_PC = new_pc & (uint32_t)(~ 0x1 );
this->core.reg.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
@ -2631,7 +2631,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
uint32_t offs = (uint32_t)(*(X+2) + uimm); uint32_t offs = (uint32_t)((uint64_t)(*(X+2) ) + (uint64_t)(uimm ));
super::template write_mem<uint32_t>(traits::MEM, offs, (uint32_t)*(X+rs2)); super::template write_mem<uint32_t>(traits::MEM, offs, (uint32_t)*(X+rs2));
if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception(); if(this->core.reg.trap_state>=0x80000000UL) throw memory_access_exception();
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff