33 Commits

Author SHA1 Message Date
4876f18ba9 adds windows compatibility fixes 2022-07-18 11:43:42 +02:00
a53ee42e13 updates TGC_C according to CoreDSL description update 2022-07-12 22:34:22 +02:00
12ccfc055a updates generate tgc_c definition 2022-07-11 22:58:10 +02:00
feaa49d367 removes decoder again as there is some issue 2022-06-20 00:39:11 +02:00
18f33b4a68 fixes ordering of instructions for decoding 2022-06-19 16:52:29 +02:00
f096b15dbd factors decoder into separate component 2022-06-19 13:17:31 +02:00
cb5375258a removes compilatioon of unneeded files 2022-06-10 07:19:46 +02:00
076b5a39ad fix class naming 2022-06-02 08:30:49 +02:00
f40ab41899 fix left-over from layout refactoring 2022-06-02 08:30:02 +02:00
e8fd5143bc fix build options for standalone ISS 2022-05-31 11:05:26 +02:00
31fb51de95 update tgc_c generated code 2022-05-30 22:15:44 +02:00
5d481eb79d fix generation of non-exception code 2022-05-30 22:04:16 +02:00
1c90fe765d Merge remote-tracking branch 'origin/Trace_enhancement' into develop 2022-05-30 14:18:09 +02:00
52ed8b81a6 fixed template to work with previous code generator 2022-05-30 14:08:02 +02:00
0703a0a845 update tgc-mapper 2022-05-30 07:45:32 +02:00
0c542d42aa separate generated sources 2022-05-21 12:48:28 +02:00
966d1616c5 change source code to unified layout 2022-05-21 11:55:24 +02:00
1720bd4aaa adds support for compressed instructions 2022-05-20 15:17:58 +02:00
df16378605 update template for changed code generator 2022-05-18 19:10:34 +02:00
1438f0f373 add backannotation to pc trace plugin 2022-05-17 15:29:04 +02:00
766f3ba9ee fix assertion in compressed pctrace writer 2022-05-13 12:38:12 +02:00
5da4e6b424 fix alignment check for unaligned debugger accesses 2022-05-13 12:37:47 +02:00
e382217e04 update vm_tgc_c due reworked CoreDSL generator 2022-05-11 18:52:15 +02:00
9db4e3fd87 fix assertion 2022-05-10 16:13:21 +02:00
bb658be3b4 Merge branch 'develop' of https://git.minres.com/DBT-RISE/DBT-RISE-TGC into develop 2022-05-08 15:25:56 +02:00
6579780dc9 add call column in output 2022-05-08 15:24:26 +02:00
e56bc12788 fix non-lz4 build of plugin 2022-05-07 17:27:11 +02:00
e88f309ea2 add lz4 compression to pctrace 2022-05-07 17:22:06 +02:00
03bec27376 implement extended instrumentation interface 2022-04-26 17:14:33 +02:00
9d9008a3a2 fix pointer mess 2022-04-26 15:35:17 +02:00
5f6d462973 check that no interrupts are pending before entering the wfi wait 2022-04-26 13:58:20 +02:00
a92b84bef4 add code word access for ISS plugins 2022-04-25 14:18:19 +02:00
477c530847 extend debug mode handling 2022-04-13 11:41:01 +02:00
38 changed files with 2945 additions and 7314 deletions

1
.gitignore vendored
View File

