29 Commits

Author SHA1 Message Date
58311b37db Merge branch 'feature/reduced_output' of
https://git.minres.com/DBT-RISE/DBT-RISE-TGC.git into
feature/reduced_output
2022-03-28 11:16:09 +02:00
ad8dc09bee Merge branch 'feature/reduced_output' of https://git.minres.com/DBT-RISE/DBT-RISE-TGC.git into feature/reduced_output 2022-03-28 11:15:45 +02:00
2bba5645c3 adds functionality to reduce the output 2022-02-16 10:13:29 +01:00
bf0a5a80de adds functionality to reduce the output 2022-02-16 10:12:45 +01:00
b37ef973de clean up 2022-02-14 20:36:12 +01:00
4c363f4073 adds additional functionality by fetching delay information 2022-02-11 11:28:00 +01:00
b8fa5fbbda adapt to extended instrumentation interface 2022-02-09 21:01:17 +01:00
ac86f14a54 add tgc_c_xrb_nn to tgc-sim 2022-02-02 21:33:42 +01:00
68b5697c8f Fix cycles JSON template 2022-02-01 21:48:56 +01:00
09b0f0d0c8 fix cycle estimation plugin 2022-02-01 21:14:50 +01:00
98b418ff43 fix JSON reading 2022-02-01 19:28:11 +01:00
059bd0d371 rework cycle estimation 2022-02-01 19:03:45 +01:00
ef2a4df925 simplify spawn block handling 2022-01-31 23:40:31 +01:00
7578906310 adds coverage plugin 2022-01-31 21:38:18 +01:00
afe8905ac9 fix else-ambiguity in CoreDSL description 2022-01-31 20:30:46 +01:00
ecc6091d1e cleans up source code to remove clang compiler warnings 2022-01-19 08:01:15 +01:00
3563ba80d0 add spawn blocks 2022-01-12 07:21:16 +01:00
09955be90f update gitignore 2021-12-05 08:45:49 +01:00
dd4c19a15c add option to configure number of irq 2021-12-01 12:56:36 +01:00
07d5af1dde fix stand-alone ISS compilation to include all generated cores 2021-11-26 17:56:40 +01:00
6f8595759e make tgc-sim include all available ISS 2021-11-25 20:00:27 +01:00
86da31033c correct size usage in pmp addr checks 2021-11-22 15:15:47 +01:00
974d103381 fix pmpcfg register write 2021-11-22 10:49:29 +01:00
309758b994 fix clic_cfg access scheme 2021-11-17 07:59:02 +01:00
965929d1eb remove descriptions 2021-11-15 09:30:16 +01:00
d47375a70e fix ebreak CSR update 2021-11-13 12:47:23 +01:00
d31b4ef5a8 fix MISA val 2021-11-11 12:58:57 +01:00
7452c5df43 add TGC_D_XRB_NN definition 2021-11-11 12:16:35 +01:00
43d7b99905 revert pmp check implementation 2021-11-11 09:58:19 +01:00
20 changed files with 936 additions and 679 deletions

1
.gitignore vendored
View File

