Compare commits
19 Commits
07d5af1dde
...
feature/re
Author | SHA1 | Date | |
---|---|---|---|
58311b37db | |||
ad8dc09bee | |||
2bba5645c3 | |||
bf0a5a80de | |||
b37ef973de | |||
4c363f4073 | |||
b8fa5fbbda | |||
ac86f14a54 | |||
68b5697c8f | |||
09b0f0d0c8 | |||
98b418ff43 | |||
059bd0d371 | |||
ef2a4df925 | |||
7578906310 | |||
afe8905ac9 | |||
ecc6091d1e | |||
3563ba80d0 | |||
09955be90f | |||
dd4c19a15c |
1
.gitignore
vendored
1
.gitignore
vendored
@ -32,3 +32,4 @@ language.settings.xml
|
|||||||
/dump.json
|
/dump.json
|
||||||
/src-gen/
|
/src-gen/
|
||||||
/*.yaml
|
/*.yaml
|
||||||
|
/*.json
|
||||||
|
@ -7,6 +7,7 @@ project(dbt-rise-tgc VERSION 1.0.0)
|
|||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
find_package(elfio)
|
find_package(elfio)
|
||||||
|
find_package(Boost COMPONENTS coroutine)
|
||||||
|
|
||||||
if(WITH_LLVM)
|
if(WITH_LLVM)
|
||||||
if(DEFINED ENV{LLVM_HOME})
|
if(DEFINED ENV{LLVM_HOME})
|
||||||
@ -34,10 +35,14 @@ FILE(GLOB TGC_VM_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/vm/interp/vm_*.cpp)
|
|||||||
set(LIB_SOURCES
|
set(LIB_SOURCES
|
||||||
src/vm/fp_functions.cpp
|
src/vm/fp_functions.cpp
|
||||||
src/plugin/instruction_count.cpp
|
src/plugin/instruction_count.cpp
|
||||||
src/plugin/cycle_estimate.cpp
|
src/plugin/pctrace.cpp
|
||||||
|
|
||||||
${TGC_SOURCES}
|
${TGC_SOURCES}
|
||||||
${TGC_VM_SOURCES}
|
${TGC_VM_SOURCES}
|
||||||
)
|
)
|
||||||
|
if(TARGET RapidJSON)
|
||||||
|
list(APPEND LIB_SOURCES src/plugin/cycle_estimate.cpp)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(WITH_LLVM)
|
if(WITH_LLVM)
|
||||||
FILE(GLOB TGC_LLVM_SOURCES
|
FILE(GLOB TGC_LLVM_SOURCES
|
||||||
@ -66,7 +71,7 @@ elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
|||||||
target_compile_options(${PROJECT_NAME} PRIVATE /wd4293)
|
target_compile_options(${PROJECT_NAME} PRIVATE /wd4293)
|
||||||
endif()
|
endif()
|
||||||
target_include_directories(${PROJECT_NAME} PUBLIC incl)
|
target_include_directories(${PROJECT_NAME} PUBLIC incl)
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC softfloat scc-util jsoncpp)
|
target_link_libraries(${PROJECT_NAME} PUBLIC softfloat scc-util jsoncpp Boost::coroutine)
|
||||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC -Wl,--whole-archive dbt-core -Wl,--no-whole-archive)
|
target_link_libraries(${PROJECT_NAME} PUBLIC -Wl,--whole-archive dbt-core -Wl,--no-whole-archive)
|
||||||
else()
|
else()
|
||||||
@ -79,6 +84,10 @@ elseif(TARGET elfio::elfio)
|
|||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "No elfio library found, maybe a find_package() call is missing")
|
message(FATAL_ERROR "No elfio library found, maybe a find_package() call is missing")
|
||||||
endif()
|
endif()
|
||||||
|
if(TARGET RapidJSON)
|
||||||
|
target_link_libraries(${PROJECT_NAME} PUBLIC RapidJSON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||||
VERSION ${PROJECT_VERSION}
|
VERSION ${PROJECT_VERSION}
|
||||||
|
Submodule gen_input/CoreDSL-Instruction-Set-Description deleted from b005607fc3
@ -161,7 +161,7 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
|
|||||||
|
|
||||||
inline uint32_t get_last_branch() { return reg.last_branch; }
|
inline uint32_t get_last_branch() { return reg.last_branch; }
|
||||||
|
|
||||||
protected:
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
struct ${coreDef.name}_regs {<%
|
struct ${coreDef.name}_regs {<%
|
||||||
registers.each { reg -> if(reg.size>0) {%>
|
registers.each { reg -> if(reg.size>0) {%>
|
||||||
@ -169,7 +169,6 @@ protected:
|
|||||||
}}%>
|
}}%>
|
||||||
uint32_t trap_state = 0, pending_trap = 0;
|
uint32_t trap_state = 0, pending_trap = 0;
|
||||||
uint64_t icount = 0;
|
uint64_t icount = 0;
|
||||||
uint64_t cycle = 0;
|
|
||||||
uint64_t instret = 0;
|
uint64_t instret = 0;
|
||||||
uint32_t last_branch;
|
uint32_t last_branch;
|
||||||
} reg;
|
} reg;
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
{
|
{
|
||||||
"${coreDef.name}" : [<%instructions.eachWithIndex{instr,index -> %>${index==0?"":","}
|
"${coreDef.name}" : [<%instructions.eachWithIndex{instr,index -> %>${index==0?"":","}
|
||||||
{
|
{
|
||||||
"name" : "${instr.name}",
|
"name" : "${instr.name}",
|
||||||
"size" : ${instr.length},
|
"size" : ${instr.length},
|
||||||
"delay" : ${instr.isConditional?"[1,1]":"1"}
|
"encoding": "${instr.encoding}",
|
||||||
|
"mask": "${instr.mask}",
|
||||||
|
"branch": ${instr.modifiesPC},
|
||||||
|
"delay" : ${instr.isConditional?"[1,1]":"1"}
|
||||||
}<%}%>
|
}<%}%>
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -45,6 +45,8 @@ def nativeTypeSize(int size){
|
|||||||
#include <iss/interp/vm_base.h>
|
#include <iss/interp/vm_base.h>
|
||||||
#include <util/logging.h>
|
#include <util/logging.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <boost/coroutine2/all.hpp>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#ifndef FMT_HEADER_ONLY
|
#ifndef FMT_HEADER_ONLY
|
||||||
#define FMT_HEADER_ONLY
|
#define FMT_HEADER_ONLY
|
||||||
@ -59,6 +61,7 @@ namespace interp {
|
|||||||
namespace ${coreDef.name.toLowerCase()} {
|
namespace ${coreDef.name.toLowerCase()} {
|
||||||
using namespace iss::arch;
|
using namespace iss::arch;
|
||||||
using namespace iss::debugger;
|
using namespace iss::debugger;
|
||||||
|
using namespace std::placeholders;
|
||||||
|
|
||||||
template <typename ARCH> class vm_impl : public iss::interp::vm_base<ARCH> {
|
template <typename ARCH> class vm_impl : public iss::interp::vm_base<ARCH> {
|
||||||
public:
|
public:
|
||||||
@ -130,6 +133,10 @@ protected:
|
|||||||
this->core.wait_until(type);
|
this->core.wait_until(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using yield_t = boost::coroutines2::coroutine<void>::push_type;
|
||||||
|
using coro_t = boost::coroutines2::coroutine<void>::pull_type;
|
||||||
|
std::vector<coro_t> spawn_blocks;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T& pc_assign(T& val){super::ex_info.branch_taken=true; return val;}
|
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){
|
inline uint8_t readSpace1(typename super::mem_type_e space, uint64_t addr){
|
||||||
@ -174,7 +181,18 @@ protected:
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void process_spawn_blocks() {
|
||||||
|
for(auto it = std::begin(spawn_blocks); it!=std::end(spawn_blocks);)
|
||||||
|
if(*it){
|
||||||
|
(*it)();
|
||||||
|
++it;
|
||||||
|
} else
|
||||||
|
spawn_blocks.erase(it);
|
||||||
|
}
|
||||||
|
<%functions.each{ it.eachLine { %>
|
||||||
|
${it}<%}%>
|
||||||
|
<%}%>
|
||||||
private:
|
private:
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* start opcode definitions
|
* start opcode definitions
|
||||||
@ -196,11 +214,6 @@ private:
|
|||||||
/* instruction ${idx}: ${instr.name} */
|
/* instruction ${idx}: ${instr.name} */
|
||||||
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr){
|
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr){
|
||||||
// pre execution stuff
|
// pre execution stuff
|
||||||
auto* PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
|
|
||||||
auto NEXT_PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
|
|
||||||
*PC=*NEXT_PC;
|
|
||||||
auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]);
|
|
||||||
*trap_state = *reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PENDING_TRAP]);
|
|
||||||
if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, ${idx});
|
if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, ${idx});
|
||||||
<%instr.fields.eachLine{%>${it}
|
<%instr.fields.eachLine{%>${it}
|
||||||
<%}%>if(this->disass_enabled){
|
<%}%>if(this->disass_enabled){
|
||||||
@ -208,6 +221,9 @@ private:
|
|||||||
<%instr.disass.eachLine{%>${it}
|
<%instr.disass.eachLine{%>${it}
|
||||||
<%}%>
|
<%}%>
|
||||||
}
|
}
|
||||||
|
auto* PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
|
||||||
|
auto* NEXT_PC = reinterpret_cast<uint${addrDataWidth}_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]);
|
||||||
// used registers<%instr.usedVariables.each{ k,v->
|
// used registers<%instr.usedVariables.each{ k,v->
|
||||||
if(v.isArray) {%>
|
if(v.isArray) {%>
|
||||||
auto* ${k} = reinterpret_cast<uint${nativeTypeSize(v.type.size)}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}0]);<% }else{ %>
|
auto* ${k} = reinterpret_cast<uint${nativeTypeSize(v.type.size)}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}0]);<% }else{ %>
|
||||||
@ -219,6 +235,7 @@ private:
|
|||||||
<%instr.behavior.eachLine{%>${it}
|
<%instr.behavior.eachLine{%>${it}
|
||||||
<%}%>} catch(...){}
|
<%}%>} catch(...){}
|
||||||
// post execution stuff
|
// post execution stuff
|
||||||
|
process_spawn_blocks();
|
||||||
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, ${idx});
|
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, ${idx});
|
||||||
// trap check
|
// trap check
|
||||||
if(*trap_state!=0){
|
if(*trap_state!=0){
|
||||||
@ -335,6 +352,8 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
|
|||||||
auto f = decode_inst(insn);
|
auto f = decode_inst(insn);
|
||||||
auto old_pc = pc.val;
|
auto old_pc = pc.val;
|
||||||
pc = (this->*f)(pc, insn);
|
pc = (this->*f)(pc, insn);
|
||||||
|
this->core.reg.PC = this->core.reg.NEXT_PC;
|
||||||
|
this->core.reg.trap_state = this->core.reg.pending_trap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pc;
|
return pc;
|
||||||
|
@ -201,7 +201,7 @@ public:
|
|||||||
|
|
||||||
void disass_output(uint64_t pc, const std::string instr) override {
|
void disass_output(uint64_t pc, const std::string instr) override {
|
||||||
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [s:0x{:x};c:{}]",
|
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [s:0x{:x};c:{}]",
|
||||||
pc, instr, (reg_t)state.mstatus, this->reg.icount);
|
pc, instr, (reg_t)state.mstatus, this->reg.icount + cycle_offset);
|
||||||
};
|
};
|
||||||
|
|
||||||
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
|
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
|
||||||
@ -218,6 +218,9 @@ public:
|
|||||||
csr[addr & csr.page_addr_mask] = val;
|
csr[addr & csr.page_addr_mask] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_irq_num(unsigned i) {
|
||||||
|
mcause_max_irq=1<<util::ilog2(i);
|
||||||
|
}
|
||||||
protected:
|
protected:
|
||||||
struct riscv_instrumentation_if : public iss::instrumentation_if {
|
struct riscv_instrumentation_if : public iss::instrumentation_if {
|
||||||
|
|
||||||
@ -230,11 +233,15 @@ protected:
|
|||||||
*/
|
*/
|
||||||
const std::string core_type_name() const override { return traits<BASE>::core_type; }
|
const std::string core_type_name() const override { return traits<BASE>::core_type; }
|
||||||
|
|
||||||
virtual uint64_t get_pc() { return arch.get_pc(); };
|
uint64_t get_pc() override { return arch.get_pc(); };
|
||||||
|
|
||||||
virtual uint64_t get_next_pc() { return arch.get_next_pc(); };
|
uint64_t get_next_pc() override { return arch.get_next_pc(); };
|
||||||
|
|
||||||
virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; };
|
uint64_t get_instr_count() { return arch.reg.icount; }
|
||||||
|
|
||||||
|
uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
|
||||||
|
|
||||||
|
void set_curr_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; };
|
||||||
|
|
||||||
riscv_hart_m_p<BASE, FEAT> &arch;
|
riscv_hart_m_p<BASE, FEAT> &arch;
|
||||||
};
|
};
|
||||||
@ -777,7 +784,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>::write_cause(unsigned addr, reg_t val) {
|
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_cause(unsigned addr, reg_t val) {
|
||||||
csr[mcause] = val & ((1UL<<(traits<BASE>::XLEN-1))|0xf); //TODO: make exception code size configurable
|
csr[mcause] = val & ((1UL<<(traits<BASE>::XLEN-1))| (mcause_max_irq-1));
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1029,7 +1036,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::e
|
|||||||
csr[mepc] = this->reg.NEXT_PC & get_pc_mask(); // store next address if interrupt
|
csr[mepc] = this->reg.NEXT_PC & get_pc_mask(); // store next address if interrupt
|
||||||
this->reg.pending_trap = 0;
|
this->reg.pending_trap = 0;
|
||||||
}
|
}
|
||||||
csr[mcause] = (trap_id << 31) + cause;
|
csr[mcause] = (trap_id << (traits<BASE>::XLEN-1)) + cause;
|
||||||
// update mstatus
|
// update mstatus
|
||||||
// xPP field of mstatus is written with the active privilege mode at the time
|
// xPP field of mstatus is written with the active privilege mode at the time
|
||||||
// of the trap; the x PIE field of mstatus
|
// of the trap; the x PIE field of mstatus
|
||||||
|
@ -293,21 +293,21 @@ public:
|
|||||||
|
|
||||||
std::pair<uint64_t, bool> load_file(std::string name, int type = -1) override;
|
std::pair<uint64_t, bool> load_file(std::string name, int type = -1) override;
|
||||||
|
|
||||||
virtual phys_addr_t virt2phys(const iss::addr_t &addr) override;
|
phys_addr_t virt2phys(const iss::addr_t &addr) override;
|
||||||
|
|
||||||
iss::status read(const address_type type, const access_type access, const uint32_t space,
|
iss::status read(const address_type type, const access_type access, const uint32_t space,
|
||||||
const uint64_t addr, const unsigned length, uint8_t *const data) override;
|
const uint64_t addr, const unsigned length, uint8_t *const data) override;
|
||||||
iss::status write(const address_type type, const access_type access, const uint32_t space,
|
iss::status write(const address_type type, const access_type access, const uint32_t space,
|
||||||
const uint64_t addr, const unsigned length, const uint8_t *const data) override;
|
const uint64_t addr, const unsigned length, const uint8_t *const data) override;
|
||||||
|
|
||||||
virtual uint64_t enter_trap(uint64_t flags) override { return riscv_hart_msu_vp::enter_trap(flags, fault_data, fault_data); }
|
uint64_t enter_trap(uint64_t flags) override { return riscv_hart_msu_vp::enter_trap(flags, fault_data, fault_data); }
|
||||||
virtual uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override;
|
uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override;
|
||||||
virtual uint64_t leave_trap(uint64_t flags) override;
|
uint64_t leave_trap(uint64_t flags) override;
|
||||||
void wait_until(uint64_t flags) override;
|
void wait_until(uint64_t flags) override;
|
||||||
|
|
||||||
void disass_output(uint64_t pc, const std::string instr) override {
|
void disass_output(uint64_t pc, const std::string instr) override {
|
||||||
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]",
|
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);
|
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.ccount + cycle_offset);
|
||||||
};
|
};
|
||||||
|
|
||||||
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
|
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
|
||||||
@ -340,6 +340,10 @@ protected:
|
|||||||
|
|
||||||
virtual uint64_t get_next_pc() { return arch.get_next_pc(); };
|
virtual uint64_t get_next_pc() { return arch.get_next_pc(); };
|
||||||
|
|
||||||
|
uint64_t get_instr_count() { return arch.reg.icount; }
|
||||||
|
|
||||||
|
uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
|
||||||
|
|
||||||
virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; };
|
virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; };
|
||||||
|
|
||||||
riscv_hart_msu_vp<BASE> &arch;
|
riscv_hart_msu_vp<BASE> &arch;
|
||||||
|
@ -207,16 +207,16 @@ public:
|
|||||||
iss::status write(const address_type type, const access_type access, const uint32_t space,
|
iss::status write(const address_type type, const access_type access, const uint32_t space,
|
||||||
const uint64_t addr, const unsigned length, const uint8_t *const data) override;
|
const uint64_t addr, const unsigned length, const uint8_t *const data) override;
|
||||||
|
|
||||||
virtual uint64_t enter_trap(uint64_t flags) override { return riscv_hart_mu_p::enter_trap(flags, fault_data, fault_data); }
|
uint64_t enter_trap(uint64_t flags) override { return riscv_hart_mu_p::enter_trap(flags, fault_data, fault_data); }
|
||||||
virtual uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override;
|
uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override;
|
||||||
virtual uint64_t leave_trap(uint64_t flags) override;
|
uint64_t leave_trap(uint64_t flags) override;
|
||||||
|
|
||||||
const reg_t& get_mhartid() const { return mhartid_reg; }
|
const reg_t& get_mhartid() const { return mhartid_reg; }
|
||||||
void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; };
|
void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; };
|
||||||
|
|
||||||
void disass_output(uint64_t pc, const std::string instr) override {
|
void disass_output(uint64_t pc, const std::string instr) override {
|
||||||
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]",
|
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);
|
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.icount + cycle_offset);
|
||||||
};
|
};
|
||||||
|
|
||||||
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
|
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
|
||||||
@ -233,6 +233,9 @@ public:
|
|||||||
csr[addr & csr.page_addr_mask] = val;
|
csr[addr & csr.page_addr_mask] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_irq_num(unsigned i) {
|
||||||
|
mcause_max_irq=1<<util::ilog2(i);
|
||||||
|
}
|
||||||
protected:
|
protected:
|
||||||
struct riscv_instrumentation_if : public iss::instrumentation_if {
|
struct riscv_instrumentation_if : public iss::instrumentation_if {
|
||||||
|
|
||||||
@ -249,6 +252,10 @@ protected:
|
|||||||
|
|
||||||
virtual uint64_t get_next_pc() { return arch.get_next_pc(); };
|
virtual uint64_t get_next_pc() { return arch.get_next_pc(); };
|
||||||
|
|
||||||
|
uint64_t get_instr_count() { return arch.reg.icount; }
|
||||||
|
|
||||||
|
uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
|
||||||
|
|
||||||
virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; };
|
virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; };
|
||||||
|
|
||||||
riscv_hart_mu_p<BASE, FEAT> &arch;
|
riscv_hart_mu_p<BASE, FEAT> &arch;
|
||||||
@ -959,7 +966,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>::write_cause(unsigned addr, reg_t val) {
|
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_cause(unsigned addr, reg_t val) {
|
||||||
csr[addr] = val & ((1UL<<(traits<BASE>::XLEN-1))|(mcause_max_irq-1)); //TODO: make exception code size configurable
|
csr[addr] = val & ((1UL<<(traits<BASE>::XLEN-1))|(mcause_max_irq-1));
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1319,7 +1326,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
|
|||||||
this->reg.pending_trap = 0;
|
this->reg.pending_trap = 0;
|
||||||
}
|
}
|
||||||
size_t adr = ucause | (new_priv << 8);
|
size_t adr = ucause | (new_priv << 8);
|
||||||
csr[adr] = (trap_id << 31) + cause;
|
csr[adr] = (trap_id << (traits<BASE>::XLEN-1)) + cause;
|
||||||
// update mstatus
|
// update mstatus
|
||||||
// xPP field of mstatus is written with the active privilege mode at the time
|
// xPP field of mstatus is written with the active privilege mode at the time
|
||||||
// of the trap; the x PIE field of mstatus
|
// of the trap; the x PIE field of mstatus
|
||||||
|
@ -217,7 +217,7 @@ struct tgc_c: public arch_if {
|
|||||||
|
|
||||||
inline uint32_t get_last_branch() { return reg.last_branch; }
|
inline uint32_t get_last_branch() { return reg.last_branch; }
|
||||||
|
|
||||||
protected:
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
struct TGC_C_regs {
|
struct TGC_C_regs {
|
||||||
uint32_t X0 = 0;
|
uint32_t X0 = 0;
|
||||||
@ -258,7 +258,6 @@ protected:
|
|||||||
uint32_t DPC = 0;
|
uint32_t DPC = 0;
|
||||||
uint32_t trap_state = 0, pending_trap = 0;
|
uint32_t trap_state = 0, pending_trap = 0;
|
||||||
uint64_t icount = 0;
|
uint64_t icount = 0;
|
||||||
uint64_t cycle = 0;
|
|
||||||
uint64_t instret = 0;
|
uint64_t instret = 0;
|
||||||
uint32_t last_branch;
|
uint32_t last_branch;
|
||||||
} reg;
|
} reg;
|
||||||
|
@ -37,9 +37,9 @@
|
|||||||
|
|
||||||
#include "iss/instrumentation_if.h"
|
#include "iss/instrumentation_if.h"
|
||||||
#include "iss/vm_plugin.h"
|
#include "iss/vm_plugin.h"
|
||||||
#include <json/json.h>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace iss {
|
namespace iss {
|
||||||
|
|
||||||
@ -49,11 +49,13 @@ class cycle_estimate: public iss::vm_plugin {
|
|||||||
BEGIN_BF_DECL(instr_desc, uint32_t)
|
BEGIN_BF_DECL(instr_desc, uint32_t)
|
||||||
BF_FIELD(taken, 24, 8)
|
BF_FIELD(taken, 24, 8)
|
||||||
BF_FIELD(not_taken, 16, 8)
|
BF_FIELD(not_taken, 16, 8)
|
||||||
BF_FIELD(size, 0, 16)
|
BF_FIELD(is_branch, 8, 8)
|
||||||
instr_desc(uint32_t size, uint32_t taken, uint32_t not_taken): instr_desc() {
|
BF_FIELD(size, 0, 8)
|
||||||
|
instr_desc(uint32_t size, uint32_t taken, uint32_t not_taken, bool branch): instr_desc() {
|
||||||
this->size=size;
|
this->size=size;
|
||||||
this->taken=taken;
|
this->taken=taken;
|
||||||
this->not_taken=not_taken;
|
this->not_taken=not_taken;
|
||||||
|
this->is_branch=branch;
|
||||||
}
|
}
|
||||||
END_BF_DECL();
|
END_BF_DECL();
|
||||||
|
|
||||||
@ -64,7 +66,7 @@ public:
|
|||||||
|
|
||||||
cycle_estimate(const cycle_estimate &&) = delete;
|
cycle_estimate(const cycle_estimate &&) = delete;
|
||||||
|
|
||||||
cycle_estimate(std::string config_file_name);
|
cycle_estimate(std::string const& config_file_name);
|
||||||
|
|
||||||
virtual ~cycle_estimate();
|
virtual ~cycle_estimate();
|
||||||
|
|
||||||
@ -88,7 +90,7 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
std::unordered_map<std::pair<uint64_t, uint64_t>, uint64_t, pair_hash> blocks;
|
std::unordered_map<std::pair<uint64_t, uint64_t>, uint64_t, pair_hash> blocks;
|
||||||
Json::Value root;
|
std::string config_file_name;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
99
incl/iss/plugin/pctrace.h
Normal file
99
incl/iss/plugin/pctrace.h
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2017, 2018, MINRES Technologies GmbH
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* eyck@minres.com - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _ISS_PLUGIN_COV_H_
|
||||||
|
#define _ISS_PLUGIN_COV_H_
|
||||||
|
|
||||||
|
#include <iss/vm_plugin.h>
|
||||||
|
#include "iss/instrumentation_if.h"
|
||||||
|
#include <json/json.h>
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
|
||||||
|
namespace iss {
|
||||||
|
namespace plugin {
|
||||||
|
|
||||||
|
class cov : public iss::vm_plugin {
|
||||||
|
struct instr_delay {
|
||||||
|
std::string instr_name;
|
||||||
|
size_t size;
|
||||||
|
size_t not_taken_delay;
|
||||||
|
size_t taken_delay;
|
||||||
|
};
|
||||||
|
BEGIN_BF_DECL(instr_desc, uint32_t)
|
||||||
|
BF_FIELD(taken, 24, 8)
|
||||||
|
BF_FIELD(not_taken, 16, 8)
|
||||||
|
BF_FIELD(is_branch, 8, 8)
|
||||||
|
BF_FIELD(size, 0, 8)
|
||||||
|
instr_desc(uint32_t size, uint32_t taken, uint32_t not_taken, bool branch): instr_desc() {
|
||||||
|
this->size=size;
|
||||||
|
this->taken=taken;
|
||||||
|
this->not_taken=not_taken;
|
||||||
|
this->is_branch=branch;
|
||||||
|
}
|
||||||
|
END_BF_DECL();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
cov(const cov &) = delete;
|
||||||
|
|
||||||
|
cov(const cov &&) = delete;
|
||||||
|
|
||||||
|
cov(std::string const &);
|
||||||
|
|
||||||
|
virtual ~cov();
|
||||||
|
|
||||||
|
cov &operator=(const cov &) = delete;
|
||||||
|
|
||||||
|
cov &operator=(const cov &&) = delete;
|
||||||
|
|
||||||
|
bool registration(const char *const version, vm_if &arch) override;
|
||||||
|
|
||||||
|
sync_type get_sync() override { return POST_SYNC; };
|
||||||
|
|
||||||
|
void callback(instr_info_t, exec_info const&) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
iss::instrumentation_if *instr_if {nullptr};
|
||||||
|
std::ofstream output;
|
||||||
|
std::string filename;
|
||||||
|
std::vector<instr_desc> delays;
|
||||||
|
bool jumped, first;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _ISS_PLUGIN_COV_H_ */
|
11
src/main.cpp
11
src/main.cpp
@ -44,6 +44,11 @@ using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>;
|
|||||||
#include "iss/arch/tgc_b.h"
|
#include "iss/arch/tgc_b.h"
|
||||||
using tgc_b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_b>;
|
using tgc_b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_b>;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CORE_TGC_C_XRB_NN
|
||||||
|
#include "iss/arch/riscv_hart_m_p.h"
|
||||||
|
#include "iss/arch/tgc_c_xrb_nn.h"
|
||||||
|
using tgc_c_xrb_nn_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c_xrb_nn>;
|
||||||
|
#endif
|
||||||
#ifdef CORE_TGC_D
|
#ifdef CORE_TGC_D
|
||||||
#include "iss/arch/riscv_hart_mu_p.h"
|
#include "iss/arch/riscv_hart_mu_p.h"
|
||||||
#include "iss/arch/tgc_d.h"
|
#include "iss/arch/tgc_d.h"
|
||||||
@ -152,6 +157,12 @@ int main(int argc, char *argv[]) {
|
|||||||
iss::create_cpu<tgc_b_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
iss::create_cpu<tgc_b_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CORE_TGC_C_XRB_NN
|
||||||
|
if (isa_opt == "tgc_c_xrb_nn") {
|
||||||
|
std::tie(cpu, vm) =
|
||||||
|
iss::create_cpu<tgc_c_xrb_nn_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
#ifdef CORE_TGC_D
|
#ifdef CORE_TGC_D
|
||||||
if (isa_opt == "tgc_d") {
|
if (isa_opt == "tgc_d") {
|
||||||
std::tie(cpu, vm) =
|
std::tie(cpu, vm) =
|
||||||
|
@ -36,58 +36,82 @@
|
|||||||
|
|
||||||
#include <iss/arch_if.h>
|
#include <iss/arch_if.h>
|
||||||
#include <util/logging.h>
|
#include <util/logging.h>
|
||||||
|
#include <rapidjson/document.h>
|
||||||
|
#include <rapidjson/istreamwrapper.h>
|
||||||
|
#include "rapidjson/writer.h"
|
||||||
|
#include "rapidjson/stringbuffer.h"
|
||||||
|
#include <rapidjson/ostreamwrapper.h>
|
||||||
|
#include <rapidjson/error/en.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
iss::plugin::cycle_estimate::cycle_estimate(std::string config_file_name)
|
using namespace rapidjson;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
iss::plugin::cycle_estimate::cycle_estimate(string const& config_file_name)
|
||||||
: arch_instr(nullptr)
|
: arch_instr(nullptr)
|
||||||
|
, config_file_name(config_file_name)
|
||||||
{
|
{
|
||||||
if (config_file_name.length() > 0) {
|
|
||||||
std::ifstream is(config_file_name);
|
|
||||||
if (is.is_open()) {
|
|
||||||
try {
|
|
||||||
is >> root;
|
|
||||||
} catch (Json::RuntimeError &e) {
|
|
||||||
LOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOG(ERR) << "Could not open input file " << config_file_name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
iss::plugin::cycle_estimate::~cycle_estimate() {
|
iss::plugin::cycle_estimate::~cycle_estimate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if& vm) {
|
bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if& vm) {
|
||||||
arch_instr = vm.get_arch()->get_instrumentation_if();
|
arch_instr = vm.get_arch()->get_instrumentation_if();
|
||||||
if(!arch_instr) return false;
|
if(!arch_instr) return false;
|
||||||
const std::string core_name = arch_instr->core_type_name();
|
const string core_name = arch_instr->core_type_name();
|
||||||
Json::Value &val = root[core_name];
|
if (config_file_name.length() > 0) {
|
||||||
if(!val.isNull() && val.isArray()){
|
ifstream is(config_file_name);
|
||||||
delays.reserve(val.size());
|
if (is.is_open()) {
|
||||||
for(auto it:val){
|
try {
|
||||||
auto name = it["name"];
|
IStreamWrapper isw(is);
|
||||||
auto size = it["size"];
|
Document d;
|
||||||
auto delay = it["delay"];
|
ParseResult ok = d.ParseStream(isw);
|
||||||
if(!name.isString() || !size.isUInt() || !(delay.isUInt() || delay.isArray())) throw std::runtime_error("JSON parse error");
|
if(ok) {
|
||||||
if(delay.isUInt()){
|
Value& val = d[core_name.c_str()];
|
||||||
delays.push_back(instr_desc{size.asUInt(), delay.asUInt(), 0});
|
if(val.IsArray()){
|
||||||
} else {
|
delays.reserve(val.Size());
|
||||||
delays.push_back(instr_desc{size.asUInt(), delay[0].asUInt(), delay[1].asUInt()});
|
for (auto it = val.Begin(); it != val.End(); ++it) {
|
||||||
}
|
auto& name = (*it)["name"];
|
||||||
}
|
auto& size = (*it)["size"];
|
||||||
} else {
|
auto& delay = (*it)["delay"];
|
||||||
LOG(ERR)<<"plugin cycle_estimate: could not find an entry for "<<core_name<<" in JSON file"<<std::endl;
|
auto& branch = (*it)["branch"];
|
||||||
|
if(delay.IsArray()) {
|
||||||
|
auto dt = delay[0].Get<unsigned>();
|
||||||
|
auto dnt = delay[1].Get<unsigned>();
|
||||||
|
delays.push_back(instr_desc{size.Get<unsigned>(), dt, dnt, branch.Get<bool>()});
|
||||||
|
} else if(delay.Is<unsigned>()) {
|
||||||
|
auto d = delay.Get<unsigned>();
|
||||||
|
delays.push_back(instr_desc{size.Get<unsigned>(), d, d, branch.Get<bool>()});
|
||||||
|
} else
|
||||||
|
throw runtime_error("JSON parse error");
|
||||||
|
}
|
||||||
|
} 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 " << config_file_name << ", reason: " << e.what();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG(ERR) << "Could not open input file " << config_file_name;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void iss::plugin::cycle_estimate::callback(instr_info_t instr_info, exec_info const&) {
|
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(arch_instr && "No instrumentation interface available but callback executed");
|
||||||
auto entry = delays[instr_info.instr_id];
|
auto entry = delays[instr_info.instr_id];
|
||||||
bool taken = (arch_instr->get_next_pc()-arch_instr->get_pc()) != (entry.size/8);
|
bool taken = exc_info.branch_taken;
|
||||||
if (taken && entry.taken > 1)
|
if (exc_info.branch_taken && (entry.taken > 1))
|
||||||
arch_instr->set_curr_instr_cycles(entry.taken);
|
arch_instr->set_curr_instr_cycles(entry.taken);
|
||||||
else if (entry.not_taken > 1)
|
else if (entry.not_taken > 1)
|
||||||
arch_instr->set_curr_instr_cycles(entry.not_taken);
|
arch_instr->set_curr_instr_cycles(entry.not_taken);
|
||||||
|
133
src/plugin/pctrace.cpp
Normal file
133
src/plugin/pctrace.cpp
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
#include <iss/arch_if.h>
|
||||||
|
#include <iss/plugin/pctrace.h>
|
||||||
|
#include <util/logging.h>
|
||||||
|
#include <rapidjson/document.h>
|
||||||
|
#include <rapidjson/istreamwrapper.h>
|
||||||
|
#include "rapidjson/writer.h"
|
||||||
|
#include "rapidjson/stringbuffer.h"
|
||||||
|
#include <rapidjson/ostreamwrapper.h>
|
||||||
|
#include <rapidjson/error/en.h>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
iss::plugin::cov::~cov() {
|
||||||
|
output.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool iss::plugin::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();
|
||||||
|
if (filename.length() > 0) {
|
||||||
|
ifstream is(filename);
|
||||||
|
if (is.is_open()) {
|
||||||
|
try {
|
||||||
|
IStreamWrapper isw(is);
|
||||||
|
Document d;
|
||||||
|
ParseResult ok = d.ParseStream(isw);
|
||||||
|
if(ok) {
|
||||||
|
Value& val = d[core_name.c_str()];
|
||||||
|
if(val.IsArray()){
|
||||||
|
delays.reserve(val.Size());
|
||||||
|
for (auto it = val.Begin(); it != val.End(); ++it) {
|
||||||
|
auto& name = (*it)["name"];
|
||||||
|
auto& size = (*it)["size"];
|
||||||
|
auto& delay = (*it)["delay"];
|
||||||
|
auto& branch = (*it)["branch"];
|
||||||
|
if(delay.IsArray()) {
|
||||||
|
auto dt = delay[0].Get<unsigned>();
|
||||||
|
auto dnt = delay[1].Get<unsigned>();
|
||||||
|
delays.push_back(instr_desc{size.Get<unsigned>(), dt, dnt, branch.Get<bool>()});
|
||||||
|
} else if(delay.Is<unsigned>()) {
|
||||||
|
auto d = delay.Get<unsigned>();
|
||||||
|
delays.push_back(instr_desc{size.Get<unsigned>(), d, d, branch.Get<bool>()});
|
||||||
|
} else
|
||||||
|
throw runtime_error("JSON parse error");
|
||||||
|
|
||||||
|
}
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG(ERR) << "Could not open input file " << filename;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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
|
||||||
|
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;
|
||||||
|
output<<std::hex <<"0x" << instr_if->get_pc() <<"," << delay << "\n";
|
||||||
|
}
|
@ -69,6 +69,8 @@ using tgc_d_xrb_nn_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_n
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <iss/plugin/cycle_estimate.h>
|
#include <iss/plugin/cycle_estimate.h>
|
||||||
#include <iss/plugin/instruction_count.h>
|
#include <iss/plugin/instruction_count.h>
|
||||||
|
#include <iss/plugin/pctrace.h>
|
||||||
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
#define STR(X) #X
|
#define STR(X) #X
|
||||||
@ -134,7 +136,8 @@ public:
|
|||||||
if (!owner->disass_output(pc, instr)) {
|
if (!owner->disass_output(pc, instr)) {
|
||||||
std::stringstream s;
|
std::stringstream s;
|
||||||
s << "[p:" << lvl[this->reg.PRIV] << ";s:0x" << std::hex << std::setfill('0')
|
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 << "]";
|
<< std::setw(sizeof(reg_t) * 2) << (reg_t)this->state.mstatus << std::dec << ";c:"
|
||||||
|
<< this->reg.icount + this->cycle_offset << "]";
|
||||||
SCCDEBUG(owner->name())<<"disass: "
|
SCCDEBUG(owner->name())<<"disass: "
|
||||||
<< "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t" << std::setw(40)
|
<< "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t" << std::setw(40)
|
||||||
<< std::setfill(' ') << std::left << instr << s.str();
|
<< std::setfill(' ') << std::left << instr << s.str();
|
||||||
@ -423,6 +426,10 @@ void core_complex::before_end_of_elaboration() {
|
|||||||
auto *plugin = new iss::plugin::cycle_estimate(filename);
|
auto *plugin = new iss::plugin::cycle_estimate(filename);
|
||||||
cpu->vm->register_plugin(*plugin);
|
cpu->vm->register_plugin(*plugin);
|
||||||
plugin_list.push_back(plugin);
|
plugin_list.push_back(plugin);
|
||||||
|
} else if (plugin_name == "pctrace") {
|
||||||
|
auto *plugin = new iss::plugin::cov(filename);
|
||||||
|
cpu->vm->register_plugin(*plugin);
|
||||||
|
plugin_list.push_back(plugin);
|
||||||
} else {
|
} else {
|
||||||
std::array<char const*, 1> a{{filename.c_str()}};
|
std::array<char const*, 1> a{{filename.c_str()}};
|
||||||
iss::plugin::loader l(plugin_name, {{"initPlugin"}});
|
iss::plugin::loader l(plugin_name, {{"initPlugin"}});
|
||||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user