@ -30,6 +30,5 @@ language.settings.xml
/.gdbinit
/*.out
/dump.json
/src-gen/
/*.yaml
/*.json

View File

@ -29,32 +29,34 @@ endif()
add_subdirectory(softfloat)
# library files
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)
FILE(GLOB GEN_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src-gen/iss/arch/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/interp/vm_*.cpp
)
set(LIB_SOURCES
src/vm/fp_functions.cpp
src/plugin/instruction_count.cpp
${TGC_SOURCES}
${TGC_VM_SOURCES}
src/iss/plugin/instruction_count.cpp
src/iss/arch/tgc_c.cpp
src/vm/interp/vm_tgc_c.cpp
src/vm/fp_functions.cpp
${GEN_SOURCES}
)
if(TARGET RapidJSON)
list(APPEND LIB_SOURCES src/plugin/cycle_estimate.cpp src/plugin/pctrace.cpp)
list(APPEND LIB_SOURCES src/iss/plugin/cycle_estimate.cpp src/iss/plugin/pctrace.cpp)
endif()
if(WITH_LLVM)
FILE(GLOB TGC_LLVM_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/vm/llvm/vm_*.cpp
FILE(GLOB LLVM_GEN_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/llvm/vm_*.cpp
)
list(APPEND LIB_SOURCES ${TGC_LLVM_SOURCES})
list(APPEND LIB_SOURCES ${LLVM_GEN_SOURCES})
endif()
if(WITH_TCC)
FILE(GLOB TGC_TCC_SOURCES
FILE(GLOB TCC_GEN_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/vm/tcc/vm_*.cpp
)
list(APPEND LIB_SOURCES ${TGC_TCC_SOURCES})
list(APPEND LIB_SOURCES ${TCC_GEN_SOURCES})
endif()
# Define the library
@ -69,7 +71,8 @@ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
target_compile_options(${PROJECT_NAME} PRIVATE /wd4293)
endif()
target_include_directories(${PROJECT_NAME} PUBLIC incl)
target_include_directories(${PROJECT_NAME} PUBLIC src)
target_include_directories(${PROJECT_NAME} PUBLIC src-gen)
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-rise-core -Wl,--no-whole-archive)
@ -83,6 +86,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()
@ -113,6 +120,7 @@ project(tgc-sim)
find_package(Boost COMPONENTS program_options thread REQUIRED)
add_executable(${PROJECT_NAME} src/main.cpp)
FILE(GLOB TGC_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/iss/arch/*.cpp)
foreach(F IN LISTS TGC_SOURCES)
string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F})
string(TOUPPER ${CORE_NAME_LC} CORE_NAME)

View File

@ -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 {

View File

@ -33,13 +33,13 @@
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
}
%>
#include "${coreDef.name.toLowerCase()}.h"
#include "util/ities.h"
#include <util/logging.h>
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <cstdio>
#include <cstring>
#include <fstream>
@ -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() {

View File

@ -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;

View File

@ -0,0 +1,86 @@
#include "${coreDef.name.toLowerCase()}.h"
#include <vector>
#include <array>
#include <cstdlib>
#include <algorithm>
namespace iss {
namespace arch {
namespace {
// according to
// https://stackoverflow.com/questions/8871204/count-number-of-1s-in-binary-representation
#ifdef __GCC__
constexpr size_t bit_count(uint32_t u) { return __builtin_popcount(u); }
#elif __cplusplus < 201402L
constexpr size_t uCount(uint32_t u) { return u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111); }
constexpr size_t bit_count(uint32_t u) { return ((uCount(u) + (uCount(u) >> 3)) & 030707070707) % 63; }
#else
constexpr size_t bit_count(uint32_t u) {
size_t uCount = u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111);
return ((uCount + (uCount >> 3)) & 030707070707) % 63;
}
#endif
using opcode_e = traits<${coreDef.name.toLowerCase()}>::opcode_e;
/****************************************************************************
* start opcode definitions
****************************************************************************/
struct instruction_desriptor {
size_t length;
uint32_t value;
uint32_t mask;
opcode_e op;
};
const std::array<instruction_desriptor, ${instructions.size}> instr_descr = {{
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
{${instr.length}, ${instr.encoding}, ${instr.mask}, opcode_e::${instr.instruction.name}},<%}%>
}};
}
template<>
struct instruction_decoder<${coreDef.name.toLowerCase()}> {
using opcode_e = traits<${coreDef.name.toLowerCase()}>::opcode_e;
using code_word_t=traits<${coreDef.name.toLowerCase()}>::code_word_t;
struct instruction_pattern {
uint32_t value;
uint32_t mask;
opcode_e id;
};
std::array<std::vector<instruction_pattern>, 4> qlut;
template<typename T>
unsigned decode_instruction(T);
instruction_decoder() {
for (auto instr : instr_descr) {
auto quadrant = instr.value & 0x3;
qlut[quadrant].push_back(instruction_pattern{instr.value, instr.mask, instr.op});
}
for(auto& lut: qlut){
std::sort(std::begin(lut), std::end(lut), [](instruction_pattern const& a, instruction_pattern const& b){
return bit_count(a.mask) < bit_count(b.mask);
});
}
}
};
template<>
unsigned instruction_decoder<${coreDef.name.toLowerCase()}>::decode_instruction<traits<${coreDef.name.toLowerCase()}>::code_word_t>(traits<${coreDef.name.toLowerCase()}>::code_word_t instr){
auto res = std::find_if(std::begin(qlut[instr&0x3]), std::end(qlut[instr&0x3]), [instr](instruction_pattern const& e){
return !((instr&e.mask) ^ e.value );
});
return static_cast<unsigned>(res!=std::end(qlut[instr&0x3])? res->id : opcode_e::MAX_OPCODE);
}
std::unique_ptr<instruction_decoder<${coreDef.name.toLowerCase()}>> traits<${coreDef.name.toLowerCase()}>::get_decoder(){
return std::make_unique<instruction_decoder<${coreDef.name.toLowerCase()}>>();
}
}
}

View File

@ -12,5 +12,6 @@
${name}: <% instrList.findAll{!it.instruction.name.startsWith("__")}.each { %>
- ${it.instruction.name}:
encoding: ${it.encoding}
mask: ${it.mask}<%}}%>
mask: ${it.mask}<%if(it.attributes.size) {%>
attributes: ${it.attributes}<%}}}%>

View File

@ -36,7 +36,7 @@ def nativeTypeSize(int size){
if(size<=8) return 8; else if(size<=16) return 16; else if(size<=32) return 32; else return 64;
}
%>
#include "../fp_functions.h"
#include <vm/fp_functions.h>
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/debugger/gdb_session.h>
@ -73,6 +73,7 @@ public:
using addr_t = typename super::addr_t;
using reg_t = typename traits::reg_t;
using mem_type_e = typename traits::mem_type_e;
using opcode_e = typename traits::opcode_e;
vm_impl();
@ -121,7 +122,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 +142,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 +278,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)){
@ -301,24 +302,21 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id));
switch(inst_id){<%instructions.eachWithIndex{instr, idx -> %>
case arch::traits<ARCH>::opcode_e::${instr.name}: {
<%instr.fields.eachLine{%>${it}
<%}%>if(this->disass_enabled){
/* generate console output when executing the command */
<%instr.disass.eachLine{%>${it}
<%}%>
}
// 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{ %>
auto* ${k} = reinterpret_cast<uint${nativeTypeSize(v.type.size)}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}]);
<%}}%>// calculate next pc value
*NEXT_PC = *PC + ${instr.length/8};
// execute instruction
try {
<%instr.behavior.eachLine{%>${it}
<%}%>} catch(...){}
}
break;<%}%>
<%instr.fields.eachLine{%>${it}
<%}%>if(this->disass_enabled){
/* generate console output when executing the command */<%instr.disass.eachLine{%>
${it}<%}%>
}
// 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{ %>
auto* ${k} = reinterpret_cast<uint${nativeTypeSize(v.type.size)}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}]);
<%}}%>// calculate next pc value
*NEXT_PC = *PC + ${instr.length/8};
// execute instruction<%instr.behavior.eachLine{%>
${it}<%}%>
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;

View File

@ -30,10 +30,10 @@
*
*******************************************************************************/
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/debugger/gdb_session.h>
#include <iss/debugger/server.h>
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/iss.h>
#include <iss/llvm/vm_base.h>
#include <util/logging.h>

View File

@ -1 +0,0 @@
/tgc_*.h

2
src-gen/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/iss
/vm

View File

@ -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,

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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;

View File