@ -32,3 +32,4 @@ language.settings.xml
/dump.json
/src-gen/
/*.yaml
/*.json

View File

@ -7,6 +7,7 @@ project(dbt-rise-tgc VERSION 1.0.0)
include(GNUInstallDirs)
find_package(elfio)
find_package(Boost COMPONENTS coroutine)
if(WITH_LLVM)
if(DEFINED ENV{LLVM_HOME})
@ -28,16 +29,20 @@ endif()
add_subdirectory(softfloat)
# library files
FILE(GLOB TGC_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/iss/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/vm/interp/vm_*.cpp
)
FILE(GLOB TGC_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/iss/*.cpp)
FILE(GLOB TGC_VM_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/vm/interp/vm_*.cpp)
set(LIB_SOURCES
src/vm/fp_functions.cpp
src/plugin/instruction_count.cpp
src/plugin/cycle_estimate.cpp
src/plugin/pctrace.cpp
${TGC_SOURCES}
${TGC_VM_SOURCES}
)
if(TARGET RapidJSON)
list(APPEND LIB_SOURCES src/plugin/cycle_estimate.cpp)
endif()
if(WITH_LLVM)
FILE(GLOB TGC_LLVM_SOURCES
@ -66,7 +71,7 @@ elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
target_compile_options(${PROJECT_NAME} PRIVATE /wd4293)
endif()
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")
target_link_libraries(${PROJECT_NAME} PUBLIC -Wl,--whole-archive dbt-core -Wl,--no-whole-archive)
else()
@ -79,6 +84,10 @@ elseif(TARGET elfio::elfio)
else()
message(FATAL_ERROR "No elfio library found, maybe a find_package() call is missing")
endif()
if(TARGET RapidJSON)
target_link_libraries(${PROJECT_NAME} PUBLIC RapidJSON)
endif()
set_target_properties(${PROJECT_NAME} PROPERTIES
VERSION ${PROJECT_VERSION}
@ -105,8 +114,12 @@ project(tgc-sim)
find_package(Boost COMPONENTS program_options thread REQUIRED)
add_executable(${PROJECT_NAME} src/main.cpp)
# This sets the include directory for the reference project. This is the -I flag in gcc.
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
foreach(F IN LISTS TGC_SOURCES)
string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F})
string(TOUPPER ${CORE_NAME_LC} CORE_NAME)
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
endforeach()
if(WITH_LLVM)
target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_LLVM)
target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
@ -142,15 +155,11 @@ if(SystemC_FOUND)
add_library(${PROJECT_NAME} src/sysc/core_complex.cpp)
target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_SYSTEMC)
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss/arch/tgc_b.h)
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_TGC_B)
endif()
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss/arch/tgc_c.h)
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_TGC_C)
endif()
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss/arch/tgc_d.h)
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_TGC_D)
endif()
foreach(F IN LISTS TGC_SOURCES)
string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F})
string(TOUPPER ${CORE_NAME_LC} CORE_NAME)
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
endforeach()
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc scc)
if(WITH_LLVM)
target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})

View File

@ -1,14 +0,0 @@
import "CoreDSL-Instruction-Set-Description/RV32I.core_desc"
import "CoreDSL-Instruction-Set-Description/RVM.core_desc"
import "CoreDSL-Instruction-Set-Description/RVC.core_desc"
Core TGC_B provides RV32I, Zicsr, Zifencei {
architectural_state {
XLEN=32;
// definitions for the architecture wrapper
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
unsigned MISA_VAL = 0b01000000000000000000000100000000;
unsigned MARCHID_VAL = 0x80000002;
}
}

View File

@ -1,13 +0,0 @@
import "CoreDSL-Instruction-Set-Description/RV32I.core_desc"
import "CoreDSL-Instruction-Set-Description/RVM.core_desc"
import "CoreDSL-Instruction-Set-Description/RVC.core_desc"
Core TGC_D provides RV32I, Zicsr, Zifencei, RV32M, RV32IC {
architectural_state {
XLEN=32;
// definitions for the architecture wrapper
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
unsigned MISA_VAL = 0b01000000000100000011000100000100;
unsigned MARCHID_VAL = 0x80000004;
}
}

View File

@ -1,73 +0,0 @@
import "CoreDSL-Instruction-Set-Description/RISCVBase.core_desc"
import "CoreDSL-Instruction-Set-Description/RV32I.core_desc"
import "CoreDSL-Instruction-Set-Description/RVM.core_desc"
import "CoreDSL-Instruction-Set-Description/RVC.core_desc"
InstructionSet X_RB_MAC extends RISCVBase {
architectural_state {
register unsigned<64> ACC;
}
instructions {
RESET_ACC { // v-- funct7 v-- funct3
encoding: 7'd0 :: 10'b0 :: 3'd0 :: 5'b0 :: 7'b0001011;
behavior: ACC = 0;
}
GET_ACC_LO {
encoding: 7'd1 :: 10'b0 :: 3'd0 :: rd[4:0] :: 7'b0001011;
behavior: if (rd != 0) X[rd] = ACC[31:0];
}
GET_ACC_HI {
encoding: 7'd2 :: 10'b0 :: 3'd0 :: rd[4:0] :: 7'b0001011;
behavior: if (rd != 0) X[rd] = ACC[63:32];
}
MACU_32 {
encoding: 7'd0 :: rs2[4:0] :: rs1[4:0] :: 3'd1 :: 5'b0 :: 7'b0001011;
behavior: {
unsigned<64> mul = X[rs1] * X[rs2];
unsigned<33> add = mul[31:0] + ACC[31:0];
ACC = add[31:0];
}
}
MACS_32 {
encoding: 7'd1 :: rs2[4:0] :: rs1[4:0] :: 3'd1 :: 5'b0 :: 7'b0001011;
behavior: {
signed<64> mul = ((signed) X[rs1]) * ((signed) X[rs2]);
signed<33> add = ((signed) mul[31:0]) + ((signed) ACC[31:0]);
ACC = add[31:0]; // bit range always yields unsigned type
}
}
MACU_64 {
encoding: 7'd0 :: rs2[4:0] :: rs1[4:0] :: 3'd2 :: 5'b0 :: 7'b0001011;
behavior: {
unsigned<64> mul = X[rs1] * X[rs2];
unsigned<65> add = mul + ACC;
ACC = add[63:0];
}
}
MACS_64 {
encoding: 7'd1 :: rs2[4:0] :: rs1[4:0] :: 3'd2 :: 5'b0 :: 7'b0001011;
behavior: {
signed<64> mul = ((signed) X[rs1]) * ((signed) X[rs2]);
signed<65> add = mul + ((signed) ACC);
ACC = add[63:0];
}
}
}
}
Core TGC_D_XRB_MAC provides RV32I, Zicsr, Zifencei, RV32M, RV32IC, X_RB_MAC {
architectural_state {
XLEN=32;
// definitions for the architecture wrapper
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
unsigned MISA_VAL = 0b01000000000000000001000100000100;
unsigned MARCHID_VAL = 0x80000004;
}
}

View File

@ -161,7 +161,7 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
inline uint32_t get_last_branch() { return reg.last_branch; }
protected:
#pragma pack(push, 1)
struct ${coreDef.name}_regs {<%
registers.each { reg -> if(reg.size>0) {%>
@ -169,7 +169,6 @@ protected:
}}%>
uint32_t trap_state = 0, pending_trap = 0;
uint64_t icount = 0;
uint64_t cycle = 0;
uint64_t instret = 0;
uint32_t last_branch;
} reg;

View File

@ -1,9 +1,12 @@
{
{
"${coreDef.name}" : [<%instructions.eachWithIndex{instr,index -> %>${index==0?"":","}
{
"name" : "${instr.name}",
"size" : ${instr.length},
"delay" : ${generator.hasAttribute(instr.instruction, com.minres.coredsl.coreDsl.InstrAttribute.COND)?[1,1]:1}
"name" : "${instr.name}",
"size" : ${instr.length},
"encoding": "${instr.encoding}",
"mask": "${instr.mask}",
"branch": ${instr.modifiesPC},
"delay" : ${instr.isConditional?"[1,1]":"1"}
}<%}%>
]
}

View File

@ -45,6 +45,8 @@ def nativeTypeSize(int size){
#include <iss/interp/vm_base.h>
#include <util/logging.h>
#include <sstream>
#include <boost/coroutine2/all.hpp>
#include <functional>
#ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY
@ -59,6 +61,7 @@ namespace interp {
namespace ${coreDef.name.toLowerCase()} {
using namespace iss::arch;
using namespace iss::debugger;
using namespace std::placeholders;
template <typename ARCH> class vm_impl : public iss::interp::vm_base<ARCH> {
public:
@ -130,6 +133,10 @@ protected:
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>
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){
@ -174,7 +181,18 @@ protected:
auto sign_mask = 1ULL<<(W-1);
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:
/****************************************************************************
* start opcode definitions
@ -196,11 +214,6 @@ private:
/* instruction ${idx}: ${instr.name} */
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr){
// 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});
<%instr.fields.eachLine{%>${it}
<%}%>if(this->disass_enabled){
@ -208,6 +221,9 @@ private:
<%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->
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{ %>
@ -219,6 +235,7 @@ private:
<%instr.behavior.eachLine{%>${it}
<%}%>} catch(...){}
// post execution stuff
process_spawn_blocks();
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, ${idx});
// trap check
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 old_pc = pc.val;
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;

View File

@ -201,7 +201,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);
pc, instr, (reg_t)state.mstatus, this->reg.icount + cycle_offset);
};
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
@ -218,6 +218,9 @@ public:
csr[addr & csr.page_addr_mask] = val;
}
void set_irq_num(unsigned i) {
mcause_max_irq=1<<util::ilog2(i);
}
protected:
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; }
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;
};
@ -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) {
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;
}
@ -1015,7 +1022,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::e
//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] = 0;
csr[mtval] = addr;
break;
case 4:
case 6:
@ -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
this->reg.pending_trap = 0;
}
csr[mcause] = (trap_id << 31) + cause;
csr[mcause] = (trap_id << (traits<BASE>::XLEN-1)) + cause;
// update mstatus
// xPP field of mstatus is written with the active privilege mode at the time
// of the trap; the x PIE field of mstatus

