Compare commits
16 Commits
c054d75717
...
Trace_enha
Author | SHA1 | Date | |
---|---|---|---|
1720bd4aaa | |||
df16378605 | |||
1438f0f373 | |||
766f3ba9ee | |||
5da4e6b424 | |||
e382217e04 | |||
9db4e3fd87 | |||
bb658be3b4 | |||
6579780dc9 | |||
e56bc12788 | |||
e88f309ea2 | |||
03bec27376 | |||
9d9008a3a2 | |||
5f6d462973 | |||
a92b84bef4 | |||
477c530847 |
@ -83,6 +83,10 @@ elseif(TARGET elfio::elfio)
|
||||
else()
|
||||
message(FATAL_ERROR "No elfio library found, maybe a find_package() call is missing")
|
||||
endif()
|
||||
if(TARGET lz4::lz4)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_LZ4)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC lz4::lz4)
|
||||
endif()
|
||||
if(TARGET RapidJSON)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC RapidJSON)
|
||||
endif()
|
||||
|
@ -1,6 +1,6 @@
|
||||
import "CoreDSL-Instruction-Set-Description/RV32I.core_desc"
|
||||
import "CoreDSL-Instruction-Set-Description/RVM.core_desc"
|
||||
import "CoreDSL-Instruction-Set-Description/RVC.core_desc"
|
||||
import "RV32I.core_desc"
|
||||
import "RVM.core_desc"
|
||||
import "RVC.core_desc"
|
||||
|
||||
Core TGC_C provides RV32I, Zicsr, Zifencei, RV32M, RV32IC {
|
||||
architectural_state {
|
||||
|
@ -33,7 +33,7 @@
|
||||
def getRegisterSizes(){
|
||||
def regs = registers.collect{it.size}
|
||||
regs[-1]=64 // correct for NEXT_PC
|
||||
regs+=[32, 32, 64, 64, 64] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET
|
||||
//regs+=[32, 32, 64, 64, 64, 32] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION
|
||||
return regs
|
||||
}
|
||||
%>
|
||||
@ -51,9 +51,7 @@ constexpr std::array<const char*, ${registers.size}> iss::arch::traits<iss::a
|
||||
constexpr std::array<const uint32_t, ${getRegisterSizes().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_bit_widths;
|
||||
constexpr std::array<const uint32_t, ${getRegisterSizes().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_byte_offsets;
|
||||
|
||||
${coreDef.name.toLowerCase()}::${coreDef.name.toLowerCase()}() {
|
||||
reg.icount = 0;
|
||||
}
|
||||
${coreDef.name.toLowerCase()}::${coreDef.name.toLowerCase()}() = default;
|
||||
|
||||
${coreDef.name.toLowerCase()}::~${coreDef.name.toLowerCase()}() = default;
|
||||
|
||||
@ -64,8 +62,8 @@ void ${coreDef.name.toLowerCase()}::reset(uint64_t address) {
|
||||
reg.PC=address;
|
||||
reg.NEXT_PC=reg.PC;
|
||||
reg.PRIV=0x3;
|
||||
reg.trap_state=0;
|
||||
reg.icount=0;
|
||||
trap_state=0;
|
||||
icount=0;
|
||||
}
|
||||
|
||||
uint8_t *${coreDef.name.toLowerCase()}::get_regs_base_ptr() {
|
||||
|
@ -37,7 +37,7 @@ def nativeTypeSize(int size){
|
||||
}
|
||||
def getRegisterSizes(){
|
||||
def regs = registers.collect{nativeTypeSize(it.size)}
|
||||
regs+=[32,32, 64, 64, 64] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET
|
||||
// regs+=[32,32, 64, 64, 64, 32] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION
|
||||
return regs
|
||||
}
|
||||
def getRegisterOffsets(){
|
||||
@ -91,12 +91,7 @@ template <> struct traits<${coreDef.name.toLowerCase()}> {
|
||||
constexpr static unsigned FP_REGS_SIZE = ${constants.find {it.name=='FLEN'}?.value?:0};
|
||||
|
||||
enum reg_e {
|
||||
${registers.collect{it.name}.join(', ')}, NUM_REGS,
|
||||
TRAP_STATE=NUM_REGS,
|
||||
PENDING_TRAP,
|
||||
ICOUNT,
|
||||
CYCLE,
|
||||
INSTRET
|
||||
${registers.collect{it.name}.join(', ')}, NUM_REGS
|
||||
};
|
||||
|
||||
using reg_t = uint${addrDataWidth}_t;
|
||||
@ -141,7 +136,7 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
|
||||
|
||||
uint8_t* get_regs_base_ptr() override;
|
||||
|
||||
inline uint64_t get_icount() { return reg.icount; }
|
||||
inline uint64_t get_icount() { return icount; }
|
||||
|
||||
inline bool should_stop() { return interrupt_sim; }
|
||||
|
||||
@ -159,7 +154,7 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
|
||||
|
||||
virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
|
||||
|
||||
inline uint32_t get_last_branch() { return reg.last_branch; }
|
||||
inline uint32_t get_last_branch() { return last_branch; }
|
||||
|
||||
|
||||
#pragma pack(push, 1)
|
||||
@ -167,12 +162,14 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
|
||||
registers.each { reg -> if(reg.size>0) {%>
|
||||
uint${byteSize(reg.size)}_t ${reg.name} = 0;<%
|
||||
}}%>
|
||||
uint32_t trap_state = 0, pending_trap = 0;
|
||||
uint64_t icount = 0;
|
||||
uint64_t instret = 0;
|
||||
uint32_t last_branch;
|
||||
} reg;
|
||||
#pragma pack(pop)
|
||||
uint32_t trap_state = 0, pending_trap = 0;
|
||||
uint64_t icount = 0;
|
||||
uint64_t cycle = 0;
|
||||
uint64_t instret = 0;
|
||||
uint32_t instruction = 0;
|
||||
uint32_t last_branch = 0;
|
||||
std::array<address_type, 4> addr_mode;
|
||||
|
||||
uint64_t interrupt_sim=0;
|
||||
|
@ -121,7 +121,7 @@ protected:
|
||||
|
||||
inline void raise(uint16_t trap_id, uint16_t cause){
|
||||
auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id;
|
||||
this->template get_reg<uint32_t>(traits::TRAP_STATE) = trap_val;
|
||||
this->core.trap_state = trap_val;
|
||||
this->template get_reg<uint32_t>(traits::NEXT_PC) = std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
|
||||
@ -141,39 +141,39 @@ protected:
|
||||
T& pc_assign(T& val){super::ex_info.branch_taken=true; return val;}
|
||||
inline uint8_t readSpace1(typename super::mem_type_e space, uint64_t addr){
|
||||
auto ret = super::template read_mem<uint8_t>(space, addr);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
if(this->core.trap_state) throw 0;
|
||||
return ret;
|
||||
}
|
||||
inline uint16_t readSpace2(typename super::mem_type_e space, uint64_t addr){
|
||||
auto ret = super::template read_mem<uint16_t>(space, addr);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
if(this->core.trap_state) throw 0;
|
||||
return ret;
|
||||
}
|
||||
inline uint32_t readSpace4(typename super::mem_type_e space, uint64_t addr){
|
||||
auto ret = super::template read_mem<uint32_t>(space, addr);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
if(this->core.trap_state) throw 0;
|
||||
return ret;
|
||||
}
|
||||
inline uint64_t readSpace8(typename super::mem_type_e space, uint64_t addr){
|
||||
auto ret = super::template read_mem<uint64_t>(space, addr);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
if(this->core.trap_state) throw 0;
|
||||
return ret;
|
||||
}
|
||||
inline void writeSpace1(typename super::mem_type_e space, uint64_t addr, uint8_t data){
|
||||
super::write_mem(space, addr, data);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
if(this->core.trap_state) throw 0;
|
||||
}
|
||||
inline void writeSpace2(typename super::mem_type_e space, uint64_t addr, uint16_t data){
|
||||
super::write_mem(space, addr, data);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
if(this->core.trap_state) throw 0;
|
||||
}
|
||||
inline void writeSpace4(typename super::mem_type_e space, uint64_t addr, uint32_t data){
|
||||
super::write_mem(space, addr, data);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
if(this->core.trap_state) throw 0;
|
||||
}
|
||||
inline void writeSpace8(typename super::mem_type_e space, uint64_t addr, uint64_t data){
|
||||
super::write_mem(space, addr, data);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
if(this->core.trap_state) throw 0;
|
||||
}
|
||||
template<unsigned W, typename U, typename S = typename std::make_signed<U>::type>
|
||||
inline S sext(U from) {
|
||||
@ -277,16 +277,16 @@ typename arch::traits<ARCH>::opcode_e vm_impl<ARCH>::decode_inst_id(code_word_t
|
||||
|
||||
template <typename ARCH>
|
||||
typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit){
|
||||
// we fetch at max 4 byte, alignment is 2
|
||||
code_word_t instr = 0;
|
||||
auto *const data = (uint8_t *)&instr;
|
||||
auto pc=start;
|
||||
|
||||
auto* PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
|
||||
auto* NEXT_PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
|
||||
auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]);
|
||||
auto* icount = reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::ICOUNT]);
|
||||
auto* instret = reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::INSTRET]);
|
||||
auto& trap_state = this->core.trap_state;
|
||||
auto& icount = this->core.icount;
|
||||
auto& cycle = this->core.cycle;
|
||||
auto& instret = this->core.instret;
|
||||
auto& instr = this->core.instruction;
|
||||
// we fetch at max 4 byte, alignment is 2
|
||||
auto *const data = reinterpret_cast<uint8_t*>(&instr);
|
||||
|
||||
while(!this->core.should_stop() &&
|
||||
!(is_count_limit_enabled(cond) && this->core.get_icount() >= icount_limit)){
|
||||
@ -314,11 +314,9 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
|
||||
<%}}%>// calculate next pc value
|
||||
*NEXT_PC = *PC + ${instr.length/8};
|
||||
// execute instruction
|
||||
try {
|
||||
<%instr.behavior.eachLine{%>${it}
|
||||
<%}%>} catch(...){}
|
||||
}
|
||||
break;<%}%>
|
||||
<%}%>TRAP_${instr.name}:break;
|
||||
}// @suppress("No break at end of case")<%}%>
|
||||
default: {
|
||||
*NEXT_PC = *PC + ((instr & 3) == 3 ? 4 : 2);
|
||||
raise(0, 2);
|
||||
@ -328,16 +326,16 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
|
||||
process_spawn_blocks();
|
||||
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, static_cast<unsigned>(inst_id));
|
||||
// trap check
|
||||
if(*trap_state!=0){
|
||||
super::core.enter_trap(*trap_state, pc.val, instr);
|
||||
if(trap_state!=0){
|
||||
super::core.enter_trap(trap_state, pc.val, instr);
|
||||
} else {
|
||||
(*icount)++;
|
||||
(*instret)++;
|
||||
icount++;
|
||||
instret++;
|
||||
}
|
||||
(*reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::CYCLE]))++;
|
||||
cycle++;
|
||||
pc.val=*NEXT_PC;
|
||||
this->core.reg.PC = this->core.reg.NEXT_PC;
|
||||
this->core.reg.trap_state = this->core.reg.pending_trap;
|
||||
this->core.trap_state = this->core.pending_trap;
|
||||
}
|
||||
}
|
||||
return pc;
|
||||
|
@ -188,7 +188,7 @@ enum {
|
||||
|
||||
template <typename T> inline bool PTE_TABLE(T PTE) { return (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V); }
|
||||
|
||||
enum { PRIV_U = 0, PRIV_S = 1, PRIV_M = 3 };
|
||||
enum { PRIV_U = 0, PRIV_S = 1, PRIV_M = 3, PRIV_D = 4};
|
||||
|
||||
enum {
|
||||
ISA_A = 1,
|
||||
|
@ -203,7 +203,7 @@ public:
|
||||
|
||||
void disass_output(uint64_t pc, const std::string instr) override {
|
||||
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [s:0x{:x};c:{}]",
|
||||
pc, instr, (reg_t)state.mstatus, this->reg.icount + cycle_offset);
|
||||
pc, instr, (reg_t)state.mstatus, this->icount + cycle_offset);
|
||||
};
|
||||
|
||||
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
|
||||
@ -235,13 +235,17 @@ protected:
|
||||
*/
|
||||
const std::string core_type_name() const override { return traits<BASE>::core_type; }
|
||||
|
||||
uint64_t get_pc() override { return arch.get_pc(); };
|
||||
uint64_t get_pc() override { return arch.reg.PC; };
|
||||
|
||||
uint64_t get_next_pc() override { return arch.get_next_pc(); };
|
||||
uint64_t get_next_pc() override { return arch.reg.NEXT_PC; };
|
||||
|
||||
uint64_t get_instr_count() { return arch.reg.icount; }
|
||||
uint64_t get_instr_word() override { return arch.instruction; }
|
||||
|
||||
uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
|
||||
uint64_t get_instr_count() override { return arch.icount; }
|
||||
|
||||
uint64_t get_pendig_traps() override { return arch.trap_state; }
|
||||
|
||||
uint64_t get_total_cycles() override { return arch.icount + arch.cycle_offset; }
|
||||
|
||||
void set_curr_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; };
|
||||
|
||||
@ -249,8 +253,6 @@ protected:
|
||||
};
|
||||
|
||||
friend struct riscv_instrumentation_if;
|
||||
addr_t get_pc() { return this->reg.PC; }
|
||||
addr_t get_next_pc() { return this->reg.NEXT_PC; }
|
||||
|
||||
virtual iss::status read_mem(phys_addr_t addr, unsigned length, uint8_t *const data);
|
||||
virtual iss::status write_mem(phys_addr_t addr, unsigned length, const uint8_t *const data);
|
||||
@ -565,22 +567,22 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
|
||||
try {
|
||||
switch (space) {
|
||||
case traits<BASE>::MEM: {
|
||||
if (unlikely((access == iss::access_type::FETCH || access == iss::access_type::DEBUG_FETCH) && (addr & 0x1) == 1)) {
|
||||
auto alignment = is_fetch(access)? (traits<BASE>::MISA_VAL&0x100? 2 : 4) : length;
|
||||
if (unlikely(is_fetch(access) && (addr&(alignment-1)))) {
|
||||
fault_data = addr;
|
||||
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
|
||||
this->reg.trap_state = (1 << 31); // issue trap 0
|
||||
if (is_debug(access)) throw trap_access(0, addr);
|
||||
this->trap_state = (1 << 31); // issue trap 0
|
||||
return iss::Err;
|
||||
}
|
||||
try {
|
||||
auto alignment = access == iss::access_type::FETCH? (traits<BASE>::MISA_VAL&0x100? 2 : 4) : length;
|
||||
if(alignment>1 && (addr&(alignment-1))){
|
||||
this->reg.trap_state = 1<<31 | 4<<16;
|
||||
if(!is_debug(access) && (addr&(alignment-1))){
|
||||
this->trap_state = 1<<31 | 4<<16;
|
||||
fault_data=addr;
|
||||
return iss::Err;
|
||||
}
|
||||
auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
|
||||
auto res = iss::Err;
|
||||
if(access != access_type::FETCH && memfn_range.size()){
|
||||
if(!is_fetch(access) && memfn_range.size()){
|
||||
auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){
|
||||
return std::get<0>(a)<=phys_addr.val && (std::get<0>(a)+std::get<1>(a))>phys_addr.val;
|
||||
});
|
||||
@ -593,12 +595,12 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
|
||||
res = read_mem( phys_addr, length, data);
|
||||
}
|
||||
if (unlikely(res != iss::Ok)){
|
||||
this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
|
||||
this->trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
|
||||
fault_data=addr;
|
||||
}
|
||||
return res;
|
||||
} catch (trap_access &ta) {
|
||||
this->reg.trap_state = (1 << 31) | ta.id;
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
fault_data=ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -624,7 +626,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
|
||||
}
|
||||
return iss::Ok;
|
||||
} catch (trap_access &ta) {
|
||||
this->reg.trap_state = (1 << 31) | ta.id;
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
fault_data=ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -662,12 +664,12 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
|
||||
if (unlikely((access && iss::access_type::FETCH) && (addr & 0x1) == 1)) {
|
||||
fault_data = addr;
|
||||
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
|
||||
this->reg.trap_state = (1 << 31); // issue trap 0
|
||||
this->trap_state = (1 << 31); // issue trap 0
|
||||
return iss::Err;
|
||||
}
|
||||
try {
|
||||
if(length>1 && (addr&(length-1)) && (access&access_type::DEBUG) != access_type::DEBUG){
|
||||
this->reg.trap_state = 1<<31 | 6<<16;
|
||||
this->trap_state = 1<<31 | 6<<16;
|
||||
fault_data=addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -686,12 +688,12 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
|
||||
res = write_mem( phys_addr, length, data);
|
||||
}
|
||||
if (unlikely(res != iss::Ok)) {
|
||||
this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
||||
this->trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
||||
fault_data=addr;
|
||||
}
|
||||
return res;
|
||||
} catch (trap_access &ta) {
|
||||
this->reg.trap_state = (1 << 31) | ta.id;
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
fault_data=ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -751,7 +753,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
|
||||
}
|
||||
return iss::Ok;
|
||||
} catch (trap_access &ta) {
|
||||
this->reg.trap_state = (1 << 31) | ta.id;
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
fault_data=ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -797,7 +799,7 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_cycle(unsigned addr, reg_t &val) {
|
||||
auto cycle_val = this->reg.icount + cycle_offset;
|
||||
auto cycle_val = this->icount + cycle_offset;
|
||||
if (addr == mcycle) {
|
||||
val = static_cast<reg_t>(cycle_val);
|
||||
} else if (addr == mcycleh) {
|
||||
@ -819,16 +821,16 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
||||
mcycle_csr = (static_cast<uint64_t>(val)<<32) + (mcycle_csr & 0xffffffff);
|
||||
}
|
||||
}
|
||||
cycle_offset = mcycle_csr-this->reg.icount; // TODO: relying on wrap-around
|
||||
cycle_offset = mcycle_csr-this->icount; // TODO: relying on wrap-around
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_instret(unsigned addr, reg_t &val) {
|
||||
if ((addr&0xff) == (minstret&0xff)) {
|
||||
val = static_cast<reg_t>(this->reg.instret);
|
||||
val = static_cast<reg_t>(this->instret);
|
||||
} else if ((addr&0xff) == (minstreth&0xff)) {
|
||||
if (sizeof(typename traits<BASE>::reg_t) != 4) return iss::Err;
|
||||
val = static_cast<reg_t>(this->reg.instret >> 32);
|
||||
val = static_cast<reg_t>(this->instret >> 32);
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
@ -837,20 +839,20 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
|
||||
if (sizeof(typename traits<BASE>::reg_t) != 4) {
|
||||
if ((addr&0xff) == (minstreth&0xff))
|
||||
return iss::Err;
|
||||
this->reg.instret = static_cast<uint64_t>(val);
|
||||
this->instret = static_cast<uint64_t>(val);
|
||||
} else {
|
||||
if ((addr&0xff) == (minstret&0xff)) {
|
||||
this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val;
|
||||
this->instret = (this->instret & 0xffffffff00000000) + val;
|
||||
} else {
|
||||
this->reg.instret = (static_cast<uint64_t>(val)<<32) + (this->reg.instret & 0xffffffff);
|
||||
this->instret = (static_cast<uint64_t>(val)<<32) + (this->instret & 0xffffffff);
|
||||
}
|
||||
}
|
||||
this->reg.instret--;
|
||||
this->instret--;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_time(unsigned addr, reg_t &val) {
|
||||
uint64_t time_val = this->reg.icount / (100000000 / 32768 - 1); //-> ~3052;
|
||||
uint64_t time_val = this->icount / (100000000 / 32768 - 1); //-> ~3052;
|
||||
if (addr == time) {
|
||||
val = static_cast<reg_t>(time_val);
|
||||
} else if (addr == timeh) {
|
||||
@ -969,7 +971,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned len
|
||||
const mem_type::page_type &p = mem(paddr.val / mem.page_size);
|
||||
uint64_t offs = paddr.val & mem.page_addr_mask;
|
||||
std::copy(p.data() + offs, p.data() + offs + length, data);
|
||||
if (this->reg.icount > 30000) data[3] |= 0x80;
|
||||
if (this->icount > 30000) data[3] |= 0x80;
|
||||
} break;
|
||||
default: {
|
||||
for(auto offs=0U; offs<length; ++offs) {
|
||||
@ -1029,7 +1031,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned le
|
||||
LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
|
||||
<< "), stopping simulation";
|
||||
}
|
||||
this->reg.trap_state=std::numeric_limits<uint32_t>::max();
|
||||
this->trap_state=std::numeric_limits<uint32_t>::max();
|
||||
this->interrupt_sim=hostvar;
|
||||
break;
|
||||
//throw(iss::simulation_stopped(hostvar));
|
||||
@ -1117,7 +1119,7 @@ template <typename BASE, features_e FEAT> void riscv_hart_m_p<BASE, FEAT>::check
|
||||
enabled_interrupts >>= 1;
|
||||
res++;
|
||||
}
|
||||
this->reg.pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
|
||||
this->pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
|
||||
}
|
||||
}
|
||||
|
||||
@ -1127,6 +1129,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::e
|
||||
auto trap_id = bit_sub<0, 16>(flags);
|
||||
auto cause = bit_sub<16, 15>(flags);
|
||||
// calculate effective privilege level
|
||||
unsigned new_priv = PRIV_M;
|
||||
if (trap_id == 0) { // exception
|
||||
if (cause == 11) cause = 0x8 + PRIV_M; // adjust environment call cause
|
||||
// store ret addr in xepc register
|
||||
@ -1146,10 +1149,13 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::e
|
||||
csr[mtval] = (instr & 0x3)==3?instr:instr&0xffff;
|
||||
break;
|
||||
case 3:
|
||||
//TODO: implement debug mode behavior
|
||||
// csr[dpc] = addr;
|
||||
// csr[dcsr] = (csr[dcsr] & ~0x1c3) | (1<<6) | PRIV_M; //FIXME: cause should not be 4 (stepi)
|
||||
csr[mtval] = addr;
|
||||
if((FEAT & FEAT_DEBUG) && (csr[dcsr] & 0x8000)) {
|
||||
this->reg.DPC = addr;
|
||||
csr[dcsr] = (csr[dcsr] & ~0x1c3) | (1<<6) | PRIV_M; //FIXME: cause should not be 4 (stepi)
|
||||
new_priv = this->reg.PRIV | PRIV_D;
|
||||
} else {
|
||||
csr[mtval] = addr;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
@ -1161,7 +1167,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::e
|
||||
fault_data = 0;
|
||||
} else {
|
||||
csr[mepc] = this->reg.NEXT_PC & get_pc_mask(); // store next address if interrupt
|
||||
this->reg.pending_trap = 0;
|
||||
this->pending_trap = 0;
|
||||
}
|
||||
csr[mcause] = (trap_id << (traits<BASE>::XLEN-1)) + cause;
|
||||
// update mstatus
|
||||
@ -1182,8 +1188,8 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::e
|
||||
this->reg.NEXT_PC = ivec & ~0x3UL;
|
||||
if ((ivec & 0x1) == 1 && trap_id != 0) this->reg.NEXT_PC += 4 * cause;
|
||||
// reset trap state
|
||||
this->reg.PRIV = PRIV_M;
|
||||
this->reg.trap_state = 0;
|
||||
this->reg.PRIV = new_priv;
|
||||
this->trap_state = 0;
|
||||
std::array<char, 32> buffer;
|
||||
#if defined(_MSC_VER)
|
||||
sprintf(buffer.data(), "0x%016llx", addr);
|
||||
|
@ -307,7 +307,7 @@ public:
|
||||
|
||||
void disass_output(uint64_t pc, const std::string instr) override {
|
||||
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]",
|
||||
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.ccount + cycle_offset);
|
||||
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->icount + cycle_offset);
|
||||
};
|
||||
|
||||
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
|
||||
@ -340,9 +340,13 @@ protected:
|
||||
|
||||
virtual uint64_t get_next_pc() { return arch.get_next_pc(); };
|
||||
|
||||
uint64_t get_instr_count() { return arch.reg.icount; }
|
||||
uint64_t get_instr_word() override { return arch.instruction; }
|
||||
|
||||
uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
|
||||
uint64_t get_instr_count() { return arch.icount; }
|
||||
|
||||
uint64_t get_pendig_traps() override { return arch.trap_state; }
|
||||
|
||||
uint64_t get_total_cycles() override { return arch.icount + arch.cycle_offset; }
|
||||
|
||||
virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; };
|
||||
|
||||
@ -607,13 +611,19 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
|
||||
try {
|
||||
switch (space) {
|
||||
case traits<BASE>::MEM: {
|
||||
if (unlikely((access == iss::access_type::FETCH || access == iss::access_type::DEBUG_FETCH) && (addr & 0x1) == 1)) {
|
||||
auto alignment = is_fetch(access)? (traits<BASE>::MISA_VAL&0x100? 2 : 4) : length;
|
||||
if (unlikely(is_fetch(access) && (addr&(alignment-1)))) {
|
||||
fault_data = addr;
|
||||
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
|
||||
this->reg.trap_state = (1 << 31); // issue trap 0
|
||||
this->trap_state = (1 << 31); // issue trap 0
|
||||
return iss::Err;
|
||||
}
|
||||
try {
|
||||
if(!is_debug(access) && (addr&(alignment-1))){
|
||||
this->trap_state = 1<<31 | 4<<16;
|
||||
fault_data=addr;
|
||||
return iss::Err;
|
||||
}
|
||||
if (unlikely((addr & ~PGMASK) != ((addr + length - 1) & ~PGMASK))) { // we may cross a page boundary
|
||||
vm_info vm = hart_state_type::decode_vm_info(this->reg.PRIV, state.satp);
|
||||
if (vm.levels != 0) { // VM is active
|
||||
@ -629,12 +639,12 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
|
||||
read_mem( BASE::v2p(phys_addr_t{access, space, addr}), length, data):
|
||||
read_mem( BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
|
||||
if (unlikely(res != iss::Ok)){
|
||||
this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
|
||||
this->trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
|
||||
fault_data=addr;
|
||||
}
|
||||
return res;
|
||||
} catch (trap_access &ta) {
|
||||
this->reg.trap_state = (1 << 31) | ta.id;
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
fault_data=ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -650,7 +660,7 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
|
||||
case 3: { // SFENCE:VMA upper
|
||||
auto tvm = state.mstatus.TVM;
|
||||
if (this->reg.PRIV == PRIV_S & tvm != 0) {
|
||||
this->reg.trap_state = (1 << 31) | (2 << 16);
|
||||
this->trap_state = (1 << 31) | (2 << 16);
|
||||
this->fault_data = this->reg.PC;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -671,7 +681,7 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
|
||||
}
|
||||
return iss::Ok;
|
||||
} catch (trap_access &ta) {
|
||||
this->reg.trap_state = (1 << 31) | ta.id;
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
fault_data=ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -709,7 +719,7 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
|
||||
if (unlikely((access && iss::access_type::FETCH) && (addr & 0x1) == 1)) {
|
||||
fault_data = addr;
|
||||
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
|
||||
this->reg.trap_state = (1 << 31); // issue trap 0
|
||||
this->trap_state = (1 << 31); // issue trap 0
|
||||
return iss::Err;
|
||||
}
|
||||
try {
|
||||
@ -728,12 +738,12 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
|
||||
write_mem(phys_addr_t{access, space, addr}, length, data):
|
||||
write_mem(BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
|
||||
if (unlikely(res != iss::Ok)) {
|
||||
this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
||||
this->trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
||||
fault_data=addr;
|
||||
}
|
||||
return res;
|
||||
} catch (trap_access &ta) {
|
||||
this->reg.trap_state = (1 << 31) | ta.id;
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
fault_data=ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -782,7 +792,7 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
|
||||
ptw.clear();
|
||||
auto tvm = state.mstatus.TVM;
|
||||
if (this->reg.PRIV == PRIV_S & tvm != 0) {
|
||||
this->reg.trap_state = (1 << 31) | (2 << 16);
|
||||
this->trap_state = (1 << 31) | (2 << 16);
|
||||
this->fault_data = this->reg.PC;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -798,7 +808,7 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
|
||||
}
|
||||
return iss::Ok;
|
||||
} catch (trap_access &ta) {
|
||||
this->reg.trap_state = (1 << 31) | ta.id;
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
fault_data=ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -844,7 +854,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_reg(unsigned
|
||||
}
|
||||
|
||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_cycle(unsigned addr, reg_t &val) {
|
||||
auto cycle_val = this->reg.icount + cycle_offset;
|
||||
auto cycle_val = this->icount + cycle_offset;
|
||||
if (addr == mcycle) {
|
||||
val = static_cast<reg_t>(cycle_val);
|
||||
} else if (addr == mcycleh) {
|
||||
@ -866,7 +876,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_cycle(unsigned
|
||||
mcycle_csr = (static_cast<uint64_t>(val)<<32) + (mcycle_csr & 0xffffffff);
|
||||
}
|
||||
}
|
||||
cycle_offset = mcycle_csr-this->reg.icount; // TODO: relying on wrap-around
|
||||
cycle_offset = mcycle_csr-this->icount; // TODO: relying on wrap-around
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
@ -897,7 +907,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_instret(unsigne
|
||||
}
|
||||
|
||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_time(unsigned addr, reg_t &val) {
|
||||
uint64_t time_val = this->reg.icount / (100000000 / 32768 - 1); //-> ~3052;
|
||||
uint64_t time_val = this->icount / (100000000 / 32768 - 1); //-> ~3052;
|
||||
if (addr == time) {
|
||||
val = static_cast<reg_t>(time_val);
|
||||
} else if (addr == timeh) {
|
||||
@ -966,7 +976,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_epc(unsigned
|
||||
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_satp(unsigned addr, reg_t &val) {
|
||||
reg_t tvm = state.mstatus.TVM;
|
||||
if (this->reg.PRIV == PRIV_S & tvm != 0) {
|
||||
this->reg.trap_state = (1 << 31) | (2 << 16);
|
||||
this->trap_state = (1 << 31) | (2 << 16);
|
||||
this->fault_data = this->reg.PC;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -977,7 +987,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_satp(unsigned
|
||||
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_satp(unsigned addr, reg_t val) {
|
||||
reg_t tvm = state.mstatus.TVM;
|
||||
if (this->reg.PRIV == PRIV_S & tvm != 0) {
|
||||
this->reg.trap_state = (1 << 31) | (2 << 16);
|
||||
this->trap_state = (1 << 31) | (2 << 16);
|
||||
this->fault_data = this->reg.PC;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -1033,7 +1043,7 @@ iss::status riscv_hart_msu_vp<BASE>::read_mem(phys_addr_t paddr, unsigned length
|
||||
const mem_type::page_type &p = mem(paddr.val / mem.page_size);
|
||||
uint64_t offs = paddr.val & mem.page_addr_mask;
|
||||
std::copy(p.data() + offs, p.data() + offs + length, data);
|
||||
if (this->reg.icount > 30000) data[3] |= 0x80;
|
||||
if (this->icount > 30000) data[3] |= 0x80;
|
||||
} break;
|
||||
default: {
|
||||
for(auto offs=0U; offs<length; ++offs) {
|
||||
@ -1093,7 +1103,7 @@ iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_addr_t paddr, unsigned lengt
|
||||
LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
|
||||
<< "), stopping simulation";
|
||||
}
|
||||
this->reg.trap_state=std::numeric_limits<uint32_t>::max();
|
||||
this->trap_state=std::numeric_limits<uint32_t>::max();
|
||||
this->interrupt_sim=hostvar;
|
||||
break;
|
||||
//throw(iss::simulation_stopped(hostvar));
|
||||
@ -1162,7 +1172,7 @@ template <typename BASE> void riscv_hart_msu_vp<BASE>::check_interrupt() {
|
||||
if (enabled_interrupts != 0) {
|
||||
int res = 0;
|
||||
while ((enabled_interrupts & 1) == 0) enabled_interrupts >>= 1, res++;
|
||||
this->reg.pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
|
||||
this->pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
|
||||
}
|
||||
}
|
||||
|
||||
@ -1306,7 +1316,7 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f
|
||||
if (cur_priv != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0)
|
||||
new_priv = (csr[sideleg] >> cause) & 0x1 ? PRIV_U : PRIV_S;
|
||||
csr[uepc | (new_priv << 8)] = this->reg.NEXT_PC; // store next address if interrupt
|
||||
this->reg.pending_trap = 0;
|
||||
this->pending_trap = 0;
|
||||
}
|
||||
size_t adr = ucause | (new_priv << 8);
|
||||
csr[adr] = (trap_id << 31) + cause;
|
||||
@ -1351,7 +1361,7 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f
|
||||
<< lvl[cur_priv] << " to " << lvl[new_priv];
|
||||
// reset trap state
|
||||
this->reg.PRIV = new_priv;
|
||||
this->reg.trap_state = 0;
|
||||
this->trap_state = 0;
|
||||
update_vm_info();
|
||||
return this->reg.NEXT_PC;
|
||||
}
|
||||
@ -1363,7 +1373,7 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::leave_trap(uint64_t f
|
||||
|
||||
auto tsr = state.mstatus.TSR;
|
||||
if (cur_priv == PRIV_S && inst_priv == PRIV_S && tsr != 0) {
|
||||
this->reg.trap_state = (1 << 31) | (2 << 16);
|
||||
this->trap_state = (1 << 31) | (2 << 16);
|
||||
this->fault_data = this->reg.PC;
|
||||
return this->reg.PC;
|
||||
}
|
||||
@ -1402,7 +1412,7 @@ template <typename BASE> void riscv_hart_msu_vp<BASE>::wait_until(uint64_t flags
|
||||
auto status = state.mstatus;
|
||||
auto tw = status.TW;
|
||||
if (this->reg.PRIV == PRIV_S && tw != 0) {
|
||||
this->reg.trap_state = (1 << 31) | (2 << 16);
|
||||
this->trap_state = (1 << 31) | (2 << 16);
|
||||
this->fault_data = this->reg.PC;
|
||||
}
|
||||
}
|
||||
|
@ -218,7 +218,7 @@ public:
|
||||
|
||||
void disass_output(uint64_t pc, const std::string instr) override {
|
||||
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]",
|
||||
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.icount + cycle_offset);
|
||||
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->icount + cycle_offset);
|
||||
};
|
||||
|
||||
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
|
||||
@ -254,9 +254,13 @@ protected:
|
||||
|
||||
virtual uint64_t get_next_pc() { return arch.get_next_pc(); };
|
||||
|
||||
uint64_t get_instr_count() { return arch.reg.icount; }
|
||||
uint64_t get_instr_word() override { return arch.instruction; }
|
||||
|
||||
uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
|
||||
uint64_t get_instr_count() { return arch.icount; }
|
||||
|
||||
uint64_t get_pendig_traps() override { return arch.trap_state; }
|
||||
|
||||
uint64_t get_total_cycles() override { return arch.icount + arch.cycle_offset; }
|
||||
|
||||
virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; };
|
||||
|
||||
@ -701,23 +705,23 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
|
||||
switch (space) {
|
||||
case traits<BASE>::MEM: {
|
||||
if(FEAT & FEAT_PMP){
|
||||
if(!pmp_check(access, addr, length) && (access&access_type::DEBUG) != access_type::DEBUG) {
|
||||
if(!pmp_check(access, addr, length) && !is_debug(access)) {
|
||||
fault_data = addr;
|
||||
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
|
||||
this->reg.trap_state = (1 << 31) | ((access==access_type::FETCH?1:5) << 16); // issue trap 1
|
||||
if (is_debug(access)) throw trap_access(0, addr);
|
||||
this->trap_state = (1 << 31) | ((access==access_type::FETCH?1:5) << 16); // issue trap 1
|
||||
return iss::Err;
|
||||
}
|
||||
}
|
||||
if (unlikely((access == iss::access_type::FETCH || access == iss::access_type::DEBUG_FETCH) && (addr & 0x1) == 1)) {
|
||||
auto alignment = is_fetch(access)? (traits<BASE>::MISA_VAL&0x100? 2 : 4) : length;
|
||||
if (unlikely(is_fetch(access) && (addr&(alignment-1)))) {
|
||||
fault_data = addr;
|
||||
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
|
||||
this->reg.trap_state = (1 << 31); // issue trap 0
|
||||
if (is_debug(access)) throw trap_access(0, addr);
|
||||
this->trap_state = (1 << 31); // issue trap 0
|
||||
return iss::Err;
|
||||
}
|
||||
try {
|
||||
auto alignment = access == iss::access_type::FETCH? (traits<BASE>::MISA_VAL&0x100? 2 : 4) : length;
|
||||
if(alignment>1 && (addr&(alignment-1))){
|
||||
this->reg.trap_state = 1<<31 | 4<<16;
|
||||
if(!is_debug(access) && (addr&(alignment-1))){
|
||||
this->trap_state = 1<<31 | 4<<16;
|
||||
fault_data=addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -736,12 +740,12 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
|
||||
res = read_mem( phys_addr, length, data);
|
||||
}
|
||||
if (unlikely(res != iss::Ok)){
|
||||
this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
|
||||
this->trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
|
||||
fault_data=addr;
|
||||
}
|
||||
return res;
|
||||
} catch (trap_access &ta) {
|
||||
this->reg.trap_state = (1 << 31) | ta.id;
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
fault_data=ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -767,7 +771,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
|
||||
}
|
||||
return iss::Ok;
|
||||
} catch (trap_access &ta) {
|
||||
this->reg.trap_state = (1 << 31) | ta.id;
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
fault_data=ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -806,19 +810,19 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
|
||||
if(!pmp_check(access, addr, length) && (access&access_type::DEBUG) != access_type::DEBUG) {
|
||||
fault_data = addr;
|
||||
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
|
||||
this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 1
|
||||
this->trap_state = (1 << 31) | (7 << 16); // issue trap 1
|
||||
return iss::Err;
|
||||
}
|
||||
}
|
||||
if (unlikely((access && iss::access_type::FETCH) && (addr & 0x1) == 1)) {
|
||||
fault_data = addr;
|
||||
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
|
||||
this->reg.trap_state = (1 << 31); // issue trap 0
|
||||
this->trap_state = (1 << 31); // issue trap 0
|
||||
return iss::Err;
|
||||
}
|
||||
try {
|
||||
if(length>1 && (addr&(length-1)) && (access&access_type::DEBUG) != access_type::DEBUG){
|
||||
this->reg.trap_state = 1<<31 | 6<<16;
|
||||
this->trap_state = 1<<31 | 6<<16;
|
||||
fault_data=addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -837,12 +841,12 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
|
||||
res = write_mem( phys_addr, length, data);
|
||||
}
|
||||
if (unlikely(res != iss::Ok)) {
|
||||
this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
||||
this->trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
||||
fault_data=addr;
|
||||
}
|
||||
return res;
|
||||
} catch (trap_access &ta) {
|
||||
this->reg.trap_state = (1 << 31) | ta.id;
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
fault_data=ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -902,7 +906,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
|
||||
}
|
||||
return iss::Ok;
|
||||
} catch (trap_access &ta) {
|
||||
this->reg.trap_state = (1 << 31) | ta.id;
|
||||
this->trap_state = (1 << 31) | ta.id;
|
||||
fault_data=ta.addr;
|
||||
return iss::Err;
|
||||
}
|
||||
@ -948,7 +952,7 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_cycle(unsigned addr, reg_t &val) {
|
||||
auto cycle_val = this->reg.icount + cycle_offset;
|
||||
auto cycle_val = this->icount + cycle_offset;
|
||||
if (addr == mcycle) {
|
||||
val = static_cast<reg_t>(cycle_val);
|
||||
} else if (addr == mcycleh) {
|
||||
@ -970,16 +974,16 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
|
||||
mcycle_csr = (static_cast<uint64_t>(val)<<32) + (mcycle_csr & 0xffffffff);
|
||||
}
|
||||
}
|
||||
cycle_offset = mcycle_csr-this->reg.icount; // TODO: relying on wrap-around
|
||||
cycle_offset = mcycle_csr-this->icount; // TODO: relying on wrap-around
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_instret(unsigned addr, reg_t &val) {
|
||||
if ((addr&0xff) == (minstret&0xff)) {
|
||||
val = static_cast<reg_t>(this->reg.instret);
|
||||
val = static_cast<reg_t>(this->instret);
|
||||
} else if ((addr&0xff) == (minstreth&0xff)) {
|
||||
if (sizeof(typename traits<BASE>::reg_t) != 4) return iss::Err;
|
||||
val = static_cast<reg_t>(this->reg.instret >> 32);
|
||||
val = static_cast<reg_t>(this->instret >> 32);
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
@ -988,20 +992,20 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
|
||||
if (sizeof(typename traits<BASE>::reg_t) != 4) {
|
||||
if ((addr&0xff) == (minstreth&0xff))
|
||||
return iss::Err;
|
||||
this->reg.instret = static_cast<uint64_t>(val);
|
||||
this->instret = static_cast<uint64_t>(val);
|
||||
} else {
|
||||
if ((addr&0xff) == (minstret&0xff)) {
|
||||
this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val;
|
||||
this->instret = (this->instret & 0xffffffff00000000) + val;
|
||||
} else {
|
||||
this->reg.instret = (static_cast<uint64_t>(val)<<32) + (this->reg.instret & 0xffffffff);
|
||||
this->instret = (static_cast<uint64_t>(val)<<32) + (this->instret & 0xffffffff);
|
||||
}
|
||||
}
|
||||
this->reg.instret--;
|
||||
this->instret--;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_time(unsigned addr, reg_t &val) {
|
||||
uint64_t time_val = this->reg.icount / (100000000 / 32768 - 1); //-> ~3052;
|
||||
uint64_t time_val = this->icount / (100000000 / 32768 - 1); //-> ~3052;
|
||||
if (addr == time) {
|
||||
val = static_cast<reg_t>(time_val);
|
||||
} else if (addr == timeh) {
|
||||
@ -1137,7 +1141,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned le
|
||||
const mem_type::page_type &p = mem(paddr.val / mem.page_size);
|
||||
uint64_t offs = paddr.val & mem.page_addr_mask;
|
||||
std::copy(p.data() + offs, p.data() + offs + length, data);
|
||||
if (this->reg.icount > 30000) data[3] |= 0x80;
|
||||
if (this->icount > 30000) data[3] |= 0x80;
|
||||
} break;
|
||||
default: {
|
||||
for(auto offs=0U; offs<length; ++offs) {
|
||||
@ -1196,7 +1200,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned l
|
||||
LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
|
||||
<< "), stopping simulation";
|
||||
}
|
||||
this->reg.trap_state=std::numeric_limits<uint32_t>::max();
|
||||
this->trap_state=std::numeric_limits<uint32_t>::max();
|
||||
this->interrupt_sim=hostvar;
|
||||
break;
|
||||
//throw(iss::simulation_stopped(hostvar));
|
||||
@ -1284,19 +1288,19 @@ template <typename BASE, features_e FEAT> void riscv_hart_mu_p<BASE, FEAT>::chec
|
||||
enabled_interrupts >>= 1;
|
||||
res++;
|
||||
}
|
||||
this->reg.pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
|
||||
this->pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
|
||||
}
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) {
|
||||
// flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0]
|
||||
// calculate and write mcause val
|
||||
if(flags==std::numeric_limits<uint64_t>::max()) flags=this->reg.trap_state;
|
||||
if(flags==std::numeric_limits<uint64_t>::max()) flags=this->trap_state;
|
||||
auto trap_id = bit_sub<0, 16>(flags);
|
||||
auto cause = bit_sub<16, 15>(flags);
|
||||
if (trap_id == 0 && cause == 11) cause = 0x8 + this->reg.PRIV; // adjust environment call cause
|
||||
// calculate effective privilege level
|
||||
auto new_priv = PRIV_M;
|
||||
unsigned new_priv = PRIV_M;
|
||||
if (trap_id == 0) { // exception
|
||||
if (this->reg.PRIV != PRIV_M && ((csr[medeleg] >> cause) & 0x1) != 0)
|
||||
new_priv = PRIV_U;
|
||||
@ -1317,10 +1321,13 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
|
||||
csr[utval | (new_priv << 8)] = (instr & 0x3)==3?instr:instr&0xffff;
|
||||
break;
|
||||
case 3:
|
||||
//TODO: implement debug mode behavior
|
||||
// csr[dpc] = addr;
|
||||
// csr[dcsr] = (csr[dcsr] & ~0x1c3) | (1<<6) | PRIV_M; //FIXME: cause should not be 4 (stepi)
|
||||
csr[utval | (new_priv << 8)] = addr;
|
||||
if((FEAT & FEAT_DEBUG) && (csr[dcsr] & 0x8000)) {
|
||||
this->reg.DPC = addr;
|
||||
csr[dcsr] = (csr[dcsr] & ~0x1c3) | (1<<6) | PRIV_M; //FIXME: cause should not be 4 (stepi)
|
||||
new_priv = this->reg.PRIV | PRIV_D;
|
||||
} else {
|
||||
csr[utval | (new_priv << 8)] = addr;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
@ -1335,7 +1342,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
|
||||
if (this->reg.PRIV != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0)
|
||||
new_priv = PRIV_U;
|
||||
csr[uepc | (new_priv << 8)] = this->reg.NEXT_PC; // store next address if interrupt
|
||||
this->reg.pending_trap = 0;
|
||||
this->pending_trap = 0;
|
||||
}
|
||||
size_t adr = ucause | (new_priv << 8);
|
||||
csr[adr] = (trap_id << (traits<BASE>::XLEN-1)) + cause;
|
||||
@ -1375,7 +1382,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
|
||||
<< lvl[this->reg.PRIV] << " to " << lvl[new_priv];
|
||||
// reset trap state
|
||||
this->reg.PRIV = new_priv;
|
||||
this->reg.trap_state = 0;
|
||||
this->trap_state = 0;
|
||||
return this->reg.NEXT_PC;
|
||||
}
|
||||
|
||||
@ -1384,7 +1391,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
|
||||
auto inst_priv = (flags & 0x3)? 3:0;
|
||||
if(inst_priv>cur_priv){
|
||||
auto trap_val = 0x80ULL << 24 | (2 << 16); // illegal instruction
|
||||
this->reg.trap_state = trap_val;
|
||||
this->trap_state = trap_val;
|
||||
this->reg.NEXT_PC = std::numeric_limits<uint32_t>::max();
|
||||
} else {
|
||||
auto status = state.mstatus;
|
||||
|
@ -58,12 +58,7 @@ template <> struct traits<tgc_c> {
|
||||
constexpr static unsigned FP_REGS_SIZE = 0;
|
||||
|
||||
enum reg_e {
|
||||
X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, X30, X31, PC, NEXT_PC, PRIV, DPC, NUM_REGS,
|
||||
TRAP_STATE=NUM_REGS,
|
||||
PENDING_TRAP,
|
||||
ICOUNT,
|
||||
CYCLE,
|
||||
INSTRET
|
||||
X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, X30, X31, PC, NEXT_PC, PRIV, DPC, NUM_REGS
|
||||
};
|
||||
|
||||
using reg_t = uint32_t;
|
||||
@ -76,11 +71,11 @@ template <> struct traits<tgc_c> {
|
||||
|
||||
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
|
||||
|
||||
static constexpr std::array<const uint32_t, 41> reg_bit_widths{
|
||||
{32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,8,32,32,32,64,64,64}};
|
||||
static constexpr std::array<const uint32_t, 36> reg_bit_widths{
|
||||
{32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,8,32}};
|
||||
|
||||
static constexpr std::array<const uint32_t, 41> 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}};
|
||||
static constexpr std::array<const uint32_t, 36> 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}};
|
||||
|
||||
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
|
||||
|
||||
@ -197,7 +192,7 @@ struct tgc_c: public arch_if {
|
||||
|
||||
uint8_t* get_regs_base_ptr() override;
|
||||
|
||||
inline uint64_t get_icount() { return reg.icount; }
|
||||
inline uint64_t get_icount() { return icount; }
|
||||
|
||||
inline bool should_stop() { return interrupt_sim; }
|
||||
|
||||
@ -215,7 +210,7 @@ struct tgc_c: public arch_if {
|
||||
|
||||
virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
|
||||
|
||||
inline uint32_t get_last_branch() { return reg.last_branch; }
|
||||
inline uint32_t get_last_branch() { return last_branch; }
|
||||
|
||||
|
||||
#pragma pack(push, 1)
|
||||
@ -256,12 +251,14 @@ struct tgc_c: public arch_if {
|
||||
uint32_t NEXT_PC = 0;
|
||||
uint8_t PRIV = 0;
|
||||
uint32_t DPC = 0;
|
||||
uint32_t trap_state = 0, pending_trap = 0;
|
||||
uint64_t icount = 0;
|
||||
uint64_t instret = 0;
|
||||
uint32_t last_branch;
|
||||
} reg;
|
||||
#pragma pack(pop)
|
||||
uint32_t trap_state = 0, pending_trap = 0;
|
||||
uint64_t icount = 0;
|
||||
uint64_t cycle = 0;
|
||||
uint64_t instret = 0;
|
||||
uint32_t instruction = 0;
|
||||
uint32_t last_branch = 0;
|
||||
std::array<address_type, 4> addr_mode;
|
||||
|
||||
uint64_t interrupt_sim=0;
|
||||
|
@ -81,7 +81,7 @@ public:
|
||||
void callback(instr_info_t instr_info, exec_info const&) override;
|
||||
|
||||
private:
|
||||
iss::instrumentation_if *arch_instr;
|
||||
iss::instrumentation_if *instr_if;
|
||||
std::vector<instr_desc> delays;
|
||||
struct pair_hash {
|
||||
size_t operator()(const std::pair<uint64_t, uint64_t> &p) const {
|
||||
|
@ -44,7 +44,7 @@
|
||||
|
||||
namespace iss {
|
||||
namespace plugin {
|
||||
|
||||
class lz4compress_steambuf;
|
||||
class cov : public iss::vm_plugin {
|
||||
struct instr_delay {
|
||||
std::string instr_name;
|
||||
@ -88,10 +88,13 @@ public:
|
||||
private:
|
||||
iss::instrumentation_if *instr_if {nullptr};
|
||||
std::ofstream output;
|
||||
#ifdef WITH_LZ4
|
||||
std::unique_ptr<lz4compress_steambuf> strbuf;
|
||||
std::ostream ostr;
|
||||
#endif
|
||||
std::string filename;
|
||||
std::vector<instr_desc> delays;
|
||||
bool jumped, first;
|
||||
|
||||
bool jumped{false}, first{true};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -41,12 +41,10 @@ using namespace iss::arch;
|
||||
|
||||
constexpr std::array<const char*, 36> iss::arch::traits<iss::arch::tgc_c>::reg_names;
|
||||
constexpr std::array<const char*, 36> iss::arch::traits<iss::arch::tgc_c>::reg_aliases;
|
||||
constexpr std::array<const uint32_t, 41> iss::arch::traits<iss::arch::tgc_c>::reg_bit_widths;
|
||||
constexpr std::array<const uint32_t, 41> iss::arch::traits<iss::arch::tgc_c>::reg_byte_offsets;
|
||||
constexpr std::array<const uint32_t, 36> iss::arch::traits<iss::arch::tgc_c>::reg_bit_widths;
|
||||
constexpr std::array<const uint32_t, 36> iss::arch::traits<iss::arch::tgc_c>::reg_byte_offsets;
|
||||
|
||||
tgc_c::tgc_c() {
|
||||
reg.icount = 0;
|
||||
}
|
||||
tgc_c::tgc_c() = default;
|
||||
|
||||
tgc_c::~tgc_c() = default;
|
||||
|
||||
@ -57,8 +55,8 @@ void tgc_c::reset(uint64_t address) {
|
||||
reg.PC=address;
|
||||
reg.NEXT_PC=reg.PC;
|
||||
reg.PRIV=0x3;
|
||||
reg.trap_state=0;
|
||||
reg.icount=0;
|
||||
trap_state=0;
|
||||
icount=0;
|
||||
}
|
||||
|
||||
uint8_t *tgc_c::get_regs_base_ptr() {
|
||||
|
@ -60,13 +60,13 @@ int main(int argc, char *argv[]) {
|
||||
desc.add_options()
|
||||
("help,h", "Print help message")
|
||||
("verbose,v", po::value<int>()->implicit_value(0), "Sets logging verbosity")
|
||||
("logfile,f", po::value<std::string>(), "Sets default log file.")
|
||||
("logfile,l", po::value<std::string>(), "Sets default log file.")
|
||||
("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly")
|
||||
("gdb-port,g", po::value<unsigned>()->default_value(0), "enable gdb server and specify port to use")
|
||||
("instructions,i", po::value<uint64_t>()->default_value(std::numeric_limits<uint64_t>::max()), "max. number of instructions to simulate")
|
||||
("reset,r", po::value<std::string>(), "reset address")
|
||||
("dump-ir", "dump the intermediate representation")
|
||||
("elf", 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")
|
||||
("plugin,p", po::value<std::vector<std::string>>(), "plugin to activate")
|
||||
("backend", po::value<std::string>()->default_value("interp"), "the memory input file")
|
||||
|
@ -48,7 +48,7 @@ using namespace rapidjson;
|
||||
using namespace std;
|
||||
|
||||
iss::plugin::cycle_estimate::cycle_estimate(string const& config_file_name)
|
||||
: arch_instr(nullptr)
|
||||
: instr_if(nullptr)
|
||||
, config_file_name(config_file_name)
|
||||
{
|
||||
}
|
||||
@ -57,9 +57,9 @@ iss::plugin::cycle_estimate::~cycle_estimate() {
|
||||
}
|
||||
|
||||
bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if& vm) {
|
||||
arch_instr = vm.get_arch()->get_instrumentation_if();
|
||||
if(!arch_instr) return false;
|
||||
const string core_name = arch_instr->core_type_name();
|
||||
instr_if = vm.get_arch()->get_instrumentation_if();
|
||||
if(!instr_if) return false;
|
||||
const string core_name = instr_if->core_type_name();
|
||||
if (config_file_name.length() > 0) {
|
||||
ifstream is(config_file_name);
|
||||
if (is.is_open()) {
|
||||
@ -108,11 +108,11 @@ bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if&
|
||||
}
|
||||
|
||||
void iss::plugin::cycle_estimate::callback(instr_info_t instr_info, exec_info const& exc_info) {
|
||||
assert(arch_instr && "No instrumentation interface available but callback executed");
|
||||
assert(instr_if && "No instrumentation interface available but callback executed");
|
||||
auto entry = delays[instr_info.instr_id];
|
||||
bool taken = exc_info.branch_taken;
|
||||
if (exc_info.branch_taken && (entry.taken > 1))
|
||||
arch_instr->set_curr_instr_cycles(entry.taken);
|
||||
instr_if->set_curr_instr_cycles(entry.taken);
|
||||
else if (entry.not_taken > 1)
|
||||
arch_instr->set_curr_instr_cycles(entry.not_taken);
|
||||
instr_if->set_curr_instr_cycles(entry.not_taken);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <iss/arch_if.h>
|
||||
#include <iss/plugin/pctrace.h>
|
||||
#include <util/logging.h>
|
||||
#include <util/ities.h>
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/istreamwrapper.h>
|
||||
#include "rapidjson/writer.h"
|
||||
@ -8,27 +9,99 @@
|
||||
#include <rapidjson/ostreamwrapper.h>
|
||||
#include <rapidjson/error/en.h>
|
||||
#include <fstream>
|
||||
|
||||
#include <iostream>
|
||||
#ifdef WITH_LZ4
|
||||
#include <lz4frame.h>
|
||||
#endif
|
||||
|
||||
namespace iss {
|
||||
namespace plugin {
|
||||
|
||||
using namespace rapidjson;
|
||||
using namespace std;
|
||||
|
||||
iss::plugin::cov::cov(std::string const &filename)
|
||||
: instr_if(nullptr)
|
||||
, filename(filename)
|
||||
{
|
||||
output.open("output.trc");
|
||||
jumped = false;
|
||||
first = true;
|
||||
}
|
||||
#ifdef WITH_LZ4
|
||||
class lz4compress_steambuf: public std::streambuf {
|
||||
public:
|
||||
lz4compress_steambuf(const lz4compress_steambuf&) = delete;
|
||||
lz4compress_steambuf& operator=(const lz4compress_steambuf&) = delete;
|
||||
lz4compress_steambuf(std::ostream &sink, size_t buf_size)
|
||||
: sink(sink)
|
||||
, src_buf(buf_size)
|
||||
, dest_buf(LZ4F_compressBound(buf_size, nullptr))
|
||||
{
|
||||
auto errCode = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION);
|
||||
if (LZ4F_isError(errCode) != 0)
|
||||
throw std::runtime_error(std::string("Failed to create LZ4 context: ") + LZ4F_getErrorName(errCode));
|
||||
size_t ret = LZ4F_compressBegin(ctx, &dest_buf.front(), dest_buf.capacity(), nullptr);
|
||||
if (LZ4F_isError(ret) != 0)
|
||||
throw std::runtime_error(std::string("Failed to start LZ4 compression: ") + LZ4F_getErrorName(ret));
|
||||
setp(src_buf.data(), src_buf.data() + src_buf.size() - 1);
|
||||
sink.write(dest_buf.data(), ret);
|
||||
}
|
||||
|
||||
iss::plugin::cov::~cov() {
|
||||
output.close();
|
||||
}
|
||||
~lz4compress_steambuf() {
|
||||
close();
|
||||
}
|
||||
|
||||
bool iss::plugin::cov::registration(const char *const version, vm_if& vm) {
|
||||
void close() {
|
||||
if (closed)
|
||||
return;
|
||||
sync();
|
||||
auto ret = LZ4F_compressEnd(ctx, dest_buf.data(), dest_buf.capacity(), nullptr);
|
||||
if (LZ4F_isError(ret) != 0)
|
||||
throw std::runtime_error(std::string("Failed to finish LZ4 compression: ") + LZ4F_getErrorName(ret));
|
||||
sink.write(dest_buf.data(), ret);
|
||||
LZ4F_freeCompressionContext(ctx);
|
||||
closed = true;
|
||||
}
|
||||
|
||||
private:
|
||||
int_type overflow(int_type ch) override {
|
||||
compress_and_write();
|
||||
*pptr() = static_cast<char_type>(ch);
|
||||
pbump(1);
|
||||
return ch;
|
||||
}
|
||||
|
||||
int_type sync() override {
|
||||
compress_and_write();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void compress_and_write() {
|
||||
if (closed)
|
||||
throw std::runtime_error("Cannot write to closed stream");
|
||||
if(auto orig_size = pptr() - pbase()){
|
||||
auto ret = LZ4F_compressUpdate(ctx, dest_buf.data(), dest_buf.capacity(), pbase(), orig_size, nullptr);
|
||||
if (LZ4F_isError(ret) != 0)
|
||||
throw std::runtime_error(std::string("LZ4 compression failed: ") + LZ4F_getErrorName(ret));
|
||||
if(ret) sink.write(dest_buf.data(), ret);
|
||||
pbump(-orig_size);
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream &sink;
|
||||
std::vector<char> src_buf;
|
||||
std::vector<char> dest_buf;
|
||||
LZ4F_compressionContext_t ctx{ nullptr };
|
||||
bool closed{ false };
|
||||
};
|
||||
#endif
|
||||
|
||||
cov::cov(std::string const &filename)
|
||||
: instr_if(nullptr)
|
||||
, filename(filename)
|
||||
, output("output.trc")
|
||||
#ifdef WITH_LZ4
|
||||
, strbuf(new lz4compress_steambuf(output, 4096))
|
||||
, ostr(strbuf.get())
|
||||
#endif
|
||||
{ }
|
||||
|
||||
cov::~cov() { }
|
||||
|
||||
bool cov::registration(const char *const version, vm_if& vm) {
|
||||
instr_if = vm.get_arch()->get_instrumentation_if();
|
||||
if(!instr_if) return false;
|
||||
const string core_name = instr_if->core_type_name();
|
||||
@ -62,11 +135,11 @@ bool iss::plugin::cov::registration(const char *const version, vm_if& vm) {
|
||||
} else {
|
||||
LOG(ERR)<<"plugin cycle_estimate: could not find an entry for "<<core_name<<" in JSON file"<<endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG(ERR)<<"plugin cycle_estimate: could not parse in JSON file at "<< ok.Offset()<<": "<<GetParseError_En(ok.Code())<<endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (runtime_error &e) {
|
||||
LOG(ERR) << "Could not parse input file " << filename << ", reason: " << e.what();
|
||||
return false;
|
||||
@ -77,57 +150,31 @@ bool iss::plugin::cov::registration(const char *const version, vm_if& vm) {
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
inline string formatPC(uint64_t pc) {
|
||||
stringstream stream;
|
||||
stream << "0x" << std::hex << pc;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
void iss::plugin::cov::callback(instr_info_t iinfo, const exec_info& einfo) {
|
||||
// auto delay = 0;
|
||||
// auto entry = delays[iinfo.instr_id];
|
||||
// bool taken = einfo.branch_taken;
|
||||
// if (einfo.branch_taken)
|
||||
// delay = entry.taken;
|
||||
// else
|
||||
// delay = entry.not_taken;
|
||||
//
|
||||
// if (first){
|
||||
// output << formatPC(instr_if->get_pc()) << "," << delay;
|
||||
// first = false;
|
||||
// }
|
||||
// if(instr_if->get_next_pc()-instr_if->get_pc() != delays[iinfo.instr_id].size/8){
|
||||
// //The goal is to keep the output in start-target pairs, so after a jump the target address needs to get written
|
||||
// //to the output. If the target happens to also be a start, we keep the pairing by adding a 0-delay entry.
|
||||
// if (jumped)
|
||||
// output <<"\n" <<formatPC(instr_if->get_pc()) << "," << 0;
|
||||
// output <<"\n" << formatPC(instr_if->get_pc()) << "," << delay;
|
||||
// jumped = true;
|
||||
// }
|
||||
// else{
|
||||
// if (jumped){
|
||||
// output <<"\n" << formatPC(instr_if->get_pc()) << "," << delay;
|
||||
// jumped = false;
|
||||
// }
|
||||
// else if(delay!=1){
|
||||
// output <<"\n" << formatPC(instr_if->get_pc()) << "," << delay;
|
||||
// output <<"\n" << formatPC(instr_if->get_pc()) << "," << 0;
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
//source code for the full output
|
||||
void cov::callback(instr_info_t iinfo, const exec_info& einfo) {
|
||||
auto delay = 0;
|
||||
auto entry = delays[iinfo.instr_id];
|
||||
size_t id = iinfo.instr_id;
|
||||
auto entry = delays[id];
|
||||
auto instr = instr_if->get_instr_word();
|
||||
auto call = id==65 || id ==86 || ((id==2 || id==3) && bit_sub<7,5>(instr)!=0) ;//not taking care of tail calls (jalr with loading x6)
|
||||
bool taken = einfo.branch_taken;
|
||||
if (einfo.branch_taken)
|
||||
bool compressed = (instr&0x3)!=0x3;
|
||||
if (einfo.branch_taken) {
|
||||
delay = entry.taken;
|
||||
else
|
||||
delay = entry.not_taken;
|
||||
output<<std::hex <<"0x" << instr_if->get_pc() <<"," << delay << "\n";
|
||||
if(entry.taken > 1)
|
||||
instr_if->set_curr_instr_cycles(entry.taken);
|
||||
} else {
|
||||
delay = entry.not_taken;
|
||||
if (entry.not_taken > 1)
|
||||
instr_if->set_curr_instr_cycles(entry.not_taken);
|
||||
}
|
||||
#ifndef WITH_LZ4
|
||||
output<<std::hex <<"0x" << instr_if->get_pc() <<"," << delay <<"," << call<<","<<(compressed?2:4) <<"\n";
|
||||
#else
|
||||
auto rdbuf=ostr.rdbuf();
|
||||
ostr<<std::hex <<"0x" << instr_if->get_pc() <<"," << delay <<"," << call<<","<<(compressed?2:4) <<"\n";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ public:
|
||||
heart_state_t &get_state() { return this->state; }
|
||||
|
||||
void notify_phase(iss::arch_if::exec_phase p) override {
|
||||
if (p == iss::arch_if::ISTART) owner->sync(this->reg.icount);
|
||||
if (p == iss::arch_if::ISTART) owner->sync(this->icount);
|
||||
}
|
||||
|
||||
sync_type needed_sync() const override { return PRE_SYNC; }
|
||||
@ -115,7 +115,7 @@ public:
|
||||
std::stringstream s;
|
||||
s << "[p:" << lvl[this->reg.PRIV] << ";s:0x" << std::hex << std::setfill('0')
|
||||
<< std::setw(sizeof(reg_t) * 2) << (reg_t)this->state.mstatus << std::dec << ";c:"
|
||||
<< this->reg.icount + this->cycle_offset << "]";
|
||||
<< this->icount + this->cycle_offset << "]";
|
||||
SCCDEBUG(owner->name())<<"disass: "
|
||||
<< "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t" << std::setw(40)
|
||||
<< std::setfill(' ') << std::left << instr << s.str();
|
||||
@ -175,9 +175,9 @@ public:
|
||||
|
||||
void wait_until(uint64_t flags) override {
|
||||
SCCDEBUG(owner->name()) << "Sleeping until interrupt";
|
||||
do {
|
||||
while(this->pending_trap == 0 && (this->csr[arch::mip] & this->csr[arch::mie]) == 0) {
|
||||
sc_core::wait(wfi_evt);
|
||||
} while (this->reg.pending_trap == 0);
|
||||
}
|
||||
PLAT::wait_until(flags);
|
||||
}
|
||||
|
||||
@ -204,7 +204,7 @@ public:
|
||||
this->csr[arch::mip] &= ~mask;
|
||||
this->check_interrupt();
|
||||
if(value)
|
||||
SCCTRACE(owner->name()) << "Triggering interrupt " << id << " Pending trap: " << this->reg.pending_trap;
|
||||
SCCTRACE(owner->name()) << "Triggering interrupt " << id << " Pending trap: " << this->pending_trap;
|
||||
}
|
||||
|
||||
private:
|
||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user