@ -30,9 +30,9 @@
*
*******************************************************************************/
#include "tgc_c.h"
#include "util/ities.h"
#include <util/logging.h>
#include <iss/arch/tgc_c.h>
#include <cstdio>
#include <cstring>
#include <fstream>
@ -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() {

View File

@ -53,17 +53,12 @@ template <> struct traits<tgc_c> {
static constexpr std::array<const char*, 36> reg_aliases{
{"ZERO", "RA", "SP", "GP", "TP", "T0", "T1", "T2", "S0", "S1", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "S10", "S11", "T3", "T4", "T5", "T6", "PC", "NEXT_PC", "PRIV", "DPC"}};
enum constants {MISA_VAL=0b01000000000000000001000100000100, MARCHID_VAL=0x80000003, RFS=32, INSTR_ALIGNMENT=2, XLEN=32, CSR_SIZE=4096, fence=0, fencei=1, fencevmal=2, fencevmau=3, MUL_LEN=64};
enum constants {MISA_VAL=0b01000000000000000001000100000100, MARCHID_VAL=0x80000003, XLEN=32, INSTR_ALIGNMENT=2, RFS=32, fence=0, fencei=1, fencevmal=2, fencevmau=3, CSR_SIZE=4096, MUL_LEN=64};
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,17 +71,17 @@ 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);
enum sreg_flag_e { FLAGS };
enum mem_type_e { MEM, CSR, FENCE, RES };
enum mem_type_e { MEM, FENCE, RES, CSR };
enum class opcode_e : unsigned short {
LUI = 0,
@ -129,56 +124,53 @@ template <> struct traits<tgc_c> {
FENCE = 37,
ECALL = 38,
EBREAK = 39,
URET = 40,
SRET = 41,
MRET = 42,
WFI = 43,
DRET = 44,
CSRRW = 45,
CSRRS = 46,
CSRRC = 47,
CSRRWI = 48,
CSRRSI = 49,
CSRRCI = 50,
FENCE_I = 51,
MUL = 52,
MULH = 53,
MULHSU = 54,
MULHU = 55,
DIV = 56,
DIVU = 57,
REM = 58,
REMU = 59,
CADDI4SPN = 60,
CLW = 61,
CSW = 62,
CADDI = 63,
CNOP = 64,
CJAL = 65,
CLI = 66,
CLUI = 67,
CADDI16SP = 68,
__reserved_clui = 69,
CSRLI = 70,
CSRAI = 71,
CANDI = 72,
CSUB = 73,
CXOR = 74,
COR = 75,
CAND = 76,
CJ = 77,
CBEQZ = 78,
CBNEZ = 79,
CSLLI = 80,
CLWSP = 81,
CMV = 82,
CJR = 83,
__reserved_cmv = 84,
CADD = 85,
CJALR = 86,
CEBREAK = 87,
CSWSP = 88,
DII = 89,
MRET = 40,
WFI = 41,
CSRRW = 42,
CSRRS = 43,
CSRRC = 44,
CSRRWI = 45,
CSRRSI = 46,
CSRRCI = 47,
FENCE_I = 48,
MUL = 49,
MULH = 50,
MULHSU = 51,
MULHU = 52,
DIV = 53,
DIVU = 54,
REM = 55,
REMU = 56,
CADDI4SPN = 57,
CLW = 58,
CSW = 59,
CADDI = 60,
CNOP = 61,
CJAL = 62,
CLI = 63,
CLUI = 64,
CADDI16SP = 65,
__reserved_clui = 66,
CSRLI = 67,
CSRAI = 68,
CANDI = 69,
CSUB = 70,
CXOR = 71,
COR = 72,
CAND = 73,
CJ = 74,
CBEQZ = 75,
CBNEZ = 76,
CSLLI = 77,
CLWSP = 78,
CMV = 79,
CJR = 80,
__reserved_cmv = 81,
CADD = 82,
CJALR = 83,
CEBREAK = 84,
CSWSP = 85,
DII = 86,
MAX_OPCODE
};
};
@ -197,7 +189,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 +207,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 +248,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;

View File

@ -0,0 +1,175 @@
#include "tgc_c.h"
#include <vector>
#include <array>
#include <cstdlib>
#include <algorithm>
namespace iss {
namespace arch {
namespace {
// according to
// https://stackoverflow.com/questions/8871204/count-number-of-1s-in-binary-representation
#ifdef __GCC__
constexpr size_t bit_count(uint32_t u) { return __builtin_popcount(u); }
#elif __cplusplus < 201402L
constexpr size_t uCount(uint32_t u) { return u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111); }
constexpr size_t bit_count(uint32_t u) { return ((uCount(u) + (uCount(u) >> 3)) & 030707070707) % 63; }
#else
constexpr size_t bit_count(uint32_t u) {
size_t uCount = u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111);
return ((uCount + (uCount >> 3)) & 030707070707) % 63;
}
#endif
using opcode_e = traits<tgc_c>::opcode_e;
/****************************************************************************
* start opcode definitions
****************************************************************************/
struct instruction_desriptor {
size_t length;
uint32_t value;
uint32_t mask;
opcode_e op;
};
const std::array<instruction_desriptor, 90> instr_descr = {{
/* entries are: size, valid value, valid mask, function ptr */
{32, 0b00000000000000000000000000110111, 0b00000000000000000000000001111111, opcode_e::LUI},
{32, 0b00000000000000000000000000010111, 0b00000000000000000000000001111111, opcode_e::AUIPC},
{32, 0b00000000000000000000000001101111, 0b00000000000000000000000001111111, opcode_e::JAL},
{32, 0b00000000000000000000000001100111, 0b00000000000000000111000001111111, opcode_e::JALR},
{32, 0b00000000000000000000000001100011, 0b00000000000000000111000001111111, opcode_e::BEQ},
{32, 0b00000000000000000001000001100011, 0b00000000000000000111000001111111, opcode_e::BNE},
{32, 0b00000000000000000100000001100011, 0b00000000000000000111000001111111, opcode_e::BLT},
{32, 0b00000000000000000101000001100011, 0b00000000000000000111000001111111, opcode_e::BGE},
{32, 0b00000000000000000110000001100011, 0b00000000000000000111000001111111, opcode_e::BLTU},
{32, 0b00000000000000000111000001100011, 0b00000000000000000111000001111111, opcode_e::BGEU},
{32, 0b00000000000000000000000000000011, 0b00000000000000000111000001111111, opcode_e::LB},
{32, 0b00000000000000000001000000000011, 0b00000000000000000111000001111111, opcode_e::LH},
{32, 0b00000000000000000010000000000011, 0b00000000000000000111000001111111, opcode_e::LW},
{32, 0b00000000000000000100000000000011, 0b00000000000000000111000001111111, opcode_e::LBU},
{32, 0b00000000000000000101000000000011, 0b00000000000000000111000001111111, opcode_e::LHU},
{32, 0b00000000000000000000000000100011, 0b00000000000000000111000001111111, opcode_e::SB},
{32, 0b00000000000000000001000000100011, 0b00000000000000000111000001111111, opcode_e::SH},
{32, 0b00000000000000000010000000100011, 0b00000000000000000111000001111111, opcode_e::SW},
{32, 0b00000000000000000000000000010011, 0b00000000000000000111000001111111, opcode_e::ADDI},
{32, 0b00000000000000000010000000010011, 0b00000000000000000111000001111111, opcode_e::SLTI},
{32, 0b00000000000000000011000000010011, 0b00000000000000000111000001111111, opcode_e::SLTIU},
{32, 0b00000000000000000100000000010011, 0b00000000000000000111000001111111, opcode_e::XORI},
{32, 0b00000000000000000110000000010011, 0b00000000000000000111000001111111, opcode_e::ORI},
{32, 0b00000000000000000111000000010011, 0b00000000000000000111000001111111, opcode_e::ANDI},
{32, 0b00000000000000000001000000010011, 0b11111110000000000111000001111111, opcode_e::SLLI},
{32, 0b00000000000000000101000000010011, 0b11111110000000000111000001111111, opcode_e::SRLI},
{32, 0b01000000000000000101000000010011, 0b11111110000000000111000001111111, opcode_e::SRAI},
{32, 0b00000000000000000000000000110011, 0b11111110000000000111000001111111, opcode_e::ADD},
{32, 0b01000000000000000000000000110011, 0b11111110000000000111000001111111, opcode_e::SUB},
{32, 0b00000000000000000001000000110011, 0b11111110000000000111000001111111, opcode_e::SLL},
{32, 0b00000000000000000010000000110011, 0b11111110000000000111000001111111, opcode_e::SLT},
{32, 0b00000000000000000011000000110011, 0b11111110000000000111000001111111, opcode_e::SLTU},
{32, 0b00000000000000000100000000110011, 0b11111110000000000111000001111111, opcode_e::XOR},
{32, 0b00000000000000000101000000110011, 0b11111110000000000111000001111111, opcode_e::SRL},
{32, 0b01000000000000000101000000110011, 0b11111110000000000111000001111111, opcode_e::SRA},
{32, 0b00000000000000000110000000110011, 0b11111110000000000111000001111111, opcode_e::OR},
{32, 0b00000000000000000111000000110011, 0b11111110000000000111000001111111, opcode_e::AND},
{32, 0b00000000000000000000000000001111, 0b00000000000000000111000001111111, opcode_e::FENCE},
{32, 0b00000000000000000000000001110011, 0b11111111111111111111111111111111, opcode_e::ECALL},
{32, 0b00000000000100000000000001110011, 0b11111111111111111111111111111111, opcode_e::EBREAK},
{32, 0b00000000001000000000000001110011, 0b11111111111111111111111111111111, opcode_e::URET},
{32, 0b00010000001000000000000001110011, 0b11111111111111111111111111111111, opcode_e::SRET},
{32, 0b00110000001000000000000001110011, 0b11111111111111111111111111111111, opcode_e::MRET},
{32, 0b00010000010100000000000001110011, 0b11111111111111111111111111111111, opcode_e::WFI},
{32, 0b01111011001000000000000001110011, 0b11111111111111111111111111111111, opcode_e::DRET},
{32, 0b00000000000000000001000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRW},
{32, 0b00000000000000000010000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRS},
{32, 0b00000000000000000011000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRC},
{32, 0b00000000000000000101000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRWI},
{32, 0b00000000000000000110000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRSI},
{32, 0b00000000000000000111000001110011, 0b00000000000000000111000001111111, opcode_e::CSRRCI},
{32, 0b00000000000000000001000000001111, 0b00000000000000000111000001111111, opcode_e::FENCE_I},
{32, 0b00000010000000000000000000110011, 0b11111110000000000111000001111111, opcode_e::MUL},
{32, 0b00000010000000000001000000110011, 0b11111110000000000111000001111111, opcode_e::MULH},
{32, 0b00000010000000000010000000110011, 0b11111110000000000111000001111111, opcode_e::MULHSU},
{32, 0b00000010000000000011000000110011, 0b11111110000000000111000001111111, opcode_e::MULHU},
{32, 0b00000010000000000100000000110011, 0b11111110000000000111000001111111, opcode_e::DIV},
{32, 0b00000010000000000101000000110011, 0b11111110000000000111000001111111, opcode_e::DIVU},
{32, 0b00000010000000000110000000110011, 0b11111110000000000111000001111111, opcode_e::REM},
{32, 0b00000010000000000111000000110011, 0b11111110000000000111000001111111, opcode_e::REMU},
{16, 0b0000000000000000, 0b1110000000000011, opcode_e::CADDI4SPN},
{16, 0b0100000000000000, 0b1110000000000011, opcode_e::CLW},
{16, 0b1100000000000000, 0b1110000000000011, opcode_e::CSW},
{16, 0b0000000000000001, 0b1110000000000011, opcode_e::CADDI},
{16, 0b0000000000000001, 0b1110111110000011, opcode_e::CNOP},
{16, 0b0010000000000001, 0b1110000000000011, opcode_e::CJAL},
{16, 0b0100000000000001, 0b1110000000000011, opcode_e::CLI},
{16, 0b0110000000000001, 0b1110000000000011, opcode_e::CLUI},
{16, 0b0110000100000001, 0b1110111110000011, opcode_e::CADDI16SP},
{16, 0b0110000000000001, 0b1111000001111111, opcode_e::__reserved_clui},
{16, 0b1000000000000001, 0b1111110000000011, opcode_e::CSRLI},
{16, 0b1000010000000001, 0b1111110000000011, opcode_e::CSRAI},
{16, 0b1000100000000001, 0b1110110000000011, opcode_e::CANDI},
{16, 0b1000110000000001, 0b1111110001100011, opcode_e::CSUB},
{16, 0b1000110000100001, 0b1111110001100011, opcode_e::CXOR},
{16, 0b1000110001000001, 0b1111110001100011, opcode_e::COR},
{16, 0b1000110001100001, 0b1111110001100011, opcode_e::CAND},
{16, 0b1010000000000001, 0b1110000000000011, opcode_e::CJ},
{16, 0b1100000000000001, 0b1110000000000011, opcode_e::CBEQZ},
{16, 0b1110000000000001, 0b1110000000000011, opcode_e::CBNEZ},
{16, 0b0000000000000010, 0b1111000000000011, opcode_e::CSLLI},
{16, 0b0100000000000010, 0b1110000000000011, opcode_e::CLWSP},
{16, 0b1000000000000010, 0b1111000000000011, opcode_e::CMV},
{16, 0b1000000000000010, 0b1111000001111111, opcode_e::CJR},
{16, 0b1000000000000010, 0b1111111111111111, opcode_e::__reserved_cmv},
{16, 0b1001000000000010, 0b1111000000000011, opcode_e::CADD},
{16, 0b1001000000000010, 0b1111000001111111, opcode_e::CJALR},
{16, 0b1001000000000010, 0b1111111111111111, opcode_e::CEBREAK},
{16, 0b1100000000000010, 0b1110000000000011, opcode_e::CSWSP},
{16, 0b0000000000000000, 0b1111111111111111, opcode_e::DII},
}};
}
template<>
struct instruction_decoder<tgc_c> {
using opcode_e = traits<tgc_c>::opcode_e;
using code_word_t=traits<tgc_c>::code_word_t;
struct instruction_pattern {
uint32_t value;
uint32_t mask;
opcode_e id;
};
std::array<std::vector<instruction_pattern>, 4> qlut;
template<typename T>
unsigned decode_instruction(T);
instruction_decoder() {
for (auto instr : instr_descr) {
auto quadrant = instr.value & 0x3;
qlut[quadrant].push_back(instruction_pattern{instr.value, instr.mask, instr.op});
}
for(auto& lut: qlut){
std::sort(std::begin(lut), std::end(lut), [](instruction_pattern const& a, instruction_pattern const& b){
return bit_count(a.mask) > bit_count(b.mask);
});
}
}
};
template<>
unsigned instruction_decoder<tgc_c>::decode_instruction<traits<tgc_c>::code_word_t>(traits<tgc_c>::code_word_t instr){
auto res = std::find_if(std::begin(qlut[instr&0x3]), std::end(qlut[instr&0x3]), [instr](instruction_pattern const& e){
return !((instr&e.mask) ^ e.value );
});
return static_cast<unsigned>(res!=std::end(qlut[instr&0x3])? res->id : opcode_e::MAX_OPCODE);
}
std::unique_ptr<instruction_decoder<tgc_c>> traits<tgc_c>::get_decoder(){
return std::make_unique<instruction_decoder<tgc_c>>();
}
}
}