View File

@ -293,21 +293,21 @@ public:
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,
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,
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); }
virtual 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 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, uint64_t addr, uint64_t instr) override;
uint64_t leave_trap(uint64_t flags) override;
void wait_until(uint64_t flags) 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:{}]",
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; }
@ -340,6 +340,10 @@ protected:
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; };
riscv_hart_msu_vp<BASE> &arch;
@ -1276,7 +1280,27 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f
* access, or page-fault exception occurs, mtval is written with the
* faulting effective address.
*/
csr[utval | (new_priv << 8)] = cause==2?((instr & 0x3)==3?instr:instr&0xffff):fault_data;
switch(cause){
case 0:
csr[utval | (new_priv << 8)] = static_cast<reg_t>(addr);
break;
case 2:
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;
break;
case 4:
case 6:
case 7:
csr[utval | (new_priv << 8)] = fault_data;
break;
default:
csr[utval | (new_priv << 8)] = 0;
}
fault_data = 0;
} else {
if (cur_priv != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0)

View File

@ -207,16 +207,16 @@ public:
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;
virtual 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;
virtual uint64_t leave_trap(uint64_t flags) override;
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, uint64_t addr, uint64_t instr) override;
uint64_t leave_trap(uint64_t flags) override;
const reg_t& get_mhartid() const { return mhartid_reg; }
void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; };
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);
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; }
@ -233,6 +233,9 @@ public:
csr[addr & csr.page_addr_mask] = val;
}
void set_irq_num(unsigned i) {
mcause_max_irq=1<<util::ilog2(i);
}
protected:
struct riscv_instrumentation_if : public iss::instrumentation_if {
@ -249,6 +252,10 @@ protected:
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; };
riscv_hart_mu_p<BASE, FEAT> &arch;
@ -330,6 +337,7 @@ protected:
iss::status write_dcsr_reg(unsigned addr, reg_t val);
iss::status read_dpc_reg(unsigned addr, reg_t &val);
iss::status write_dpc_reg(unsigned addr, reg_t val);
iss::status write_pmpcfg_reg(unsigned addr, reg_t val);
reg_t mhartid_reg{0x0};
std::function<iss::status(phys_addr_t, unsigned, uint8_t *const)>mem_read_cb;
@ -425,7 +433,7 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p()
}
for(size_t i=pmpcfg0; i<=pmpcfg3; ++i){
csr_rd_cb[i] = &this_class::read_csr_reg;
csr_wr_cb[i] = &this_class::write_csr_reg;
csr_wr_cb[i] = &this_class::write_pmpcfg_reg;
}
}
if(FEAT & FEAT_EXT_N){
@ -544,6 +552,12 @@ template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m
throw std::runtime_error("memory load file not found");
}
template<typename BASE, features_e FEAT>
inline iss::status riscv_hart_mu_p<BASE, FEAT>::write_pmpcfg_reg(unsigned addr, reg_t val) {
csr[addr] = val & 0x9f9f9f9f;
return iss::Ok;
}
template <typename BASE, features_e FEAT> bool riscv_hart_mu_p<BASE, FEAT>::pmp_check(const access_type type, const uint64_t addr, const unsigned len) {
constexpr auto PMP_SHIFT=2U;
constexpr auto PMP_R = 0x1U;
@ -554,37 +568,74 @@ template <typename BASE, features_e FEAT> bool riscv_hart_mu_p<BASE, FEAT>::pmp_
constexpr auto PMP_TOR =0x1U;
constexpr auto PMP_NA4 =0x2U;
constexpr auto PMP_NAPOT =0x3U;
constexpr auto pmp_num_regs = 16;
reg_t tor_base = 0;
reg_t base = 0;
auto any_active = false;
auto lower_addr = addr >>2;
auto upper_addr = (addr+len-1)>>2;
for (size_t i = 0; i < pmp_num_regs; i++) {
for (size_t i = 0; i < 16; i++) {
reg_t tor = csr[pmpaddr0+i] << PMP_SHIFT;
uint8_t cfg = csr[pmpcfg0+(i/4)]>>(i%4);
uint8_t cfg_next = i==(pmp_num_regs-1)? 0 : csr[pmpcfg0+((i+1)/4)]>>((i+1)%4);
auto pmpaddr = csr[pmpaddr0+i];
if (cfg & PMP_A) {
any_active=true;
auto is_tor = bit_sub<3, 2>(cfg) == PMP_TOR;
auto is_napot = bit_sub<4, 1>(cfg) && bit_sub<3, 2>(cfg_next)!= PMP_TOR;
if(is_napot) {
reg_t mask = bit_sub<3, 1>(cfg)?~( pmpaddr & ~(pmpaddr + 1)): 0x3fffffff;
auto mpmpaddr = pmpaddr & mask;
if((lower_addr&mask) == mpmpaddr && (upper_addr&mask)==mpmpaddr)
return (this->reg.PRIV == PRIV_M && !(cfg & PMP_L)) ||
(type == access_type::READ && (cfg & PMP_R)) ||
(type == access_type::WRITE && (cfg & PMP_W)) ||
(type == access_type::FETCH && (cfg & PMP_X));
} else if(is_tor) {
if(lower_addr>=tor_base && upper_addr<=pmpaddr)
return (this->reg.PRIV == PRIV_M && !(cfg & PMP_L)) ||
(type == access_type::READ && (cfg & PMP_R)) ||
(type == access_type::WRITE && (cfg & PMP_W)) ||
(type == access_type::FETCH && (cfg & PMP_X));
auto pmp_a = (cfg & PMP_A) >> 3;
auto is_tor = pmp_a == PMP_TOR;
auto is_na4 = pmp_a == PMP_NA4;
reg_t mask = (csr[pmpaddr0+i] << 1) | (!is_na4);
mask = ~(mask & ~(mask + 1)) << PMP_SHIFT;
// Check each 4-byte sector of the access
auto any_match = false;
auto all_match = true;
for (reg_t offset = 0; offset < len; offset += 1 << PMP_SHIFT) {
reg_t cur_addr = addr + offset;
auto napot_match = ((cur_addr ^ tor) & mask) == 0;
auto tor_match = base <= (cur_addr+len-1) && cur_addr < tor;
auto match = is_tor ? tor_match : napot_match;
any_match |= match;
all_match &= match;
}
if (any_match) {
// If the PMP matches only a strict subset of the access, fail it
if (!all_match)
return false;
return (this->reg.PRIV == PRIV_M && !(cfg & PMP_L)) ||
(type == access_type::READ && (cfg & PMP_R)) ||
(type == access_type::WRITE && (cfg & PMP_W)) ||
(type == access_type::FETCH && (cfg & PMP_X));
}
}
tor_base = pmpaddr;
base = tor;
}
// constexpr auto pmp_num_regs = 16;
// reg_t tor_base = 0;
// auto any_active = false;
// auto lower_addr = addr >>2;
// auto upper_addr = (addr+len-1)>>2;
// for (size_t i = 0; i < pmp_num_regs; i++) {
// uint8_t cfg = csr[pmpcfg0+(i/4)]>>(i%4);
// uint8_t cfg_next = i==(pmp_num_regs-1)? 0 : csr[pmpcfg0+((i+1)/4)]>>((i+1)%4);
// auto pmpaddr = csr[pmpaddr0+i];
// if (cfg & PMP_A) {
// any_active=true;
// auto is_tor = bit_sub<3, 2>(cfg) == PMP_TOR;
// auto is_napot = bit_sub<4, 1>(cfg) && bit_sub<3, 2>(cfg_next)!= PMP_TOR;
// if(is_napot) {
// reg_t mask = bit_sub<3, 1>(cfg)?~( pmpaddr & ~(pmpaddr + 1)): 0x3fffffff;
// auto mpmpaddr = pmpaddr & mask;
// if((lower_addr&mask) == mpmpaddr && (upper_addr&mask)==mpmpaddr)
// return (this->reg.PRIV == PRIV_M && !(cfg & PMP_L)) ||
// (type == access_type::READ && (cfg & PMP_R)) ||
// (type == access_type::WRITE && (cfg & PMP_W)) ||
// (type == access_type::FETCH && (cfg & PMP_X));
// } else if(is_tor) {
// if(lower_addr>=tor_base && upper_addr<=pmpaddr)
// return (this->reg.PRIV == PRIV_M && !(cfg & PMP_L)) ||
// (type == access_type::READ && (cfg & PMP_R)) ||
// (type == access_type::WRITE && (cfg & PMP_W)) ||
// (type == access_type::FETCH && (cfg & PMP_X));
// }
// }
// tor_base = pmpaddr;
// }
return !any_active || this->reg.PRIV == PRIV_M;
}
@ -915,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) {
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;
}
@ -1185,7 +1236,7 @@ template<typename BASE, features_e FEAT>
iss::status riscv_hart_mu_p<BASE, FEAT>::write_clic(uint64_t addr, unsigned length, const uint8_t *const data) {
if(addr==clic_base_addr) { // cliccfg
clic_cfg_reg = *data;
clic_cfg_reg&= 0x7f;
clic_cfg_reg&= 0x7e;
// } else if(addr>=(clic_base_addr+4) && (addr+length)<=(clic_base_addr+4)){ // clicinfo
// write_uint32(addr, clic_info_reg, data, length);
} else if(addr>=(clic_base_addr+0x40) && (addr+length)<=(clic_base_addr+0xC0)){ // clicinttrig
@ -1257,7 +1308,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
//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)] = 0;
csr[utval | (new_priv << 8)] = addr;
break;
case 4:
case 6:
@ -1275,7 +1326,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
this->reg.pending_trap = 0;
}
size_t adr = ucause | (new_priv << 8);
csr[adr] = (trap_id << 31) + cause;
csr[adr] = (trap_id << (traits<BASE>::XLEN-1)) + cause;
// update mstatus
// xPP field of mstatus is written with the active privilege mode at the time
// of the trap; the x PIE field of mstatus

View File

@ -217,7 +217,7 @@ struct tgc_c: public arch_if {
inline uint32_t get_last_branch() { return reg.last_branch; }
protected:
#pragma pack(push, 1)
struct TGC_C_regs {
uint32_t X0 = 0;
@ -258,7 +258,6 @@ protected:
uint32_t DPC = 0;
uint32_t trap_state = 0, pending_trap = 0;
uint64_t icount = 0;
uint64_t cycle = 0;
uint64_t instret = 0;
uint32_t last_branch;
} reg;

View File

@ -37,9 +37,9 @@
#include "iss/instrumentation_if.h"
#include "iss/vm_plugin.h"
#include <json/json.h>
#include <string>
#include <unordered_map>
#include <vector>
namespace iss {
@ -49,11 +49,13 @@ class cycle_estimate: public iss::vm_plugin {
BEGIN_BF_DECL(instr_desc, uint32_t)
BF_FIELD(taken, 24, 8)
BF_FIELD(not_taken, 16, 8)
BF_FIELD(size, 0, 16)
instr_desc(uint32_t size, uint32_t taken, uint32_t not_taken): instr_desc() {
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();
@ -64,7 +66,7 @@ public:
cycle_estimate(const cycle_estimate &&) = delete;
cycle_estimate(std::string config_file_name);
cycle_estimate(std::string const& config_file_name);
virtual ~cycle_estimate();
@ -88,7 +90,7 @@ private:
}
};
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
View 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_ */

View File

@ -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"
using tgc_b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_b>;
#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
#include "iss/arch/riscv_hart_mu_p.h"
#include "iss/arch/tgc_d.h"
@ -54,6 +59,16 @@ using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d, (iss::arch:
#include "iss/arch/tgc_d_xrb_mac.h"
using tgc_d_xrb_mac_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_mac, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
#endif
#ifdef CORE_TGC_D_XRB_NN
#include "iss/arch/riscv_hart_mu_p.h"
#include "iss/arch/tgc_d_xrb_nn.h"
using tgc_d_xrb_nn_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_nn, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
#endif
#ifdef CORE_TGC_E
#include "iss/arch/riscv_hart_mu_p.h"
#include "iss/arch/tgc_e.h"
using tgc_e_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_e, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
#endif
#ifdef WITH_LLVM
#include <iss/llvm/jit_helper.h>
#endif
@ -142,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>());
} else
#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
if (isa_opt == "tgc_d") {
std::tie(cpu, vm) =
@ -153,9 +174,21 @@ int main(int argc, char *argv[]) {
std::tie(cpu, vm) =
iss::create_cpu<tgc_d_xrb_mac_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
} else
#endif
#ifdef CORE_TGC_D_XRB_NN
if (isa_opt == "tgc_d_xrb_nn") {
std::tie(cpu, vm) =
iss::create_cpu<tgc_d_xrb_nn_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
} else
#endif
#ifdef CORE_TGC_E
if (isa_opt == "tgc_e") {
std::tie(cpu, vm) =
iss::create_cpu<tgc_e_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
} else
#endif
{
LOG(ERR) << "Illegal argument value for '--isa': " << clim["isa"].as<std::string>() << std::endl;
LOG(ERR) << "Illegal argument value for '--isa': " << isa_opt << std::endl;
return 127;
}
if (clim.count("plugin")) {

View File

@ -36,58 +36,82 @@
#include <iss/arch_if.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>
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)
, 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() {
}
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 std::string core_name = arch_instr->core_type_name();
Json::Value &val = root[core_name];
if(!val.isNull() && val.isArray()){
delays.reserve(val.size());
for(auto it:val){
auto name = it["name"];
auto size = it["size"];
auto delay = it["delay"];
if(!name.isString() || !size.isUInt() || !(delay.isUInt() || delay.isArray())) throw std::runtime_error("JSON parse error");
if(delay.isUInt()){
delays.push_back(instr_desc{size.asUInt(), delay.asUInt(), 0});
} else {
delays.push_back(instr_desc{size.asUInt(), delay[0].asUInt(), delay[1].asUInt()});
}
}
} else {
LOG(ERR)<<"plugin cycle_estimate: could not find an entry for "<<core_name<<" in JSON file"<<std::endl;
arch_instr = vm.get_arch()->get_instrumentation_if();
if(!arch_instr) return false;
const string core_name = arch_instr->core_type_name();
if (config_file_name.length() > 0) {
ifstream is(config_file_name);
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 " << 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");
auto entry = delays[instr_info.instr_id];
bool taken = (arch_instr->get_next_pc()-arch_instr->get_pc()) != (entry.size/8);
if (taken && entry.taken > 1)
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);
else if (entry.not_taken > 1)
arch_instr->set_curr_instr_cycles(entry.not_taken);

133
src/plugin/pctrace.cpp Normal file
View 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";
}

View File

@ -57,6 +57,11 @@ using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d, iss::arch::
#include "iss/arch/tgc_d_xrb_mac.h"
using tgc_d_xrb_mac_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_mac, iss::arch::FEAT_PMP>;
#endif
#ifdef CORE_TGC_D_XRB_NN
#include "iss/arch/riscv_hart_mu_p.h"
#include "iss/arch/tgc_d_xrb_nn.h"
using tgc_d_xrb_nn_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_nn, iss::arch::FEAT_PMP>;
#endif
#include <scc/report.h>
#include <util/ities.h>
#include <iostream>
@ -64,6 +69,8 @@ using tgc_d_xrb_mac_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_
#include <array>
#include <iss/plugin/cycle_estimate.h>
#include <iss/plugin/instruction_count.h>
#include <iss/plugin/pctrace.h>
// clang-format on
#define STR(X) #X
@ -129,7 +136,8 @@ public:
if (!owner->disass_output(pc, instr)) {
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 << "]";
<< std::setw(sizeof(reg_t) * 2) << (reg_t)this->state.mstatus << std::dec << ";c:"
<< this->reg.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();
@ -303,8 +311,11 @@ public:
#ifdef CORE_TGC_D
CREATE_CORE(tgc_d)
#endif
#ifdef CORE_TGC_D_XRB_MACD
#ifdef CORE_TGC_D_XRB_MAC
CREATE_CORE(tgc_d_xrb_mac)
#endif
#ifdef CORE_TGC_D_XRB_NN
CREATE_CORE(tgc_d_xrb_nn)
#endif
{
LOG(ERR) << "Illegal argument value for core type: " << type << std::endl;
@ -415,6 +426,10 @@ void core_complex::before_end_of_elaboration() {
auto *plugin = new iss::plugin::cycle_estimate(filename);
cpu->vm->register_plugin(*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 {
std::array<char const*, 1> a{{filename.c_str()}};
iss::plugin::loader l(plugin_name, {{"initPlugin"}});

File diff suppressed because it is too large Load Diff