View File

@ -4,39 +4,44 @@
#include "riscv_hart_m_p.h"
#include "tgc_c.h"
using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>;
#ifdef CORE_TGC_A
#include "riscv_hart_m_p.h"
#include <iss/arch/tgc_a.h>
using tgc_a_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_a>;
#endif
#ifdef CORE_TGC_B
#include "riscv_hart_m_p.h"
#include "tgc_b.h"
#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 "riscv_hart_m_p.h"
#include "tgc_c_xrb_nn.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 "riscv_hart_mu_p.h"
#include "tgc_d.h"
#include <iss/arch/tgc_d.h>
using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
#endif
#ifdef CORE_TGC_D_XRB_MAC
#include "riscv_hart_mu_p.h"
#include "tgc_d_xrb_mac.h"
#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 "riscv_hart_mu_p.h"
#include "tgc_d_xrb_nn.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 "riscv_hart_mu_p.h"
#include "tgc_e.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 CORE_TGC_X
#include "riscv_hart_mu_p.h"
#include "tgc_x.h"
#include <iss/arch/tgc_x.h>
using tgc_x_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_x, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N | iss::arch::FEAT_TCM)>;
#endif

View File

@ -32,14 +32,14 @@
* eyck@minres.com - initial API and implementation
******************************************************************************/
#include "iss/plugin/cycle_estimate.h"
#include "cycle_estimate.h"
#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/writer.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/ostreamwrapper.h>
#include <rapidjson/error/en.h>
#include <fstream>
@ -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);
}

View File

@ -45,7 +45,7 @@ namespace iss {
namespace plugin {
class cycle_estimate: public iss::vm_plugin {
class cycle_estimate: public vm_plugin {
BEGIN_BF_DECL(instr_desc, uint32_t)
BF_FIELD(taken, 24, 8)
BF_FIELD(not_taken, 16, 8)
@ -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 {

View File

@ -32,8 +32,8 @@
* eyck@minres.com - initial API and implementation
******************************************************************************/
#include "iss/plugin/instruction_count.h"
#include "iss/instrumentation_if.h"
#include "instruction_count.h"
#include <iss/instrumentation_if.h>
#include <iss/arch_if.h>
#include <util/logging.h>

180
src/iss/plugin/pctrace.cpp Normal file
View File

@ -0,0 +1,180 @@
#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>
#include <rapidjson/stringbuffer.h>
#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;
#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);
}
~lz4compress_steambuf() {
close();
}
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
pctrace::pctrace(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
{ }
pctrace::~pctrace() { }
bool pctrace::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;
}
void pctrace::callback(instr_info_t iinfo, const exec_info& einfo) {
auto delay = 0;
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;
bool compressed = (instr&0x3)!=0x3;
if (einfo.branch_taken) {
delay = entry.taken;
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
}
}
}

View File

@ -44,8 +44,8 @@
namespace iss {
namespace plugin {
class cov : public iss::vm_plugin {
class lz4compress_steambuf;
class pctrace : public iss::vm_plugin {
struct instr_delay {
std::string instr_name;
size_t size;
@ -67,17 +67,17 @@ class cov : public iss::vm_plugin {
public:
cov(const cov &) = delete;
pctrace(const pctrace &) = delete;
cov(const cov &&) = delete;
pctrace(const pctrace &&) = delete;
cov(std::string const &);
pctrace(std::string const &);
virtual ~cov();
virtual ~pctrace();
cov &operator=(const cov &) = delete;
pctrace &operator=(const pctrace &) = delete;
cov &operator=(const cov &&) = delete;
pctrace &operator=(const pctrace &&) = delete;
bool registration(const char *const version, vm_if &arch) override;
@ -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};
};
}
}

View File

@ -1,236 +1,241 @@
/*******************************************************************************
* 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.
*
*******************************************************************************/
#include <iostream>
#include <iss/factory.h>
#include <boost/lexical_cast.hpp>
#include <boost/program_options.hpp>
#include <iss/arch/tgc_mapper.h>
#ifdef WITH_LLVM
#include <iss/llvm/jit_helper.h>
#endif
#include <iss/log_categories.h>
#include <iss/plugin/cycle_estimate.h>
#include <iss/plugin/instruction_count.h>
#include <iss/plugin/pctrace.h>
#include <iss/plugin/loader.h>
#if defined(HAS_LUA)
#include <iss/plugin/lua.h>
#endif
namespace po = boost::program_options;
int main(int argc, char *argv[]) {
/*
* Define and parse the program options
*/
po::variables_map clim;
po::options_description desc("Options");
// clang-format off
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.")
("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")
("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")
("isa", po::value<std::string>()->default_value("tgc_c"), "isa to use for simulation");
// clang-format on
auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
try {
po::store(parsed, clim); // can throw
// --help option
if (clim.count("help")) {
std::cout << "DBT-RISE-RiscV simulator for RISC-V" << std::endl << desc << std::endl;
return 0;
}
po::notify(clim); // throws on error, so do after help in case
} catch (po::error &e) {
// there are problems
std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
std::cerr << desc << std::endl;
return 1;
}
std::vector<std::string> args = collect_unrecognized(parsed.options, po::include_positional);
LOGGER(DEFAULT)::print_time() = false;
LOGGER(connection)::print_time() = false;
if (clim.count("verbose")) {
auto l = logging::as_log_level(clim["verbose"].as<int>());
LOGGER(DEFAULT)::reporting_level() = l;
LOGGER(connection)::reporting_level() = l;
}
if (clim.count("logfile")) {
// configure the connection logger
auto f = fopen(clim["logfile"].as<std::string>().c_str(), "w");
LOG_OUTPUT(DEFAULT)::stream() = f;
LOG_OUTPUT(connection)::stream() = f;
}
std::vector<iss::vm_plugin *> plugin_list;
auto res = 0;
try {
#ifdef WITH_LLVM
// application code comes here //
iss::init_jit_debug(argc, argv);
#endif
bool dump = clim.count("dump-ir");
// instantiate the simulator
iss::vm_ptr vm{nullptr};
iss::cpu_ptr cpu{nullptr};
std::string isa_opt(clim["isa"].as<std::string>());
if (isa_opt == "tgc_c") {
std::tie(cpu, vm) =
iss::create_cpu<tgc_c_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
} else
#ifdef CORE_TGC_B
if (isa_opt == "tgc_b") {
std::tie(cpu, vm) =
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) =
iss::create_cpu<tgc_d_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
} else
#endif
#ifdef CORE_TGC_D_XRB_MAC
if (isa_opt == "tgc_d_xrb_mac") {
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
{
/*******************************************************************************
* 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.
*
*******************************************************************************/
#include <iostream>
#include "iss/factory.h"
#include <boost/lexical_cast.hpp>
#include <boost/program_options.hpp>
#include "iss/arch/tgc_mapper.h"
#ifdef WITH_LLVM
#include <iss/llvm/jit_helper.h>
#endif
#include <iss/log_categories.h>
#include "iss/plugin/cycle_estimate.h"
#include "iss/plugin/instruction_count.h"
#include "iss/plugin/pctrace.h"
#ifndef WIN32
#include <iss/plugin/loader.h>
#endif
#if defined(HAS_LUA)
#include <iss/plugin/lua.h>
#endif
namespace po = boost::program_options;
int main(int argc, char *argv[]) {
/*
* Define and parse the program options
*/
po::variables_map clim;
po::options_description desc("Options");
// clang-format off
desc.add_options()
("help,h", "Print help message")
("verbose,v", po::value<int>()->implicit_value(0), "Sets logging verbosity")
("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,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")
("isa", po::value<std::string>()->default_value("tgc_c"), "isa to use for simulation");
// clang-format on
auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
try {
po::store(parsed, clim); // can throw
// --help option
if (clim.count("help")) {
std::cout << "DBT-RISE-RiscV simulator for RISC-V" << std::endl << desc << std::endl;
return 0;
}
po::notify(clim); // throws on error, so do after help in case
} catch (po::error &e) {
// there are problems
std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
std::cerr << desc << std::endl;
return 1;
}
std::vector<std::string> args = collect_unrecognized(parsed.options, po::include_positional);
LOGGER(DEFAULT)::print_time() = false;
LOGGER(connection)::print_time() = false;
if (clim.count("verbose")) {
auto l = logging::as_log_level(clim["verbose"].as<int>());
LOGGER(DEFAULT)::reporting_level() = l;
LOGGER(connection)::reporting_level() = l;
}
if (clim.count("logfile")) {
// configure the connection logger
auto f = fopen(clim["logfile"].as<std::string>().c_str(), "w");
LOG_OUTPUT(DEFAULT)::stream() = f;
LOG_OUTPUT(connection)::stream() = f;
}
std::vector<iss::vm_plugin *> plugin_list;
auto res = 0;
try {
#ifdef WITH_LLVM
// application code comes here //
iss::init_jit_debug(argc, argv);
#endif
bool dump = clim.count("dump-ir");
// instantiate the simulator
iss::vm_ptr vm{nullptr};
iss::cpu_ptr cpu{nullptr};
std::string isa_opt(clim["isa"].as<std::string>());
if (isa_opt == "tgc_c") {
std::tie(cpu, vm) =
iss::create_cpu<tgc_c_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
} else
#ifdef CORE_TGC_B
if (isa_opt == "tgc_b") {
std::tie(cpu, vm) =
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) =
iss::create_cpu<tgc_d_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
} else
#endif
#ifdef CORE_TGC_D_XRB_MAC
if (isa_opt == "tgc_d_xrb_mac") {
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': " << isa_opt << std::endl;
return 127;
}
if (clim.count("plugin")) {
for (std::string const& opt_val : clim["plugin"].as<std::vector<std::string>>()) {
std::string plugin_name=opt_val;
std::string filename{"cycles.txt"};
std::size_t found = opt_val.find('=');
if (found != std::string::npos) {
plugin_name = opt_val.substr(0, found);
filename = opt_val.substr(found + 1, opt_val.size());
}
if (plugin_name == "ic") {
auto *ic_plugin = new iss::plugin::instruction_count(filename);
vm->register_plugin(*ic_plugin);
plugin_list.push_back(ic_plugin);
} else if (plugin_name == "ce") {
auto *ce_plugin = new iss::plugin::cycle_estimate(filename);
vm->register_plugin(*ce_plugin);
plugin_list.push_back(ce_plugin);
} else if (plugin_name == "pctrace") {
auto *plugin = new iss::plugin::cov(filename);
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"}});
auto* plugin = l.call_function<iss::vm_plugin*>("initPlugin", a.size(), a.data());
if(plugin){
vm->register_plugin(*plugin);
plugin_list.push_back(plugin);
} else {
return 127;
}
if (clim.count("plugin")) {
for (std::string const& opt_val : clim["plugin"].as<std::vector<std::string>>()) {
std::string plugin_name=opt_val;
std::string filename{"cycles.txt"};
std::size_t found = opt_val.find('=');
if (found != std::string::npos) {
plugin_name = opt_val.substr(0, found);
filename = opt_val.substr(found + 1, opt_val.size());
}
if (plugin_name == "ic") {
auto *ic_plugin = new iss::plugin::instruction_count(filename);
vm->register_plugin(*ic_plugin);
plugin_list.push_back(ic_plugin);
} else if (plugin_name == "ce") {
auto *ce_plugin = new iss::plugin::cycle_estimate(filename);
vm->register_plugin(*ce_plugin);
plugin_list.push_back(ce_plugin);
} else if (plugin_name == "pctrace") {
auto *plugin = new iss::plugin::pctrace(filename);
vm->register_plugin(*plugin);
plugin_list.push_back(plugin);
} else {
#ifndef WIN32
std::array<char const*, 1> a{{filename.c_str()}};
iss::plugin::loader l(plugin_name, {{"initPlugin"}});
auto* plugin = l.call_function<iss::vm_plugin*>("initPlugin", a.size(), a.data());
if(plugin){
vm->register_plugin(*plugin);
plugin_list.push_back(plugin);
} else
#endif
{
LOG(ERR) << "Unknown plugin name: " << plugin_name << ", valid names are 'ce', 'ic'" << std::endl;
return 127;
}
}
}
}
if (clim.count("disass")) {
vm->setDisassEnabled(true);
LOGGER(disass)::reporting_level() = logging::INFO;
LOGGER(disass)::print_time() = false;
auto file_name = clim["disass"].as<std::string>();
if (file_name.length() > 0) {
LOG_OUTPUT(disass)::stream() = fopen(file_name.c_str(), "w");
LOGGER(disass)::print_severity() = false;
}
}
uint64_t start_address = 0;
if (clim.count("mem"))
vm->get_arch()->load_file(clim["mem"].as<std::string>());
if (clim.count("elf"))
for (std::string input : clim["elf"].as<std::vector<std::string>>()) {
auto start_addr = vm->get_arch()->load_file(input);
if (start_addr.second) start_address = start_addr.first;
}
for (std::string input : args) {
auto start_addr = vm->get_arch()->load_file(input); // treat remaining arguments as elf files
if (start_addr.second) start_address = start_addr.first;
}
if (clim.count("reset")) {
auto str = clim["reset"].as<std::string>();
start_address = str.find("0x") == 0 ? std::stoull(str.substr(2), nullptr, 16) : std::stoull(str, nullptr, 10);
}
vm->reset(start_address);
auto cycles = clim["instructions"].as<uint64_t>();
res = vm->start(cycles, dump);
} catch (std::exception &e) {
return 127;
}
}
}
}
if (clim.count("disass")) {
vm->setDisassEnabled(true);
LOGGER(disass)::reporting_level() = logging::INFO;
LOGGER(disass)::print_time() = false;
auto file_name = clim["disass"].as<std::string>();
if (file_name.length() > 0) {
LOG_OUTPUT(disass)::stream() = fopen(file_name.c_str(), "w");
LOGGER(disass)::print_severity() = false;
}
}
uint64_t start_address = 0;
if (clim.count("mem"))
vm->get_arch()->load_file(clim["mem"].as<std::string>());
if (clim.count("elf"))
for (std::string input : clim["elf"].as<std::vector<std::string>>()) {
auto start_addr = vm->get_arch()->load_file(input);
if (start_addr.second) start_address = start_addr.first;
}
for (std::string input : args) {
auto start_addr = vm->get_arch()->load_file(input); // treat remaining arguments as elf files
if (start_addr.second) start_address = start_addr.first;
}
if (clim.count("reset")) {
auto str = clim["reset"].as<std::string>();
start_address = str.find("0x") == 0 ? std::stoull(str.substr(2), nullptr, 16) : std::stoull(str, nullptr, 10);
}
vm->reset(start_address);
auto cycles = clim["instructions"].as<uint64_t>();
res = vm->start(cycles, dump);
} catch (std::exception &e) {
LOG(ERR) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit"
<< std::endl;
res = 2;
}
// cleanup to let plugins report of needed
for (auto *p : plugin_list) {
delete p;
}
return res;
}
<< std::endl;
res = 2;
}
// cleanup to let plugins report of needed
for (auto *p : plugin_list) {
delete p;
}
return res;
}

View File

@ -1,133 +0,0 @@
#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

@ -30,15 +30,17 @@
*
*******************************************************************************/
// clang-format off
#include <iss/debugger/gdb_session.h>
#include <iss/debugger/encoderdecoder.h>
#include <iss/debugger/server.h>
#include <iss/debugger/target_adapter_if.h>
#include <iss/iss.h>
// clang-format off
#include <iss/debugger/gdb_session.h>
#include <iss/debugger/encoderdecoder.h>
#include <iss/debugger/server.h>
#include <iss/debugger/target_adapter_if.h>
#include <iss/iss.h>
#include <iss/vm_types.h>
#include <iss/plugin/loader.h>
#include <sysc/core_complex.h>
#ifndef WIN32
#include <iss/plugin/loader.h>
#endif
#include "core_complex.h"
#include <iss/arch/tgc_mapper.h>
#include <scc/report.h>
#include <util/ities.h>
@ -49,7 +51,7 @@
#include <iss/plugin/instruction_count.h>
#include <iss/plugin/pctrace.h>
// clang-format on
// clang-format on
#define STR(X) #X
#define CREATE_CORE(CN) \
@ -68,12 +70,12 @@ using namespace scv_tr;
#define GET_PROP_VALUE(P) P.getValue()
#endif
#ifdef _MSC_VER
// not #if defined(_WIN32) || defined(_WIN64) because we have strncasecmp in mingw
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#endif
#ifdef _MSC_VER
// not #if defined(_WIN32) || defined(_WIN64) because we have strncasecmp in mingw
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#endif
namespace sysc {
namespace tgfs {
using namespace std;
@ -105,7 +107,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 +117,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 +177,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 +206,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:
@ -296,7 +298,7 @@ public:
CREATE_CORE(tgc_d_xrb_nn)
#endif
{
LOG(ERR) << "Illegal argument value for core type: " << type << std::endl;
LOG(ERR) << "Illegal argument value for core type: " << type << std::endl;
}
auto *srv = debugger::server<debugger::gdb_session>::get();
if (srv) tgt_adapter = srv->get_target();
@ -405,10 +407,11 @@ void core_complex::before_end_of_elaboration() {
cpu->vm->register_plugin(*plugin);
plugin_list.push_back(plugin);
} else if (plugin_name == "pctrace") {
auto *plugin = new iss::plugin::cov(filename);
auto *plugin = new iss::plugin::pctrace(filename);
cpu->vm->register_plugin(*plugin);
plugin_list.push_back(plugin);
} else {
#ifndef WIN32
std::array<char const*, 1> a{{filename.c_str()}};
iss::plugin::loader l(plugin_name, {{"initPlugin"}});
auto* plugin = l.call_function<iss::vm_plugin*>("initPlugin", a.size(), a.data());
@ -416,6 +419,7 @@ void core_complex::before_end_of_elaboration() {
cpu->vm->register_plugin(*plugin);
plugin_list.push_back(plugin);
} else
#endif
SCCERR(SCMOD) << "Unknown plugin '" << plugin_name << "' or plugin not found";
}
}

View File

@ -1 +0,0 @@
/vm_tgc_*.cpp

File diff suppressed because it is too large Load Diff

View File

@ -30,7 +30,7 @@
*
*******************************************************************************/
#include <iss/arch/tgf_c.h>
#include <iss/arch/tgc_c.h>
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/debugger/gdb_session.h>
#include <iss/debugger/server.h>
@ -52,7 +52,7 @@ namespace fp_impl {
void add_fp_functions_2_module(::llvm::Module *, unsigned, unsigned);
}
namespace tgf_c {
namespace tgc_c {
using namespace ::llvm;
using namespace iss::arch;
using namespace iss::debugger;
@ -4151,11 +4151,11 @@ template <typename ARCH> inline void vm_impl<ARCH>::gen_trap_check(BasicBlock *b
bb, this->trap_blk, 1);
}
} // namespace tgf_c
} // namespace tgc_c
template <>
std::unique_ptr<vm_if> create<arch::tgf_c>(arch::tgf_c *core, unsigned short port, bool dump) {
auto ret = new tgf_c::vm_impl<arch::tgf_c>(*core, dump);
std::unique_ptr<vm_if> create<arch::tgc_c>(arch::tgc_c *core, unsigned short port, bool dump) {
auto ret = new tgc_c::vm_impl<arch::tgc_c>(*core, dump);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
return std::unique_ptr<vm_if>(ret);
}

File diff suppressed because it is too large Load Diff

View File

@ -30,7 +30,7 @@
*
*******************************************************************************/
#include <iss/arch/tgf_c.h>
#include <iss/arch/tgc_c.h>
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/debugger/gdb_session.h>
#include <iss/debugger/server.h>
@ -49,7 +49,7 @@
namespace iss {
namespace tcc {
namespace tgf_c {
namespace tgc_c {
using namespace iss::arch;
using namespace iss::debugger;
@ -3251,8 +3251,8 @@ template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(tu_builder& tu) {
} // namespace mnrv32
template <>
std::unique_ptr<vm_if> create<arch::tgf_c>(arch::tgf_c *core, unsigned short port, bool dump) {
auto ret = new tgf_c::vm_impl<arch::tgf_c>(*core, dump);
std::unique_ptr<vm_if> create<arch::tgc_c>(arch::tgc_c *core, unsigned short port, bool dump) {
auto ret = new tgc_c::vm_impl<arch::tgc_c>(*core, dump);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
return std::unique_ptr<vm_if>(ret);
}

File diff suppressed because it is too large Load Diff