1 Commits

Author SHA1 Message Date
d5fa47ef7f Merge branch 'develop' 2021-11-11 19:34:21 +01:00
30 changed files with 4775 additions and 3503 deletions

1
.gitignore vendored
View File

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

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "gen_input/CoreDSL-Instruction-Set-Description"]
path = gen_input/CoreDSL-Instruction-Set-Description
url = ../CoreDSL-Instruction-Set-Description.git

View File

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

View File

@ -1,2 +1 @@
/src-gen/
/CoreDSL-Instruction-Set-Description

14
gen_input/TGC_B.core_desc Normal file
View File

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

View File

@ -1,6 +1,6 @@
import "RV32I.core_desc"
import "RVM.core_desc"
import "RVC.core_desc"
import "CoreDSL-Instruction-Set-Description/RV32I.core_desc"
import "CoreDSL-Instruction-Set-Description/RVM.core_desc"
import "CoreDSL-Instruction-Set-Description/RVC.core_desc"
Core TGC_C provides RV32I, Zicsr, Zifencei, RV32M, RV32IC {
architectural_state {

13
gen_input/TGC_D.core_desc Normal file
View File

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

View File

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

View File

@ -0,0 +1,133 @@
import "CoreDSL-Instruction-Set-Description/RISCVBase.core_desc"
import "CoreDSL-Instruction-Set-Description/RV32I.core_desc"
import "CoreDSL-Instruction-Set-Description/RVM.core_desc"
import "CoreDSL-Instruction-Set-Description/RVC.core_desc"
InstructionSet X_RB_NN extends RISCVBase {
instructions {
// signed saturate with pre-shift
SSAT {
// instruction format: R-type
// opcode space: custom-1 (inst[6:2] = 01010)
// opcode = 0b0101011, func3 = 0b000, func7 = <bit position to saturate to>
encoding: sat_bit_pos[6:0] :: rs2[4:0] :: rs1[4:0] :: 0b000 :: rd[4:0] :: 0b0101011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}, {name(sat_bit_pos)}";
behavior: {
signed<XLEN> val_s = (signed<XLEN>)X[rs1];
unsigned<XLEN> pre_shift = (unsigned<XLEN>)X[rs2];
unsigned<XLEN> sat_limit;
signed<XLEN> upper_limit;
signed<XLEN> lower_limit;
if((rd != 0) && (sat_bit_pos > 0) && (sat_bit_pos <= 32) && (pre_shift < 32)) {
sat_limit = (unsigned<XLEN>)(1 << (sat_bit_pos - 1));
upper_limit = (signed)sat_limit - 1;
lower_limit = (signed)sat_limit * (-1);
// important: arithmetical shift right
val_s = val_s >> pre_shift;
X[rd] = (val_s > upper_limit) ? (upper_limit) : ( (val_s < lower_limit) ? (lower_limit) : (val_s) );
}
}
}
// custom packed dot product with accumulation (4x8bit)
PDOT8 {
// instruction format: R-type
// opcode space: custom-1 (inst[6:2] = 01010)
// opcode = 0b0101011, func3 = 0b001, func7 = 0b0000000
encoding: 0b0000000 :: rs2[4:0] :: rs1[4:0] :: 0b001 :: rd[4:0] :: 0b0101011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
behavior: {
signed<8> op1_0 = (signed<8>)X[rs1][ 7: 0];
signed<8> op1_1 = (signed<8>)X[rs1][15: 8];
signed<8> op1_2 = (signed<8>)X[rs1][23:16];
signed<8> op1_3 = (signed<8>)X[rs1][31:24];
signed<8> op2_0 = (signed<8>)X[rs2][ 7: 0];
signed<8> op2_1 = (signed<8>)X[rs2][15: 8];
signed<8> op2_2 = (signed<8>)X[rs2][23:16];
signed<8> op2_3 = (signed<8>)X[rs2][31:24];
signed<XLEN> op3 = (signed<XLEN>)X[rd];
signed<16> mul0 = op1_0 * op2_0;
signed<16> mul1 = op1_1 * op2_1;
signed<16> mul2 = op1_2 * op2_2;
signed<16> mul3 = op1_3 * op2_3;
signed<19> sum_tmp = mul0 + mul1 + mul2 + mul3;
signed<33> result = op3 + sum_tmp;
if(rd != 0) X[rd] = result[31:0];
}
}
// standard signed multiply accumulate with 32 bit operands and 32 bit result
MAC {
// instruction format: R-type
// opcode space: custom-1 (inst[6:2] = 01010)
// opcode = 0b0101011, func3 = 0b010, func7 = 0b0000000
encoding: 0b0000000 :: rs2[4:0] :: rs1[4:0] :: 0b010 :: rd[4:0] :: 0b0101011;
args_disass:"{name(rd)}, {name(rs1)}, {name(rs2)}";
behavior: {
signed<65> result = (signed)X[rs1] * (signed)X[rs2] + (signed)X[rd];
if(rd != 0) X[rd] = result[31:0];
}
}
// WARNING: The following two HW loop instructions are not fully specified or implemented. The idea is to design the HW loops identical to the RI5CY core (current naming: CV32E40P)
// See "Short Hardware Loop Setup Instructions" from RI5CY specification document from April 2019, revision 4.0: https://www.pulp-platform.org/docs/ri5cy_user_manual.pdf -> page 38, chapter 14.2
// Specific CSRs are introduced to support the HW loops (see page 17, chapter 7).
// lp.setup HW loop (Short Hardware Loop Setup Instruction)
LOOP {
// instruction format: I-type
// opcode space: custom-3 (inst[6:2] = 11110)
// opcode = 0b1111011, func3 = 0b100
// uimmL[11:0] src1 100 0000 L 111 1011 -> lp.setup L,rs1, uimmL
encoding: imm[11:0] :: rs1[4:0] :: 0b100 :: 0b0000 :: L[0:0] :: 0b1111011;
args_disass:"{name(L)}, {name(rs1)}, {imm}";
behavior: {
// L: loop level (two loop levels would be sufficient); L=0 has higher priority and is considered as the inner loop.
/*
lpstart[L] = PC + 4;
lpend[L] = PC + ((unsigned<12>)imm << 1);
lpcount[L] = rs1;
*/
}
}
// lp.setupi HW loop (Short Hardware Loop Setup Instruction with immediate value for loop count)
LOOPI {
// instruction format: I-type
// opcode space: custom-3 (inst[6:2] = 11110)
// opcode = 0b1111011, func3 = 0b101
// uimmL[11:0] uimmS[4:0] 101 0000 L 111 1011 -> lp.setupi L, uimmS, uimmL
encoding: imm2[11:0] :: imm1[4:0] :: 0b101 :: 0b0000 :: L[0:0] :: 0b1111011;
args_disass:"{name(L)}, {imm1}, {imm2}";
behavior: {
// L: loop level (two loop levels would be sufficient); L=0 has higher priority and is considered as the inner loop.
/*
lpstart[L] = PC + 4;
lpend[L] = PC + ((unsigned<5>)imm1 << 1);
lpcount[L] = (unsigned<12>)imm2;
*/
}
}
}
}
Core TGC_D_XRB_NN provides RV32I, Zicsr, Zifencei, RV32M, RV32IC, X_RB_NN {
architectural_state {
XLEN=32;
// definitions for the architecture wrapper
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
unsigned MISA_VAL = 0b01000000100100000011000100000100;
unsigned MARCHID_VAL = 0x80000004;
}
}

View File

@ -33,7 +33,7 @@
def getRegisterSizes(){
def regs = registers.collect{it.size}
regs[-1]=64 // correct for NEXT_PC
//regs+=[32, 32, 64, 64, 64, 32] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION
regs+=[32, 32, 64, 64, 64] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET
return regs
}
%>
@ -51,7 +51,9 @@ 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()}() = default;
${coreDef.name.toLowerCase()}::${coreDef.name.toLowerCase()}() {
reg.icount = 0;
}
${coreDef.name.toLowerCase()}::~${coreDef.name.toLowerCase()}() = default;
@ -62,8 +64,8 @@ void ${coreDef.name.toLowerCase()}::reset(uint64_t address) {
reg.PC=address;
reg.NEXT_PC=reg.PC;
reg.PRIV=0x3;
trap_state=0;
icount=0;
reg.trap_state=0;
reg.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, 32] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION
regs+=[32,32, 64, 64, 64] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET
return regs
}
def getRegisterOffsets(){
@ -91,7 +91,12 @@ 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
${registers.collect{it.name}.join(', ')}, NUM_REGS,
TRAP_STATE=NUM_REGS,
PENDING_TRAP,
ICOUNT,
CYCLE,
INSTRET
};
using reg_t = uint${addrDataWidth}_t;
@ -136,7 +141,7 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
uint8_t* get_regs_base_ptr() override;
inline uint64_t get_icount() { return icount; }
inline uint64_t get_icount() { return reg.icount; }
inline bool should_stop() { return interrupt_sim; }
@ -154,22 +159,21 @@ 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 last_branch; }
inline uint32_t get_last_branch() { return reg.last_branch; }
protected:
#pragma pack(push, 1)
struct ${coreDef.name}_regs {<%
registers.each { reg -> if(reg.size>0) {%>
uint${byteSize(reg.size)}_t ${reg.name} = 0;<%
}}%>
uint32_t trap_state = 0, pending_trap = 0;
uint64_t icount = 0;
uint64_t cycle = 0;
uint64_t instret = 0;
uint32_t last_branch;
} reg;
#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

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

View File

@ -45,8 +45,6 @@ def nativeTypeSize(int size){
#include <iss/interp/vm_base.h>
#include <util/logging.h>
#include <sstream>
#include <boost/coroutine2/all.hpp>
#include <functional>
#ifndef FMT_HEADER_ONLY
#define FMT_HEADER_ONLY
@ -61,7 +59,6 @@ namespace interp {
namespace ${coreDef.name.toLowerCase()} {
using namespace iss::arch;
using namespace iss::debugger;
using namespace std::placeholders;
template <typename ARCH> class vm_impl : public iss::interp::vm_base<ARCH> {
public:
@ -94,7 +91,7 @@ protected:
inline const char *name(size_t index){return traits::reg_aliases.at(index);}
typename arch::traits<ARCH>::opcode_e decode_inst_id(code_word_t instr);
compile_func decode_inst(code_word_t instr) ;
virt_addr_t execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit) override;
// some compile time constants
@ -114,14 +111,14 @@ protected:
struct instruction_pattern {
uint32_t value;
uint32_t mask;
typename arch::traits<ARCH>::opcode_e id;
compile_func opc;
};
std::array<std::vector<instruction_pattern>, 4> qlut;
inline void raise(uint16_t trap_id, uint16_t cause){
auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id;
this->core.trap_state = trap_val;
this->template get_reg<uint32_t>(traits::TRAP_STATE) = trap_val;
this->template get_reg<uint32_t>(traits::NEXT_PC) = std::numeric_limits<uint32_t>::max();
}
@ -133,47 +130,43 @@ protected:
this->core.wait_until(type);
}
using yield_t = boost::coroutines2::coroutine<void>::push_type;
using coro_t = boost::coroutines2::coroutine<void>::pull_type;
std::vector<coro_t> spawn_blocks;
template<typename T>
T& pc_assign(T& val){super::ex_info.branch_taken=true; return val;}
inline uint8_t readSpace1(typename super::mem_type_e space, uint64_t addr){
auto ret = super::template read_mem<uint8_t>(space, addr);
if(this->core.trap_state) throw 0;
if(this->template get_reg<uint32_t>(traits::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->core.trap_state) throw 0;
if(this->template get_reg<uint32_t>(traits::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->core.trap_state) throw 0;
if(this->template get_reg<uint32_t>(traits::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->core.trap_state) throw 0;
if(this->template get_reg<uint32_t>(traits::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->core.trap_state) throw 0;
if(this->template get_reg<uint32_t>(traits::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->core.trap_state) throw 0;
if(this->template get_reg<uint32_t>(traits::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->core.trap_state) throw 0;
if(this->template get_reg<uint32_t>(traits::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->core.trap_state) throw 0;
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
}
template<unsigned W, typename U, typename S = typename std::make_signed<U>::type>
inline S sext(U from) {
@ -181,18 +174,7 @@ protected:
auto sign_mask = 1ULL<<(W-1);
return (from & mask) | ((from & sign_mask) ? ~mask : 0);
}
inline void process_spawn_blocks() {
for(auto it = std::begin(spawn_blocks); it!=std::end(spawn_blocks);)
if(*it){
(*it)();
++it;
} else
spawn_blocks.erase(it);
}
<%functions.each{ it.eachLine { %>
${it}<%}%>
<%}%>
private:
/****************************************************************************
* start opcode definitions
@ -201,13 +183,74 @@ private:
size_t length;
uint32_t value;
uint32_t mask;
typename arch::traits<ARCH>::opcode_e op;
compile_func op;
};
const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
{${instr.length}, ${instr.encoding}, ${instr.mask}, arch::traits<ARCH>::opcode_e::${instr.instruction.name}},<%}%>
/* instruction ${instr.instruction.name} */
{${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
}};
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
/* instruction ${idx}: ${instr.name} */
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr){
// pre execution stuff
auto* PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
auto NEXT_PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
*PC=*NEXT_PC;
auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]);
*trap_state = *reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PENDING_TRAP]);
if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, ${idx});
<%instr.fields.eachLine{%>${it}
<%}%>if(this->disass_enabled){
/* 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(...){}
// post execution stuff
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, ${idx});
// trap check
if(*trap_state!=0){
super::core.enter_trap(*trap_state, pc.val, instr);
} else {
(*reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::ICOUNT]))++;
(*reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::INSTRET]))++;
}
(*reinterpret_cast<uint64_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::CYCLE]))++;
pc.val=*NEXT_PC;
return pc;
}
<%}%>
/****************************************************************************
* end opcode definitions
****************************************************************************/
compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr) {
this->do_sync(PRE_SYNC, static_cast<unsigned>(arch::traits<ARCH>::opcode_e::MAX_OPCODE));
uint32_t* PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
uint32_t* NEXT_PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
*NEXT_PC = *PC + ((instr & 3) == 3 ? 4 : 2);
raise(0, 2);
// post execution stuff
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, static_cast<unsigned>(arch::traits<ARCH>::opcode_e::MAX_OPCODE));
auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]);
// trap check
if(*trap_state!=0){
super::core.enter_trap(*trap_state, pc.val, instr);
}
pc.val=*NEXT_PC;
return pc;
}
//static constexpr typename traits::addr_t upper_bits = ~traits::PGMASK;
iss::status fetch_ins(virt_addr_t pc, uint8_t * data){
@ -247,7 +290,6 @@ constexpr size_t bit_count(uint32_t u) {
template <typename ARCH>
vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
: vm_base<ARCH>(core, core_id, cluster_id) {
unsigned id=0;
for (auto instr : instr_descr) {
auto quadrant = instr.value & 0x3;
qlut[quadrant].push_back(instruction_pattern{instr.value, instr.mask, instr.op});
@ -268,80 +310,37 @@ inline bool is_jump_to_self_enabled(finish_cond_e cond){
}
template <typename ARCH>
typename arch::traits<ARCH>::opcode_e vm_impl<ARCH>::decode_inst_id(code_word_t instr){
typename vm_impl<ARCH>::compile_func vm_impl<ARCH>::decode_inst(code_word_t instr){
for(auto& e: qlut[instr&0x3]){
if(!((instr&e.mask) ^ e.value )) return e.id;
if(!((instr&e.mask) ^ e.value )) return e.opc;
}
return arch::traits<ARCH>::opcode_e::MAX_OPCODE;
return &this_class::illegal_intruction;
}
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){
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 = 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);
code_word_t insn = 0;
auto *const data = (uint8_t *)&insn;
auto pc=start;
while(!this->core.should_stop() &&
!(is_count_limit_enabled(cond) && this->core.get_icount() >= icount_limit)){
if(fetch_ins(pc, data)!=iss::Ok){
auto res = fetch_ins(pc, data);
if(res!=iss::Ok){
this->do_sync(POST_SYNC, std::numeric_limits<unsigned>::max());
pc.val = super::core.enter_trap(std::numeric_limits<uint64_t>::max(), pc.val, 0);
} else {
if (is_jump_to_self_enabled(cond) &&
(instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
auto inst_id = decode_inst_id(instr);
// pre execution stuff
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
<%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);
}
}
// post execution stuff
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);
} else {
icount++;
instret++;
}
cycle++;
pc.val=*NEXT_PC;
this->core.reg.PC = this->core.reg.NEXT_PC;
this->core.trap_state = this->core.pending_trap;
(insn == 0x0000006f || (insn&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
auto f = decode_inst(insn);
auto old_pc = pc.val;
pc = (this->*f)(pc, insn);
}
}
return pc;
}
}
} // namespace mnrv32
template <>
std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreDef.name.toLowerCase()} *core, unsigned short port, bool dump) {

View File

@ -1,100 +0,0 @@
/*******************************************************************************
* Copyright (C) 2022 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Contributors:
* eyck@minres.com - initial implementation
******************************************************************************/
#ifndef _RISCV_HART_M_P_HWL_H
#define _RISCV_HART_M_P_HWL_H
#include <iss/vm_types.h>
namespace iss {
namespace arch {
template <typename BASE> class hwl : public BASE {
public:
using base_class = BASE;
using this_class = hwl<BASE>;
using reg_t = typename BASE::reg_t;
hwl();
virtual ~hwl() = default;
protected:
iss::status read_custom_csr_reg(unsigned addr, reg_t &val) override;
iss::status write_custom_csr_reg(unsigned addr, reg_t val) override;
};
template<typename BASE>
inline hwl<BASE>::hwl() {
for (unsigned addr = 0x800; addr < 0x803; ++addr){
this->register_custom_csr_rd(addr);
this->register_custom_csr_wr(addr);
}
for (unsigned addr = 0x804; addr < 0x807; ++addr){
this->register_custom_csr_rd(addr);
this->register_custom_csr_wr(addr);
}
}
template<typename BASE>
inline iss::status iss::arch::hwl<BASE>::read_custom_csr_reg(unsigned addr, reg_t &val) {
switch(addr){
case 0x800: val = this->reg.lpstart0; break;
case 0x801: val = this->reg.lpend0; break;
case 0x802: val = this->reg.lpcount0; break;
case 0x804: val = this->reg.lpstart1; break;
case 0x805: val = this->reg.lpend1; break;
case 0x806: val = this->reg.lpcount1; break;
}
return iss::Ok;
}
template<typename BASE>
inline iss::status iss::arch::hwl<BASE>::write_custom_csr_reg(unsigned addr, reg_t val) {
switch(addr){
case 0x800: this->reg.lpstart0 = val; break;
case 0x801: this->reg.lpend0 = val; break;
case 0x802: this->reg.lpcount0 = val; break;
case 0x804: this->reg.lpstart1 = val; break;
case 0x805: this->reg.lpend1 = val; break;
case 0x806: this->reg.lpcount1 = val; break;
}
return iss::Ok;
}
} // namespace arch
} // namespace iss
#endif /* _RISCV_HART_M_P_H */

View File

@ -43,7 +43,7 @@ namespace arch {
enum { tohost_dflt = 0xF0001000, fromhost_dflt = 0xF0001040 };
enum features_e{FEAT_NONE, FEAT_PMP=1, FEAT_EXT_N=2, FEAT_CLIC=4, FEAT_DEBUG=8, FEAT_TCM=16};
enum features_e{FEAT_NONE, FEAT_PMP=1, FEAT_EXT_N=2, FEAT_CLIC=4, FEAT_DEBUG=8};
enum riscv_csr {
/* user-level CSR */
@ -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, PRIV_D = 4};
enum { PRIV_U = 0, PRIV_S = 1, PRIV_M = 3 };
enum {
ISA_A = 1,
@ -214,14 +214,6 @@ struct vm_info {
bool is_active() { return levels; }
};
struct feature_config {
uint64_t clic_base{0xc0000000};
unsigned clic_num_irq{16};
unsigned clic_num_trigger{0};
uint64_t tcm_base{0x10000000};
uint64_t tcm_size{0x8000};
};
class trap_load_access_fault : public trap_access {
public:
trap_load_access_fault(uint64_t badaddr)
@ -247,49 +239,6 @@ public:
trap_store_page_fault(uint64_t badaddr)
: trap_access(15 << 16, badaddr) {}
};
inline void read_reg_uint32(uint64_t offs, uint32_t& reg, uint8_t *const data, unsigned length) {
auto reg_ptr = reinterpret_cast<uint8_t*>(&reg);
switch (offs & 0x3) {
case 0:
for (auto i = 0U; i < length; ++i)
*(data + i) = *(reg_ptr + i);
break;
case 1:
for (auto i = 0U; i < length; ++i)
*(data + i) = *(reg_ptr + 1 + i);
break;
case 2:
for (auto i = 0U; i < length; ++i)
*(data + i) = *(reg_ptr + 2 + i);
break;
case 3:
*data = *(reg_ptr + 3);
break;
}
}
inline void write_reg_uint32(uint64_t offs, uint32_t& reg, const uint8_t *const data, unsigned length) {
auto reg_ptr = reinterpret_cast<uint8_t*>(&reg);
switch (offs & 0x3) {
case 0:
for (auto i = 0U; i < length; ++i)
*(reg_ptr + i) = *(data + i);
break;
case 1:
for (auto i = 0U; i < length; ++i)
*(reg_ptr + 1 + i) = *(data + i);
break;
case 2:
for (auto i = 0U; i < length; ++i)
*(reg_ptr + 2 + i) = *(data + i);
break;
case 3:
*(reg_ptr + 3) = *data ;
break;
}
}
}
}

View File

@ -97,10 +97,8 @@ public:
using reg_t = typename core::reg_t;
using addr_t = typename core::addr_t;
using rd_csr_f = iss::status (this_class::*)(unsigned addr, reg_t &);
using wr_csr_f = iss::status (this_class::*)(unsigned addr, reg_t);
using mem_read_f = iss::status(phys_addr_t addr, unsigned, uint8_t *const);
using mem_write_f = iss::status(phys_addr_t addr, unsigned, uint8_t const *const);
using rd_csr_f = iss::status (this_class::*)(unsigned addr, reg_t &);
using wr_csr_f = iss::status (this_class::*)(unsigned addr, reg_t);
// primary template
template <class T, class Enable = void> struct hart_state {};
@ -203,7 +201,7 @@ public:
void disass_output(uint64_t pc, const std::string instr) override {
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [s:0x{:x};c:{}]",
pc, instr, (reg_t)state.mstatus, this->icount + cycle_offset);
pc, instr, (reg_t)state.mstatus, this->reg.icount);
};
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
@ -220,9 +218,6 @@ public:
csr[addr & csr.page_addr_mask] = val;
}
void set_irq_num(unsigned i) {
mcause_max_irq=1<<util::ilog2(i);
}
protected:
struct riscv_instrumentation_if : public iss::instrumentation_if {
@ -235,24 +230,18 @@ protected:
*/
const std::string core_type_name() const override { return traits<BASE>::core_type; }
uint64_t get_pc() override { return arch.reg.PC; };
virtual uint64_t get_pc() { return arch.get_pc(); };
uint64_t get_next_pc() override { return arch.reg.NEXT_PC; };
virtual uint64_t get_next_pc() { return arch.get_next_pc(); };
uint64_t get_instr_word() override { return arch.instruction; }
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; };
virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; };
riscv_hart_m_p<BASE, FEAT> &arch;
};
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);
@ -298,8 +287,6 @@ protected:
};
std::vector<clic_int_reg_t> clic_int_reg;
std::vector<uint8_t> tcm;
iss::status read_csr_reg(unsigned addr, reg_t &val);
iss::status write_csr_reg(unsigned addr, reg_t val);
iss::status read_null(unsigned addr, reg_t &val);
@ -316,6 +303,7 @@ protected:
iss::status read_ie(unsigned addr, reg_t &val);
iss::status write_ie(unsigned addr, reg_t val);
iss::status read_ip(unsigned addr, reg_t &val);
iss::status write_ip(unsigned addr, reg_t val);
iss::status read_hartid(unsigned addr, reg_t &val);
iss::status write_epc(unsigned addr, reg_t val);
iss::status write_intstatus(unsigned addr, reg_t val);
@ -326,26 +314,12 @@ protected:
iss::status read_dpc_reg(unsigned addr, reg_t &val);
iss::status write_dpc_reg(unsigned addr, reg_t val);
virtual iss::status read_custom_csr_reg(unsigned addr, reg_t &val) {return iss::status::Err;};
virtual iss::status write_custom_csr_reg(unsigned addr, reg_t val) {return iss::status::Err;};
void register_custom_csr_rd(unsigned addr){
csr_rd_cb[addr] = &this_class::read_custom_csr_reg;
}
void register_custom_csr_wr(unsigned addr){
csr_wr_cb[addr] = &this_class::write_custom_csr_reg;
}
reg_t mhartid_reg{0x0};
std::function<iss::status(phys_addr_t, unsigned, uint8_t *const)>mem_read_cb;
std::function<iss::status(phys_addr_t, unsigned, const uint8_t *const)> mem_write_cb;
void check_interrupt();
bool pmp_check(const access_type type, const uint64_t addr, const unsigned len);
std::vector<std::tuple<uint64_t, uint64_t>> memfn_range;
std::vector<std::function<mem_read_f>> memfn_read;
std::vector<std::function<mem_write_f>> memfn_write;
void insert_mem_range(uint64_t, uint64_t, std::function<mem_read_f>, std::function<mem_write_f>);
uint64_t clic_base_addr{0};
unsigned clic_num_irq{0};
unsigned clic_num_trigger{0};
@ -412,7 +386,7 @@ riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p()
csr_rd_cb[mtvec] = &this_class::read_tvec;
csr_wr_cb[mepc] = &this_class::write_epc;
csr_rd_cb[mip] = &this_class::read_ip;
csr_wr_cb[mip] = &this_class::write_null;
csr_wr_cb[mip] = &this_class::write_ip;
csr_rd_cb[mie] = &this_class::read_ie;
csr_wr_cb[mie] = &this_class::write_ie;
csr_rd_cb[mhartid] = &this_class::read_hartid;
@ -420,46 +394,6 @@ riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p()
csr_wr_cb[mvendorid] = &this_class::write_null;
csr_wr_cb[marchid] = &this_class::write_null;
csr_wr_cb[mimpid] = &this_class::write_null;
if(FEAT & FEAT_CLIC) {
csr_rd_cb[mtvt] = &this_class::read_csr_reg;
csr_wr_cb[mtvt] = &this_class::write_csr_reg;
csr_rd_cb[mxnti] = &this_class::read_csr_reg;
csr_wr_cb[mxnti] = &this_class::write_csr_reg;
csr_rd_cb[mintstatus] = &this_class::read_csr_reg;
csr_wr_cb[mintstatus] = &this_class::write_null;
csr_rd_cb[mscratchcsw] = &this_class::read_csr_reg;
csr_wr_cb[mscratchcsw] = &this_class::write_csr_reg;
csr_rd_cb[mscratchcswl] = &this_class::read_csr_reg;
csr_wr_cb[mscratchcswl] = &this_class::write_csr_reg;
csr_rd_cb[mintthresh] = &this_class::read_csr_reg;
csr_wr_cb[mintthresh] = &this_class::write_intthresh;
csr_rd_cb[mclicbase] = &this_class::read_csr_reg;
csr_wr_cb[mclicbase] = &this_class::write_null;
clic_base_addr=0xC0000000;
clic_num_irq=16;
clic_int_reg.resize(clic_num_irq);
clic_cfg_reg=0x20;
clic_info_reg = (/*CLICINTCTLBITS*/ 4U<<21) + clic_num_irq;
mcause_max_irq=clic_num_irq+16;
insert_mem_range(clic_base_addr, 0x5000UL,
[this](phys_addr_t addr, unsigned length, uint8_t * const data) { return read_clic(addr.val, length, data);},
[this](phys_addr_t addr, unsigned length, uint8_t const * const data) {return write_clic(addr.val, length, data);});
}
if(FEAT & FEAT_TCM) {
tcm.resize(0x8000);
std::function<mem_read_f> read_clic_cb = [this](phys_addr_t addr, unsigned length, uint8_t * const data) {
auto offset=addr.val-0x10000000;
std::copy(tcm.data() + offset, tcm.data() + offset + length, data);
return iss::Ok;
};
std::function<mem_write_f> write_clic_cb = [this](phys_addr_t addr, unsigned length, uint8_t const * const data) {
auto offset=addr.val-0x10000000;
std::copy(data, data + length, tcm.data() + offset);
return iss::Ok;
};
insert_mem_range(0x10000000, 0x8000UL, read_clic_cb, write_clic_cb);
}
if(FEAT & FEAT_DEBUG){
csr_wr_cb[dscratch0] = &this_class::write_dcsr_reg;
csr_rd_cb[dscratch0] = &this_class::read_dcsr_reg;
@ -538,20 +472,6 @@ template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m
throw std::runtime_error("memory load file not found");
}
template<typename BASE, features_e FEAT>
inline void riscv_hart_m_p<BASE, FEAT>::insert_mem_range(uint64_t base, uint64_t size, std::function<mem_read_f> rd_f,
std::function<mem_write_f> wr_fn) {
std::tuple<uint64_t, uint64_t> entry{base, size};
auto it = std::upper_bound( memfn_range.begin(), memfn_range.end(), entry,
[](std::tuple<uint64_t, uint64_t> const& a, std::tuple<uint64_t, uint64_t> const& b){
return std::get<0>(a)<std::get<0>(b);
});
auto idx = std::distance(memfn_range.begin(), it);
memfn_range.insert(it, entry);
memfn_read.insert(std::begin(memfn_read)+idx, rd_f);
memfn_write.insert(std::begin(memfn_write)+idx, wr_fn);
}
template <typename BASE, features_e FEAT>
iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const access_type access, const uint32_t space,
const uint64_t addr, const unsigned length, uint8_t *const data) {
@ -567,40 +487,29 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
try {
switch (space) {
case traits<BASE>::MEM: {
auto alignment = is_fetch(access)? (traits<BASE>::MISA_VAL&0x100? 2 : 4) : length;
if (unlikely(is_fetch(access) && (addr&(alignment-1)))) {
if (unlikely((access == iss::access_type::FETCH || access == iss::access_type::DEBUG_FETCH) && (addr & 0x1) == 1)) {
fault_data = addr;
if (is_debug(access)) throw trap_access(0, addr);
this->trap_state = (1 << 31); // issue trap 0
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
this->reg.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;
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;
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(!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;
});
if(it!=std::end(memfn_range)) {
auto idx = std::distance(std::begin(memfn_range), it);
res = memfn_read[idx](phys_addr, length, data);
} else
res = read_mem( phys_addr, length, data);
} else {
res = read_mem( phys_addr, length, data);
}
auto res = type==iss::address_type::PHYSICAL?
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->trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
fault_data=addr;
}
return res;
} catch (trap_access &ta) {
this->trap_state = (1 << 31) | ta.id;
this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err;
}
@ -626,7 +535,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
}
return iss::Ok;
} catch (trap_access &ta) {
this->trap_state = (1 << 31) | ta.id;
this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err;
}
@ -664,36 +573,25 @@ 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->trap_state = (1 << 31); // issue trap 0
this->reg.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->trap_state = 1<<31 | 6<<16;
if(!(access && iss::access_type::DEBUG) && length>1 && (addr&(length-1))){
this->reg.trap_state = 1<<31 | 6<<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()){
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;
});
if(it!=std::end(memfn_range)) {
auto idx = std::distance(std::begin(memfn_range), it);
res = memfn_write[idx]( phys_addr, length, data);
} else
res = write_mem( phys_addr, length, data);
} else {
res = write_mem( phys_addr, length, data);
}
auto res = type==iss::address_type::PHYSICAL?
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->trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
fault_data=addr;
}
return res;
} catch (trap_access &ta) {
this->trap_state = (1 << 31) | ta.id;
this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err;
}
@ -753,7 +651,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
}
return iss::Ok;
} catch (trap_access &ta) {
this->trap_state = (1 << 31) | ta.id;
this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err;
}
@ -799,7 +697,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->icount + cycle_offset;
auto cycle_val = this->reg.icount + cycle_offset;
if (addr == mcycle) {
val = static_cast<reg_t>(cycle_val);
} else if (addr == mcycleh) {
@ -821,16 +719,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->icount; // TODO: relying on wrap-around
cycle_offset = mcycle_csr-this->reg.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->instret);
val = static_cast<reg_t>(this->reg.instret);
} else if ((addr&0xff) == (minstreth&0xff)) {
if (sizeof(typename traits<BASE>::reg_t) != 4) return iss::Err;
val = static_cast<reg_t>(this->instret >> 32);
val = static_cast<reg_t>(this->reg.instret >> 32);
}
return iss::Ok;
}
@ -839,20 +737,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->instret = static_cast<uint64_t>(val);
this->reg.instret = static_cast<uint64_t>(val);
} else {
if ((addr&0xff) == (minstret&0xff)) {
this->instret = (this->instret & 0xffffffff00000000) + val;
this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val;
} else {
this->instret = (static_cast<uint64_t>(val)<<32) + (this->instret & 0xffffffff);
this->reg.instret = (static_cast<uint64_t>(val)<<32) + (this->reg.instret & 0xffffffff);
}
}
this->instret--;
this->reg.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->icount / (100000000 / 32768 - 1); //-> ~3052;
uint64_t time_val = this->reg.icount / (100000000 / 32768 - 1); //-> ~3052;
if (addr == time) {
val = static_cast<reg_t>(time_val);
} else if (addr == timeh) {
@ -879,7 +777,7 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
}
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_cause(unsigned addr, reg_t val) {
csr[mcause] = val & ((1UL<<(traits<BASE>::XLEN-1))| (mcause_max_irq-1));
csr[mcause] = val & ((1UL<<(traits<BASE>::XLEN-1))|0xf); //TODO: make exception code size configurable
return iss::Ok;
}
@ -907,6 +805,14 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
return iss::Ok;
}
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_ip(unsigned addr, reg_t val) {
auto mask = get_irq_mask();
mask &= 0xf; // only xSIP is writable
csr[mip] = (csr[mip] & ~mask) | (val & mask);
check_interrupt();
return iss::Ok;
}
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_epc(unsigned addr, reg_t val) {
csr[addr] = val & get_pc_mask();
return iss::Ok;
@ -951,12 +857,6 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
return iss::Ok;
}
template<typename BASE, features_e FEAT>
iss::status riscv_hart_m_p<BASE, FEAT>::write_intthresh(unsigned addr, reg_t val) {
csr[addr]= val &0xff;
return iss::Ok;
}
template <typename BASE, features_e FEAT>
iss::status riscv_hart_m_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
if(mem_read_cb) return mem_read_cb(paddr, length, data);
@ -971,7 +871,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->icount > 30000) data[3] |= 0x80;
if (this->reg.icount > 30000) data[3] |= 0x80;
} break;
default: {
for(auto offs=0U; offs<length; ++offs) {
@ -1031,7 +931,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->trap_state=std::numeric_limits<uint32_t>::max();
this->reg.trap_state=std::numeric_limits<uint32_t>::max();
this->interrupt_sim=hostvar;
break;
//throw(iss::simulation_stopped(hostvar));
@ -1060,42 +960,6 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned le
return iss::Ok;
}
template<typename BASE, features_e FEAT>
iss::status riscv_hart_m_p<BASE, FEAT>::read_clic(uint64_t addr, unsigned length, uint8_t *const data) {
if(addr==clic_base_addr) { // cliccfg
*data=clic_cfg_reg;
for(auto i=1; i<length; ++i) *(data+i)=0;
} else if(addr>=(clic_base_addr+4) && (addr+length)<=(clic_base_addr+8)){ // clicinfo
read_reg_uint32(addr, clic_info_reg, data, length);
} else if(addr>=(clic_base_addr+0x40) && (addr+length)<=(clic_base_addr+0x40+clic_num_trigger*4)){ // clicinttrig
auto offset = ((addr&0x7fff)-0x40)/4;
read_reg_uint32(addr, clic_inttrig_reg[offset], data, length);
} else if(addr>=(clic_base_addr+0x1000) && (addr+length)<=(clic_base_addr+clic_num_irq*4)){ // clicintip/clicintie/clicintattr/clicintctl
auto offset = ((addr&0x7fff)-0x1000)/4;
read_reg_uint32(addr, clic_int_reg[offset].raw, data, length);
} else {
for(auto i = 0U; i<length; ++i) *(data+i)=0;
}
return iss::Ok;
}
template<typename BASE, features_e FEAT>
iss::status riscv_hart_m_p<BASE, FEAT>::write_clic(uint64_t addr, unsigned length, const uint8_t *const data) {
if(addr==clic_base_addr) { // cliccfg
clic_cfg_reg = *data;
clic_cfg_reg&= 0x7e;
// } else if(addr>=(clic_base_addr+4) && (addr+length)<=(clic_base_addr+4)){ // clicinfo
// write_uint32(addr, clic_info_reg, data, length);
} else if(addr>=(clic_base_addr+0x40) && (addr+length)<=(clic_base_addr+0xC0)){ // clicinttrig
auto offset = ((addr&0x7fff)-0x40)/4;
write_reg_uint32(addr, clic_inttrig_reg[offset], data, length);
} else if(addr>=(clic_base_addr+0x1000) && (addr+length)<=(clic_base_addr+clic_num_irq*4)){ // clicintip/clicintie/clicintattr/clicintctl
auto offset = ((addr&0x7fff)-0x1000)/4;
write_reg_uint32(addr, clic_int_reg[offset].raw, data, length);
}
return iss::Ok;
}
template <typename BASE, features_e FEAT> inline void riscv_hart_m_p<BASE, FEAT>::reset(uint64_t address) {
BASE::reset(address);
state.mstatus = hart_state_type::mstatus_reset_val;
@ -1119,7 +983,7 @@ template <typename BASE, features_e FEAT> void riscv_hart_m_p<BASE, FEAT>::check
enabled_interrupts >>= 1;
res++;
}
this->pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
this->reg.pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
}
}
@ -1129,7 +993,6 @@ 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
@ -1149,13 +1012,10 @@ 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:
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;
}
//TODO: implement debug mode behavior
// csr[dpc] = addr;
// csr[dcsr] = (csr[dcsr] & ~0x1c3) | (1<<6) | PRIV_M; //FIXME: cause should not be 4 (stepi)
csr[mtval] = 0;
break;
case 4:
case 6:
@ -1167,9 +1027,9 @@ 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->pending_trap = 0;
this->reg.pending_trap = 0;
}
csr[mcause] = (trap_id << (traits<BASE>::XLEN-1)) + cause;
csr[mcause] = (trap_id << 31) + cause;
// update mstatus
// xPP field of mstatus is written with the active privilege mode at the time
// of the trap; the x PIE field of mstatus
@ -1188,8 +1048,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 = new_priv;
this->trap_state = 0;
this->reg.PRIV = PRIV_M;
this->reg.trap_state = 0;
std::array<char, 32> buffer;
#if defined(_MSC_VER)
sprintf(buffer.data(), "0x%016llx", addr);

View File

@ -293,21 +293,21 @@ public:
std::pair<uint64_t, bool> load_file(std::string name, int type = -1) override;
phys_addr_t virt2phys(const iss::addr_t &addr) override;
virtual phys_addr_t virt2phys(const iss::addr_t &addr) override;
iss::status read(const address_type type, const access_type access, const uint32_t space,
const uint64_t addr, const unsigned length, uint8_t *const data) override;
iss::status write(const address_type type, const access_type access, const uint32_t space,
const uint64_t addr, const unsigned length, const uint8_t *const data) override;
uint64_t enter_trap(uint64_t flags) override { return riscv_hart_msu_vp::enter_trap(flags, fault_data, fault_data); }
uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override;
uint64_t leave_trap(uint64_t flags) override;
virtual uint64_t enter_trap(uint64_t flags) override { return riscv_hart_msu_vp::enter_trap(flags, fault_data, fault_data); }
virtual uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override;
virtual uint64_t leave_trap(uint64_t flags) override;
void wait_until(uint64_t flags) override;
void disass_output(uint64_t pc, const std::string instr) override {
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]",
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->icount + cycle_offset);
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.ccount);
};
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
@ -340,14 +340,6 @@ protected:
virtual uint64_t get_next_pc() { return arch.get_next_pc(); };
uint64_t get_instr_word() override { return arch.instruction; }
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; };
riscv_hart_msu_vp<BASE> &arch;
@ -404,6 +396,7 @@ private:
iss::status read_ie(unsigned addr, reg_t &val);
iss::status write_ie(unsigned addr, reg_t val);
iss::status read_ip(unsigned addr, reg_t &val);
iss::status write_ip(unsigned addr, reg_t val);
iss::status read_hartid(unsigned addr, reg_t &val);
iss::status write_epc(unsigned addr, reg_t val);
iss::status read_satp(unsigned addr, reg_t &val);
@ -411,16 +404,6 @@ private:
iss::status read_fcsr(unsigned addr, reg_t &val);
iss::status write_fcsr(unsigned addr, reg_t val);
virtual iss::status read_custom_csr_reg(unsigned addr, reg_t &val) {return iss::status::Err;};
virtual iss::status write_custom_csr_reg(unsigned addr, reg_t val) {return iss::status::Err;};
void register_custom_csr_rd(unsigned addr){
csr_rd_cb[addr] = &this_class::read_custom_csr_reg;
}
void register_custom_csr_wr(unsigned addr){
csr_wr_cb[addr] = &this_class::write_custom_csr_reg;
}
reg_t mhartid_reg{0x0};
std::function<iss::status(phys_addr_t, unsigned, uint8_t *const)>mem_read_cb;
std::function<iss::status(phys_addr_t, unsigned, const uint8_t *const)> mem_write_cb;
@ -502,11 +485,11 @@ riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp()
csr_wr_cb[sepc] = &this_class::write_epc;
csr_wr_cb[uepc] = &this_class::write_epc;
csr_rd_cb[mip] = &this_class::read_ip;
csr_wr_cb[mip] = &this_class::write_null;
csr_wr_cb[mip] = &this_class::write_ip;
csr_rd_cb[sip] = &this_class::read_ip;
csr_wr_cb[sip] = &this_class::write_null;
csr_wr_cb[sip] = &this_class::write_ip;
csr_rd_cb[uip] = &this_class::read_ip;
csr_wr_cb[uip] = &this_class::write_null;
csr_wr_cb[uip] = &this_class::write_ip;
csr_rd_cb[mie] = &this_class::read_ie;
csr_wr_cb[mie] = &this_class::write_ie;
csr_rd_cb[sie] = &this_class::read_ie;
@ -611,19 +594,13 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
try {
switch (space) {
case traits<BASE>::MEM: {
auto alignment = is_fetch(access)? (traits<BASE>::MISA_VAL&0x100? 2 : 4) : length;
if (unlikely(is_fetch(access) && (addr&(alignment-1)))) {
if (unlikely((access == iss::access_type::FETCH || access == iss::access_type::DEBUG_FETCH) && (addr & 0x1) == 1)) {
fault_data = addr;
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
this->trap_state = (1 << 31); // issue trap 0
this->reg.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
@ -639,12 +616,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->trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
fault_data=addr;
}
return res;
} catch (trap_access &ta) {
this->trap_state = (1 << 31) | ta.id;
this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err;
}
@ -660,7 +637,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->trap_state = (1 << 31) | (2 << 16);
this->reg.trap_state = (1 << 31) | (2 << 16);
this->fault_data = this->reg.PC;
return iss::Err;
}
@ -681,7 +658,7 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
}
return iss::Ok;
} catch (trap_access &ta) {
this->trap_state = (1 << 31) | ta.id;
this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err;
}
@ -719,7 +696,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->trap_state = (1 << 31); // issue trap 0
this->reg.trap_state = (1 << 31); // issue trap 0
return iss::Err;
}
try {
@ -738,12 +715,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->trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
fault_data=addr;
}
return res;
} catch (trap_access &ta) {
this->trap_state = (1 << 31) | ta.id;
this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err;
}
@ -792,7 +769,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->trap_state = (1 << 31) | (2 << 16);
this->reg.trap_state = (1 << 31) | (2 << 16);
this->fault_data = this->reg.PC;
return iss::Err;
}
@ -808,7 +785,7 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
}
return iss::Ok;
} catch (trap_access &ta) {
this->trap_state = (1 << 31) | ta.id;
this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err;
}
@ -854,7 +831,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->icount + cycle_offset;
auto cycle_val = this->reg.icount + cycle_offset;
if (addr == mcycle) {
val = static_cast<reg_t>(cycle_val);
} else if (addr == mcycleh) {
@ -876,7 +853,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->icount; // TODO: relying on wrap-around
cycle_offset = mcycle_csr-this->reg.icount; // TODO: relying on wrap-around
return iss::Ok;
}
@ -907,7 +884,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->icount / (100000000 / 32768 - 1); //-> ~3052;
uint64_t time_val = this->reg.icount / (100000000 / 32768 - 1); //-> ~3052;
if (addr == time) {
val = static_cast<reg_t>(time_val);
} else if (addr == timeh) {
@ -968,6 +945,15 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_ip(unsigned a
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_ip(unsigned addr, reg_t val) {
auto req_priv_lvl = (addr >> 8) & 0x3;
auto mask = get_irq_mask(req_priv_lvl);
mask &= ~(1 << 7); // MTIP is read only
csr[mip] = (csr[mip] & ~mask) | (val & mask);
check_interrupt();
return iss::Ok;
}
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_epc(unsigned addr, reg_t val) {
csr[addr] = val & get_pc_mask();
return iss::Ok;
@ -976,7 +962,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->trap_state = (1 << 31) | (2 << 16);
this->reg.trap_state = (1 << 31) | (2 << 16);
this->fault_data = this->reg.PC;
return iss::Err;
}
@ -987,7 +973,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->trap_state = (1 << 31) | (2 << 16);
this->reg.trap_state = (1 << 31) | (2 << 16);
this->fault_data = this->reg.PC;
return iss::Err;
}
@ -1043,7 +1029,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->icount > 30000) data[3] |= 0x80;
if (this->reg.icount > 30000) data[3] |= 0x80;
} break;
default: {
for(auto offs=0U; offs<length; ++offs) {
@ -1103,7 +1089,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->trap_state=std::numeric_limits<uint32_t>::max();
this->reg.trap_state=std::numeric_limits<uint32_t>::max();
this->interrupt_sim=hostvar;
break;
//throw(iss::simulation_stopped(hostvar));
@ -1172,7 +1158,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->pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
this->reg.pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
}
}
@ -1290,33 +1276,13 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f
* access, or page-fault exception occurs, mtval is written with the
* faulting effective address.
*/
switch(cause){
case 0:
csr[utval | (new_priv << 8)] = static_cast<reg_t>(addr);
break;
case 2:
csr[utval | (new_priv << 8)] = (instr & 0x3)==3?instr:instr&0xffff;
break;
case 3:
//TODO: implement debug mode behavior
// csr[dpc] = addr;
// csr[dcsr] = (csr[dcsr] & ~0x1c3) | (1<<6) | PRIV_M; //FIXME: cause should not be 4 (stepi)
csr[utval | (new_priv << 8)] = addr;
break;
case 4:
case 6:
case 7:
csr[utval | (new_priv << 8)] = fault_data;
break;
default:
csr[utval | (new_priv << 8)] = 0;
}
csr[utval | (new_priv << 8)] = cause==2?((instr & 0x3)==3?instr:instr&0xffff):fault_data;
fault_data = 0;
} else {
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->pending_trap = 0;
this->reg.pending_trap = 0;
}
size_t adr = ucause | (new_priv << 8);
csr[adr] = (trap_id << 31) + cause;
@ -1361,7 +1327,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->trap_state = 0;
this->reg.trap_state = 0;
update_vm_info();
return this->reg.NEXT_PC;
}
@ -1373,7 +1339,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->trap_state = (1 << 31) | (2 << 16);
this->reg.trap_state = (1 << 31) | (2 << 16);
this->fault_data = this->reg.PC;
return this->reg.PC;
}
@ -1412,7 +1378,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->trap_state = (1 << 31) | (2 << 16);
this->reg.trap_state = (1 << 31) | (2 << 16);
this->fault_data = this->reg.PC;
}
}

View File

@ -97,10 +97,8 @@ public:
using reg_t = typename core::reg_t;
using addr_t = typename core::addr_t;
using rd_csr_f = iss::status (this_class::*)(unsigned addr, reg_t &);
using wr_csr_f = iss::status (this_class::*)(unsigned addr, reg_t);
using mem_read_f = iss::status(phys_addr_t addr, unsigned, uint8_t *const);
using mem_write_f = iss::status(phys_addr_t addr, unsigned, uint8_t const *const);
using rd_csr_f = iss::status (this_class::*)(unsigned addr, reg_t &);
using wr_csr_f = iss::status (this_class::*)(unsigned addr, reg_t);
// primary template
template <class T, class Enable = void> struct hart_state {};
@ -197,7 +195,7 @@ public:
return traits<BASE>::MISA_VAL&0b0100?~1:~3;
}
riscv_hart_mu_p(feature_config cfg = feature_config{});
riscv_hart_mu_p();
virtual ~riscv_hart_mu_p() = default;
void reset(uint64_t address) override;
@ -209,16 +207,16 @@ public:
iss::status write(const address_type type, const access_type access, const uint32_t space,
const uint64_t addr, const unsigned length, const uint8_t *const data) override;
uint64_t enter_trap(uint64_t flags) override { return riscv_hart_mu_p::enter_trap(flags, fault_data, fault_data); }
uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override;
uint64_t leave_trap(uint64_t flags) override;
virtual uint64_t enter_trap(uint64_t flags) override { return riscv_hart_mu_p::enter_trap(flags, fault_data, fault_data); }
virtual uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override;
virtual uint64_t leave_trap(uint64_t flags) override;
const reg_t& get_mhartid() const { return mhartid_reg; }
void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; };
void disass_output(uint64_t pc, const std::string instr) override {
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]",
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->icount + cycle_offset);
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.icount);
};
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
@ -235,9 +233,6 @@ public:
csr[addr & csr.page_addr_mask] = val;
}
void set_irq_num(unsigned i) {
mcause_max_irq=1<<util::ilog2(i);
}
protected:
struct riscv_instrumentation_if : public iss::instrumentation_if {
@ -254,14 +249,6 @@ protected:
virtual uint64_t get_next_pc() { return arch.get_next_pc(); };
uint64_t get_instr_word() override { return arch.instruction; }
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; };
riscv_hart_mu_p<BASE, FEAT> &arch;
@ -315,8 +302,6 @@ protected:
};
std::vector<clic_int_reg_t> clic_int_reg;
std::vector<uint8_t> tcm;
iss::status read_csr_reg(unsigned addr, reg_t &val);
iss::status write_csr_reg(unsigned addr, reg_t val);
iss::status read_null(unsigned addr, reg_t &val);
@ -333,6 +318,7 @@ protected:
iss::status read_ie(unsigned addr, reg_t &val);
iss::status write_ie(unsigned addr, reg_t val);
iss::status read_ip(unsigned addr, reg_t &val);
iss::status write_ip(unsigned addr, reg_t val);
iss::status write_ideleg(unsigned addr, reg_t val);
iss::status write_edeleg(unsigned addr, reg_t val);
iss::status read_hartid(unsigned addr, reg_t &val);
@ -344,17 +330,6 @@ protected:
iss::status write_dcsr_reg(unsigned addr, reg_t val);
iss::status read_dpc_reg(unsigned addr, reg_t &val);
iss::status write_dpc_reg(unsigned addr, reg_t val);
iss::status write_pmpcfg_reg(unsigned addr, reg_t val);
virtual iss::status read_custom_csr_reg(unsigned addr, reg_t &val) {return iss::status::Err;};
virtual iss::status write_custom_csr_reg(unsigned addr, reg_t val) {return iss::status::Err;};
void register_custom_csr_rd(unsigned addr){
csr_rd_cb[addr] = &this_class::read_custom_csr_reg;
}
void register_custom_csr_wr(unsigned addr){
csr_wr_cb[addr] = &this_class::write_custom_csr_reg;
}
reg_t mhartid_reg{0x0};
std::function<iss::status(phys_addr_t, unsigned, uint8_t *const)>mem_read_cb;
@ -362,26 +337,23 @@ protected:
void check_interrupt();
bool pmp_check(const access_type type, const uint64_t addr, const unsigned len);
std::vector<std::tuple<uint64_t, uint64_t>> memfn_range;
std::vector<std::function<mem_read_f>> memfn_read;
std::vector<std::function<mem_write_f>> memfn_write;
void insert_mem_range(uint64_t, uint64_t, std::function<mem_read_f>, std::function<mem_write_f>);
feature_config cfg;
uint64_t clic_base_addr{0};
unsigned clic_num_irq{0};
unsigned clic_num_trigger{0};
unsigned mcause_max_irq{16};
inline bool debug_mode_active() {return this->reg.PRIV&0x4;}
};
template <typename BASE, features_e FEAT>
riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p(feature_config cfg)
riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p()
: state()
, instr_if(*this)
, cfg(cfg) {
, instr_if(*this) {
// reset values
csr[misa] = traits<BASE>::MISA_VAL;
csr[mvendorid] = 0x669;
csr[marchid] = traits<BASE>::MARCHID_VAL;
csr[mimpid] = 1;
csr[mclicbase] = cfg.clic_base; // TODO: should be taken from YAML file
csr[mclicbase] = 0xc0000000; // TODO: should be taken from YAML file
uart_buf.str("");
for (unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr){
@ -435,7 +407,7 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p(feature_config cfg)
csr_rd_cb[mtvec] = &this_class::read_tvec;
csr_wr_cb[mepc] = &this_class::write_epc;
csr_rd_cb[mip] = &this_class::read_ip;
csr_wr_cb[mip] = &this_class::write_null;
csr_wr_cb[mip] = &this_class::write_ip;
csr_rd_cb[mie] = &this_class::read_ie;
csr_wr_cb[mie] = &this_class::write_ie;
csr_rd_cb[mhartid] = &this_class::read_hartid;
@ -453,7 +425,7 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p(feature_config cfg)
}
for(size_t i=pmpcfg0; i<=pmpcfg3; ++i){
csr_rd_cb[i] = &this_class::read_csr_reg;
csr_wr_cb[i] = &this_class::write_pmpcfg_reg;
csr_wr_cb[i] = &this_class::write_csr_reg;
}
}
if(FEAT & FEAT_EXT_N){
@ -464,7 +436,7 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p(feature_config cfg)
csr_rd_cb[uie] = &this_class::read_ie;
csr_wr_cb[uie] = &this_class::write_ie;
csr_rd_cb[uip] = &this_class::read_ip;
csr_wr_cb[uip] = &this_class::write_null;
csr_wr_cb[uip] = &this_class::write_ip;
csr_wr_cb[uepc] = &this_class::write_epc;
csr_rd_cb[ustatus] = &this_class::read_status;
csr_wr_cb[ustatus] = &this_class::write_status;
@ -487,27 +459,12 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p(feature_config cfg)
csr_rd_cb[mclicbase] = &this_class::read_csr_reg;
csr_wr_cb[mclicbase] = &this_class::write_null;
clic_int_reg.resize(cfg.clic_num_irq);
clic_base_addr=0xC0000000;
clic_num_irq=16;
clic_int_reg.resize(clic_num_irq);
clic_cfg_reg=0x20;
clic_info_reg = (/*CLICINTCTLBITS*/ 4U<<21) + cfg.clic_num_irq;
mcause_max_irq=cfg.clic_num_irq+16;
insert_mem_range(cfg.clic_base, 0x5000UL,
[this](phys_addr_t addr, unsigned length, uint8_t * const data) { return read_clic(addr.val, length, data);},
[this](phys_addr_t addr, unsigned length, uint8_t const * const data) {return write_clic(addr.val, length, data);});
}
if(FEAT & FEAT_TCM) {
tcm.resize(cfg.tcm_size);
std::function<mem_read_f> read_clic_cb = [this](phys_addr_t addr, unsigned length, uint8_t * const data) {
auto offset=addr.val-this->cfg.tcm_base;
std::copy(tcm.data() + offset, tcm.data() + offset + length, data);
return iss::Ok;
};
std::function<mem_write_f> write_clic_cb = [this](phys_addr_t addr, unsigned length, uint8_t const * const data) {
auto offset=addr.val-this->cfg.tcm_base;
std::copy(data, data + length, tcm.data() + offset);
return iss::Ok;
};
insert_mem_range(cfg.tcm_base, cfg.tcm_size, read_clic_cb, write_clic_cb);
clic_info_reg = (/*CLICINTCTLBITS*/ 4U<<21) + clic_num_irq;
mcause_max_irq=clic_num_irq+16;
}
if(FEAT & FEAT_DEBUG){
csr_wr_cb[dscratch0] = &this_class::write_dcsr_reg;
@ -587,26 +544,6 @@ template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m
throw std::runtime_error("memory load file not found");
}
template<typename BASE, features_e FEAT>
inline void riscv_hart_mu_p<BASE, FEAT>::insert_mem_range(uint64_t base, uint64_t size, std::function<mem_read_f> rd_f,
std::function<mem_write_f> wr_fn) {
std::tuple<uint64_t, uint64_t> entry{base, size};
auto it = std::upper_bound( memfn_range.begin(), memfn_range.end(), entry,
[](std::tuple<uint64_t, uint64_t> const& a, std::tuple<uint64_t, uint64_t> const& b){
return std::get<0>(a)<std::get<0>(b);
});
auto idx = std::distance(memfn_range.begin(), it);
memfn_range.insert(it, entry);
memfn_read.insert(std::begin(memfn_read)+idx, rd_f);
memfn_write.insert(std::begin(memfn_write)+idx, wr_fn);
}
template<typename BASE, features_e FEAT>
inline iss::status riscv_hart_mu_p<BASE, FEAT>::write_pmpcfg_reg(unsigned addr, reg_t val) {
csr[addr] = val & 0x9f9f9f9f;
return iss::Ok;
}
template <typename BASE, features_e FEAT> bool riscv_hart_mu_p<BASE, FEAT>::pmp_check(const access_type type, const uint64_t addr, const unsigned len) {
constexpr auto PMP_SHIFT=2U;
constexpr auto PMP_R = 0x1U;
@ -637,7 +574,7 @@ template <typename BASE, features_e FEAT> bool riscv_hart_mu_p<BASE, FEAT>::pmp_
for (reg_t offset = 0; offset < len; offset += 1 << PMP_SHIFT) {
reg_t cur_addr = addr + offset;
auto napot_match = ((cur_addr ^ tor) & mask) == 0;
auto tor_match = base <= (cur_addr+len-1) && cur_addr < tor;
auto tor_match = base <= cur_addr && cur_addr < tor;
auto match = is_tor ? tor_match : napot_match;
any_match |= match;
all_match &= match;
@ -705,47 +642,40 @@ 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) && !is_debug(access)) {
if(!pmp_check(access, addr, length) && (access&access_type::DEBUG) != access_type::DEBUG) {
fault_data = addr;
if (is_debug(access)) throw trap_access(0, addr);
this->trap_state = (1 << 31) | ((access==access_type::FETCH?1:5) << 16); // issue trap 1
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
return iss::Err;
}
}
auto alignment = is_fetch(access)? (traits<BASE>::MISA_VAL&0x100? 2 : 4) : length;
if (unlikely(is_fetch(access) && (addr&(alignment-1)))) {
if (unlikely((access == iss::access_type::FETCH || access == iss::access_type::DEBUG_FETCH) && (addr & 0x1) == 1)) {
fault_data = addr;
if (is_debug(access)) throw trap_access(0, addr);
this->trap_state = (1 << 31); // issue trap 0
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
this->reg.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;
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;
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()){
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;
});
if(it!=std::end(memfn_range)) {
auto idx = std::distance(std::begin(memfn_range), it);
res = memfn_read[idx](phys_addr, length, data);
} else
res = read_mem( phys_addr, length, data);
if((FEAT & FEAT_CLIC) && access != access_type::FETCH && phys_addr.val>=clic_base_addr && (phys_addr.val+length)<=(clic_base_addr+0x5000)){ //TODO: should be a constant
res = read_clic(phys_addr.val, length, data);
} else {
res = read_mem( phys_addr, length, data);
}
if (unlikely(res != iss::Ok)){
this->trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
fault_data=addr;
}
return res;
} catch (trap_access &ta) {
this->trap_state = (1 << 31) | ta.id;
this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err;
}
@ -771,7 +701,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
}
return iss::Ok;
} catch (trap_access &ta) {
this->trap_state = (1 << 31) | ta.id;
this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err;
}
@ -810,43 +740,32 @@ 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->trap_state = (1 << 31) | (7 << 16); // issue trap 1
this->reg.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->trap_state = (1 << 31); // issue trap 0
this->reg.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->trap_state = 1<<31 | 6<<16;
this->reg.trap_state = 1<<31 | 6<<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()){
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;
});
if(it!=std::end(memfn_range)) {
auto idx = std::distance(std::begin(memfn_range), it);
res = memfn_write[idx]( phys_addr, length, data);
} else
res = write_mem( phys_addr, length, data);
} else {
res = write_mem( phys_addr, length, data);
}
auto res = ((FEAT & FEAT_CLIC) && phys_addr.val>=clic_base_addr && (phys_addr.val+length)<=(clic_base_addr+0x5000))? //TODO: should be a constant
write_clic(phys_addr.val, length, data) : write_mem( phys_addr, length, data);
if (unlikely(res != iss::Ok)) {
this->trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
fault_data=addr;
}
return res;
} catch (trap_access &ta) {
this->trap_state = (1 << 31) | ta.id;
this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err;
}
@ -906,7 +825,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
}
return iss::Ok;
} catch (trap_access &ta) {
this->trap_state = (1 << 31) | ta.id;
this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr;
return iss::Err;
}
@ -952,7 +871,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->icount + cycle_offset;
auto cycle_val = this->reg.icount + cycle_offset;
if (addr == mcycle) {
val = static_cast<reg_t>(cycle_val);
} else if (addr == mcycleh) {
@ -974,16 +893,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->icount; // TODO: relying on wrap-around
cycle_offset = mcycle_csr-this->reg.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->instret);
val = static_cast<reg_t>(this->reg.instret);
} else if ((addr&0xff) == (minstreth&0xff)) {
if (sizeof(typename traits<BASE>::reg_t) != 4) return iss::Err;
val = static_cast<reg_t>(this->instret >> 32);
val = static_cast<reg_t>(this->reg.instret >> 32);
}
return iss::Ok;
}
@ -992,20 +911,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->instret = static_cast<uint64_t>(val);
this->reg.instret = static_cast<uint64_t>(val);
} else {
if ((addr&0xff) == (minstret&0xff)) {
this->instret = (this->instret & 0xffffffff00000000) + val;
this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val;
} else {
this->instret = (static_cast<uint64_t>(val)<<32) + (this->instret & 0xffffffff);
this->reg.instret = (static_cast<uint64_t>(val)<<32) + (this->reg.instret & 0xffffffff);
}
}
this->instret--;
this->reg.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->icount / (100000000 / 32768 - 1); //-> ~3052;
uint64_t time_val = this->reg.icount / (100000000 / 32768 - 1); //-> ~3052;
if (addr == time) {
val = static_cast<reg_t>(time_val);
} else if (addr == timeh) {
@ -1033,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>::write_cause(unsigned addr, reg_t val) {
csr[addr] = val & ((1UL<<(traits<BASE>::XLEN-1))|(mcause_max_irq-1));
csr[addr] = val & ((1UL<<(traits<BASE>::XLEN-1))|(mcause_max_irq-1)); //TODO: make exception code size configurable
return iss::Ok;
}
@ -1065,6 +984,14 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
return iss::Ok;
}
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_ip(unsigned addr, reg_t val) {
auto mask = get_irq_mask((addr >> 8) & 0x3);
mask &= 0xf; // only xSIP is writable
csr[mip] = (csr[mip] & ~mask) | (val & mask);
check_interrupt();
return iss::Ok;
}
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_ideleg(unsigned addr, reg_t val) {
auto mask = 0b000100010001; // only U mode supported
csr[mideleg] = (csr[mideleg] & ~mask) | (val & mask);
@ -1141,7 +1068,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->icount > 30000) data[3] |= 0x80;
if (this->reg.icount > 30000) data[3] |= 0x80;
} break;
default: {
for(auto offs=0U; offs<length; ++offs) {
@ -1160,7 +1087,8 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned l
case 0x10023000: // UART1 base, TXFIFO reg
uart_buf << (char)data[0];
if (((char)data[0]) == '\n' || data[0] == 0) {
LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send '"<<uart_buf.str()<<"'";
// LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send
// '"<<uart_buf.str()<<"'";
std::cout << uart_buf.str();
uart_buf.str("");
}
@ -1200,7 +1128,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->trap_state=std::numeric_limits<uint32_t>::max();
this->reg.trap_state=std::numeric_limits<uint32_t>::max();
this->interrupt_sim=hostvar;
break;
//throw(iss::simulation_stopped(hostvar));
@ -1229,19 +1157,61 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned l
return iss::Ok;
}
void read_uint32(uint64_t offs, uint32_t& reg, uint8_t *const data, unsigned length) {
auto reg_ptr = reinterpret_cast<uint8_t*>(&reg);
switch (offs & 0x3) {
case 0:
for (auto i = 0U; i < length; ++i)
*(data + i) = *(reg_ptr + i);
break;
case 1:
for (auto i = 0U; i < length; ++i)
*(data + i) = *(reg_ptr + 1 + i);
break;
case 2:
for (auto i = 0U; i < length; ++i)
*(data + i) = *(reg_ptr + 2 + i);
break;
case 3:
*data = *(reg_ptr + 3);
break;
}
}
void write_uint32(uint64_t offs, uint32_t& reg, const uint8_t *const data, unsigned length) {
auto reg_ptr = reinterpret_cast<uint8_t*>(&reg);
switch (offs & 0x3) {
case 0:
for (auto i = 0U; i < length; ++i)
*(reg_ptr + i) = *(data + i);
break;
case 1:
for (auto i = 0U; i < length; ++i)
*(reg_ptr + 1 + i) = *(data + i);
break;
case 2:
for (auto i = 0U; i < length; ++i)
*(reg_ptr + 2 + i) = *(data + i);
break;
case 3:
*(reg_ptr + 3) = *data ;
break;
}
}
template<typename BASE, features_e FEAT>
iss::status riscv_hart_mu_p<BASE, FEAT>::read_clic(uint64_t addr, unsigned length, uint8_t *const data) {
if(addr==cfg.clic_base) { // cliccfg
if(addr==clic_base_addr) { // cliccfg
*data=clic_cfg_reg;
for(auto i=1; i<length; ++i) *(data+i)=0;
} else if(addr>=(cfg.clic_base+4) && (addr+length)<=(cfg.clic_base+8)){ // clicinfo
read_reg_uint32(addr, clic_info_reg, data, length);
} else if(addr>=(cfg.clic_base+0x40) && (addr+length)<=(cfg.clic_base+0x40+cfg.clic_num_trigger*4)){ // clicinttrig
} else if(addr>=(clic_base_addr+4) && (addr+length)<=(clic_base_addr+8)){ // clicinfo
read_uint32(addr, clic_info_reg, data, length);
} else if(addr>=(clic_base_addr+0x40) && (addr+length)<=(clic_base_addr+0x40+clic_num_trigger*4)){ // clicinttrig
auto offset = ((addr&0x7fff)-0x40)/4;
read_reg_uint32(addr, clic_inttrig_reg[offset], data, length);
} else if(addr>=(cfg.clic_base+0x1000) && (addr+length)<=(cfg.clic_base+0x1000+cfg.clic_num_irq*4)){ // clicintip/clicintie/clicintattr/clicintctl
read_uint32(addr, clic_inttrig_reg[offset], data, length);
} else if(addr>=(clic_base_addr+0x1000) && (addr+length)<=(clic_base_addr+clic_num_irq*4)){ // clicintip/clicintie/clicintattr/clicintctl
auto offset = ((addr&0x7fff)-0x1000)/4;
read_reg_uint32(addr, clic_int_reg[offset].raw, data, length);
read_uint32(addr, clic_int_reg[offset].raw, data, length);
} else {
for(auto i = 0U; i<length; ++i) *(data+i)=0;
}
@ -1250,17 +1220,17 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read_clic(uint64_t addr, unsigned lengt
template<typename BASE, features_e FEAT>
iss::status riscv_hart_mu_p<BASE, FEAT>::write_clic(uint64_t addr, unsigned length, const uint8_t *const data) {
if(addr==cfg.clic_base) { // cliccfg
if(addr==clic_base_addr) { // cliccfg
clic_cfg_reg = *data;
clic_cfg_reg&= 0x7e;
// } else if(addr>=(cfg.clic_base+4) && (addr+length)<=(cfg.clic_base+4)){ // clicinfo
clic_cfg_reg&= 0x7f;
// } else if(addr>=(clic_base_addr+4) && (addr+length)<=(clic_base_addr+4)){ // clicinfo
// write_uint32(addr, clic_info_reg, data, length);
} else if(addr>=(cfg.clic_base+0x40) && (addr+length)<=(cfg.clic_base+0x40+cfg.clic_num_trigger*4)){ // clicinttrig
} else if(addr>=(clic_base_addr+0x40) && (addr+length)<=(clic_base_addr+0xC0)){ // clicinttrig
auto offset = ((addr&0x7fff)-0x40)/4;
write_reg_uint32(addr, clic_inttrig_reg[offset], data, length);
} else if(addr>=(cfg.clic_base+0x1000) && (addr+length)<=(cfg.clic_base+0x1000+cfg.clic_num_irq*4)){ // clicintip/clicintie/clicintattr/clicintctl
write_uint32(addr, clic_inttrig_reg[offset], data, length);
} else if(addr>=(clic_base_addr+0x1000) && (addr+length)<=(clic_base_addr+clic_num_irq*4)){ // clicintip/clicintie/clicintattr/clicintctl
auto offset = ((addr&0x7fff)-0x1000)/4;
write_reg_uint32(addr, clic_int_reg[offset].raw, data, length);
write_uint32(addr, clic_int_reg[offset].raw, data, length);
}
return iss::Ok;
}
@ -1288,19 +1258,19 @@ template <typename BASE, features_e FEAT> void riscv_hart_mu_p<BASE, FEAT>::chec
enabled_interrupts >>= 1;
res++;
}
this->pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
this->reg.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->trap_state;
if(flags==std::numeric_limits<uint64_t>::max()) flags=this->reg.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
unsigned new_priv = PRIV_M;
auto new_priv = PRIV_M;
if (trap_id == 0) { // exception
if (this->reg.PRIV != PRIV_M && ((csr[medeleg] >> cause) & 0x1) != 0)
new_priv = PRIV_U;
@ -1321,13 +1291,10 @@ 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:
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;
}
//TODO: implement debug mode behavior
// csr[dpc] = addr;
// csr[dcsr] = (csr[dcsr] & ~0x1c3) | (1<<6) | PRIV_M; //FIXME: cause should not be 4 (stepi)
csr[utval | (new_priv << 8)] = 0;
break;
case 4:
case 6:
@ -1342,10 +1309,10 @@ 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->pending_trap = 0;
this->reg.pending_trap = 0;
}
size_t adr = ucause | (new_priv << 8);
csr[adr] = (trap_id << (traits<BASE>::XLEN-1)) + cause;
csr[adr] = (trap_id << 31) + cause;
// update mstatus
// xPP field of mstatus is written with the active privilege mode at the time
// of the trap; the x PIE field of mstatus
@ -1382,7 +1349,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->trap_state = 0;
this->reg.trap_state = 0;
return this->reg.NEXT_PC;
}
@ -1391,7 +1358,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->trap_state = trap_val;
this->reg.trap_state = trap_val;
this->reg.NEXT_PC = std::numeric_limits<uint32_t>::max();
} else {
auto status = state.mstatus;

View File

@ -53,12 +53,17 @@ 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, CSR_SIZE=4096, INSTR_ALIGNMENT=2, fence=0, fencei=1, fencevmal=2, fencevmau=3, 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
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
};
using reg_t = uint32_t;
@ -71,11 +76,11 @@ template <> struct traits<tgc_c> {
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
static constexpr std::array<const uint32_t, 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_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_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 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 const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
@ -192,7 +197,7 @@ struct tgc_c: public arch_if {
uint8_t* get_regs_base_ptr() override;
inline uint64_t get_icount() { return icount; }
inline uint64_t get_icount() { return reg.icount; }
inline bool should_stop() { return interrupt_sim; }
@ -210,9 +215,9 @@ struct tgc_c: public arch_if {
virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
inline uint32_t get_last_branch() { return last_branch; }
inline uint32_t get_last_branch() { return reg.last_branch; }
protected:
#pragma pack(push, 1)
struct TGC_C_regs {
uint32_t X0 = 0;
@ -251,14 +256,13 @@ 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 cycle = 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

@ -1,43 +0,0 @@
#ifndef _ISS_ARCH_TGC_MAPPER_H
#define _ISS_ARCH_TGC_MAPPER_H
#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_B
#include "riscv_hart_m_p.h"
#include "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"
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"
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"
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"
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"
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"
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
#endif

View File

@ -214,26 +214,12 @@ template <typename ARCH> status riscv_target_adapter<ARCH>::write_registers(cons
auto start_reg=arch::traits<ARCH>::X0;
auto *reg_base = core->get_regs_base_ptr();
auto iter = data.data();
bool e_ext = arch::traits<ARCH>::PC<32;
for (size_t reg_no = 0; reg_no < start_reg+33/*arch::traits<ARCH>::NUM_REGS*/; ++reg_no) {
if(e_ext && reg_no>15){
if(reg_no==32){
auto reg_width = arch::traits<ARCH>::reg_bit_widths[arch::traits<ARCH>::PC] / 8;
auto offset = traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC];
std::copy(iter, iter + reg_width, reg_base);
} else {
const uint64_t zero_val=0;
auto reg_width = arch::traits<ARCH>::reg_bit_widths[15] / 8;
auto iter = (uint8_t*)&zero_val;
std::copy(iter, iter + reg_width, reg_base);
}
} else {
auto reg_width = arch::traits<ARCH>::reg_bit_widths[reg_no] / 8;
auto offset = traits<ARCH>::reg_byte_offsets[reg_no];
std::copy(iter, iter + reg_width, reg_base);
iter += 4;
reg_base += offset;
}
auto reg_width = arch::traits<ARCH>::reg_bit_widths[reg_no] / 8;
auto offset = traits<ARCH>::reg_byte_offsets[reg_no];
std::copy(iter, iter + reg_width, reg_base);
iter += 4;
reg_base += offset;
}
return Ok;
}

View File

@ -37,9 +37,9 @@
#include "iss/instrumentation_if.h"
#include "iss/vm_plugin.h"
#include <json/json.h>
#include <string>
#include <unordered_map>
#include <vector>
namespace iss {
@ -49,13 +49,11 @@ class cycle_estimate: public iss::vm_plugin {
BEGIN_BF_DECL(instr_desc, uint32_t)
BF_FIELD(taken, 24, 8)
BF_FIELD(not_taken, 16, 8)
BF_FIELD(is_branch, 8, 8)
BF_FIELD(size, 0, 8)
instr_desc(uint32_t size, uint32_t taken, uint32_t not_taken, bool branch): instr_desc() {
BF_FIELD(size, 0, 16)
instr_desc(uint32_t size, uint32_t taken, uint32_t not_taken): instr_desc() {
this->size=size;
this->taken=taken;
this->not_taken=not_taken;
this->is_branch=branch;
}
END_BF_DECL();
@ -66,7 +64,7 @@ public:
cycle_estimate(const cycle_estimate &&) = delete;
cycle_estimate(std::string const& config_file_name);
cycle_estimate(std::string config_file_name);
virtual ~cycle_estimate();
@ -81,7 +79,7 @@ public:
void callback(instr_info_t instr_info, exec_info const&) override;
private:
iss::instrumentation_if *instr_if;
iss::instrumentation_if *arch_instr;
std::vector<instr_desc> delays;
struct pair_hash {
size_t operator()(const std::pair<uint64_t, uint64_t> &p) const {
@ -90,7 +88,7 @@ private:
}
};
std::unordered_map<std::pair<uint64_t, uint64_t>, uint64_t, pair_hash> blocks;
std::string config_file_name;
Json::Value root;
};
}
}

View File

@ -1,102 +0,0 @@
/*******************************************************************************
* Copyright (C) 2017, 2018, MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Contributors:
* eyck@minres.com - initial API and implementation
******************************************************************************/
#ifndef _ISS_PLUGIN_COV_H_
#define _ISS_PLUGIN_COV_H_
#include <iss/vm_plugin.h>
#include "iss/instrumentation_if.h"
#include <json/json.h>
#include <string>
#include <fstream>
namespace iss {
namespace plugin {
class lz4compress_steambuf;
class cov : public iss::vm_plugin {
struct instr_delay {
std::string instr_name;
size_t size;
size_t not_taken_delay;
size_t taken_delay;
};
BEGIN_BF_DECL(instr_desc, uint32_t)
BF_FIELD(taken, 24, 8)
BF_FIELD(not_taken, 16, 8)
BF_FIELD(is_branch, 8, 8)
BF_FIELD(size, 0, 8)
instr_desc(uint32_t size, uint32_t taken, uint32_t not_taken, bool branch): instr_desc() {
this->size=size;
this->taken=taken;
this->not_taken=not_taken;
this->is_branch=branch;
}
END_BF_DECL();
public:
cov(const cov &) = delete;
cov(const cov &&) = delete;
cov(std::string const &);
virtual ~cov();
cov &operator=(const cov &) = delete;
cov &operator=(const cov &&) = delete;
bool registration(const char *const version, vm_if &arch) override;
sync_type get_sync() override { return POST_SYNC; };
void callback(instr_info_t, exec_info const&) override;
private:
iss::instrumentation_if *instr_if {nullptr};
std::ofstream output;
#ifdef WITH_LZ4
std::unique_ptr<lz4compress_steambuf> strbuf;
std::ostream ostr;
#endif
std::string filename;
std::vector<instr_desc> delays;
bool jumped{false}, first{true};
};
}
}
#endif /* _ISS_PLUGIN_COV_H_ */

View File

@ -41,10 +41,12 @@ 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, 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;
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;
tgc_c::tgc_c() = default;
tgc_c::tgc_c() {
reg.icount = 0;
}
tgc_c::~tgc_c() = default;
@ -55,8 +57,8 @@ void tgc_c::reset(uint64_t address) {
reg.PC=address;
reg.NEXT_PC=reg.PC;
reg.PRIV=0x3;
trap_state=0;
icount=0;
reg.trap_state=0;
reg.icount=0;
}
uint8_t *tgc_c::get_regs_base_ptr() {

View File

@ -35,14 +35,31 @@
#include <boost/lexical_cast.hpp>
#include <boost/program_options.hpp>
#include <iss/arch/tgc_mapper.h>
#include <iss/arch/riscv_hart_m_p.h>
#include "iss/arch/riscv_hart_m_p.h"
#include "iss/arch/tgc_c.h"
using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>;
#ifdef CORE_TGC_B
#include "iss/arch/riscv_hart_m_p.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_D
#include "iss/arch/riscv_hart_mu_p.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 "iss/arch/riscv_hart_mu_p.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 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>
@ -60,13 +77,13 @@ int main(int argc, char *argv[]) {
desc.add_options()
("help,h", "Print help message")
("verbose,v", po::value<int>()->implicit_value(0), "Sets logging verbosity")
("logfile,l", po::value<std::string>(), "Sets default log file.")
("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,f", po::value<std::vector<std::string>>(), "ELF file(s) to load")
("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")
@ -125,12 +142,6 @@ int main(int argc, char *argv[]) {
iss::create_cpu<tgc_b_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
} else
#endif
#ifdef CORE_TGC_C_XRB_NN
if (isa_opt == "tgc_c_xrb_nn") {
std::tie(cpu, vm) =
iss::create_cpu<tgc_c_xrb_nn_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
} else
#endif
#ifdef CORE_TGC_D
if (isa_opt == "tgc_d") {
std::tie(cpu, vm) =
@ -142,21 +153,9 @@ int main(int argc, char *argv[]) {
std::tie(cpu, vm) =
iss::create_cpu<tgc_d_xrb_mac_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
} else
#endif
#ifdef CORE_TGC_D_XRB_NN
if (isa_opt == "tgc_d_xrb_nn") {
std::tie(cpu, vm) =
iss::create_cpu<tgc_d_xrb_nn_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
} else
#endif
#ifdef CORE_TGC_E
if (isa_opt == "tgc_e") {
std::tie(cpu, vm) =
iss::create_cpu<tgc_e_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
} else
#endif
{
LOG(ERR) << "Illegal argument value for '--isa': " << isa_opt << std::endl;
LOG(ERR) << "Illegal argument value for '--isa': " << clim["isa"].as<std::string>() << std::endl;
return 127;
}
if (clim.count("plugin")) {
@ -176,11 +175,7 @@ int main(int argc, char *argv[]) {
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 {
} 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());

View File

@ -36,83 +36,59 @@
#include <iss/arch_if.h>
#include <util/logging.h>
#include <rapidjson/document.h>
#include <rapidjson/istreamwrapper.h>
#include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h"
#include <rapidjson/ostreamwrapper.h>
#include <rapidjson/error/en.h>
#include <fstream>
using namespace rapidjson;
using namespace std;
iss::plugin::cycle_estimate::cycle_estimate(string const& config_file_name)
: instr_if(nullptr)
, config_file_name(config_file_name)
iss::plugin::cycle_estimate::cycle_estimate(std::string config_file_name)
: arch_instr(nullptr)
{
if (config_file_name.length() > 0) {
std::ifstream is(config_file_name);
if (is.is_open()) {
try {
is >> root;
} catch (Json::RuntimeError &e) {
LOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
}
} else {
LOG(ERR) << "Could not open input file " << config_file_name;
}
}
}
iss::plugin::cycle_estimate::~cycle_estimate() {
}
bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if& vm) {
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()) {
try {
IStreamWrapper isw(is);
Document d;
ParseResult ok = d.ParseStream(isw);
if(ok) {
Value& val = d[core_name.c_str()];
if(val.IsArray()){
delays.reserve(val.Size());
for (auto it = val.Begin(); it != val.End(); ++it) {
auto& name = (*it)["name"];
auto& size = (*it)["size"];
auto& delay = (*it)["delay"];
auto& branch = (*it)["branch"];
if(delay.IsArray()) {
auto dt = delay[0].Get<unsigned>();
auto dnt = delay[1].Get<unsigned>();
delays.push_back(instr_desc{size.Get<unsigned>(), dt, dnt, branch.Get<bool>()});
} else if(delay.Is<unsigned>()) {
auto d = delay.Get<unsigned>();
delays.push_back(instr_desc{size.Get<unsigned>(), d, d, branch.Get<bool>()});
} else
throw runtime_error("JSON parse error");
}
} else {
LOG(ERR)<<"plugin cycle_estimate: could not find an entry for "<<core_name<<" in JSON file"<<endl;
return false;
}
} else {
LOG(ERR)<<"plugin cycle_estimate: could not parse in JSON file at "<< ok.Offset()<<": "<<GetParseError_En(ok.Code())<<endl;
return false;
}
} catch (runtime_error &e) {
LOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
return false;
}
} else {
LOG(ERR) << "Could not open input file " << config_file_name;
return false;
}
arch_instr = vm.get_arch()->get_instrumentation_if();
if(!arch_instr) return false;
const std::string core_name = arch_instr->core_type_name();
Json::Value &val = root[core_name];
if(!val.isNull() && val.isArray()){
delays.reserve(val.size());
for(auto it:val){
auto name = it["name"];
auto size = it["size"];
auto delay = it["delay"];
if(!name.isString() || !size.isUInt() || !(delay.isUInt() || delay.isArray())) throw std::runtime_error("JSON parse error");
if(delay.isUInt()){
delays.push_back(instr_desc{size.asUInt(), delay.asUInt(), 0});
} else {
delays.push_back(instr_desc{size.asUInt(), delay[0].asUInt(), delay[1].asUInt()});
}
}
} else {
LOG(ERR)<<"plugin cycle_estimate: could not find an entry for "<<core_name<<" in JSON file"<<std::endl;
}
return true;
return true;
}
void iss::plugin::cycle_estimate::callback(instr_info_t instr_info, exec_info const& exc_info) {
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))
instr_if->set_curr_instr_cycles(entry.taken);
void iss::plugin::cycle_estimate::callback(instr_info_t instr_info, exec_info const&) {
assert(arch_instr && "No instrumentation interface available but callback executed");
auto entry = delays[instr_info.instr_id];
bool taken = (arch_instr->get_next_pc()-arch_instr->get_pc()) != (entry.size/8);
if (taken && entry.taken > 1)
arch_instr->set_curr_instr_cycles(entry.taken);
else if (entry.not_taken > 1)
instr_if->set_curr_instr_cycles(entry.not_taken);
arch_instr->set_curr_instr_cycles(entry.not_taken);
}

View File

@ -1,180 +0,0 @@
#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
cov::cov(std::string const &filename)
: instr_if(nullptr)
, filename(filename)
, output("output.trc")
#ifdef WITH_LZ4
, strbuf(new lz4compress_steambuf(output, 4096))
, ostr(strbuf.get())
#endif
{ }
cov::~cov() { }
bool cov::registration(const char *const version, vm_if& vm) {
instr_if = vm.get_arch()->get_instrumentation_if();
if(!instr_if) return false;
const string core_name = instr_if->core_type_name();
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 cov::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

@ -31,15 +31,32 @@
*******************************************************************************/
// 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/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>
#include <iss/arch/tgc_mapper.h>
#include "sysc/core_complex.h"
#ifdef CORE_TGC_B
#include "iss/arch/riscv_hart_m_p.h"
#include "iss/arch/tgc_b.h"
using tgc_b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_b>;
#endif
#include "iss/arch/riscv_hart_m_p.h"
#include "iss/arch/tgc_c.h"
using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>;
#ifdef CORE_TGC_D
#include "iss/arch/riscv_hart_mu_p.h"
#include "iss/arch/tgc_d.h"
using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d, iss::arch::FEAT_PMP>;
#endif
#ifdef CORE_TGC_D_XRB_MAC
#include "iss/arch/riscv_hart_mu_p.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::FEAT_PMP>;
#endif
#include <scc/report.h>
#include <util/ities.h>
#include <iostream>
@ -47,8 +64,6 @@
#include <array>
#include <iss/plugin/cycle_estimate.h>
#include <iss/plugin/instruction_count.h>
#include <iss/plugin/pctrace.h>
// clang-format on
#define STR(X) #X
@ -105,7 +120,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->icount);
if (p == iss::arch_if::ISTART) owner->sync(this->reg.icount);
}
sync_type needed_sync() const override { return PRE_SYNC; }
@ -114,8 +129,7 @@ public:
if (!owner->disass_output(pc, instr)) {
std::stringstream s;
s << "[p:" << lvl[this->reg.PRIV] << ";s:0x" << std::hex << std::setfill('0')
<< std::setw(sizeof(reg_t) * 2) << (reg_t)this->state.mstatus << std::dec << ";c:"
<< this->icount + this->cycle_offset << "]";
<< std::setw(sizeof(reg_t) * 2) << (reg_t)this->state.mstatus << std::dec << ";c:" << this->reg.icount << "]";
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 +189,9 @@ public:
void wait_until(uint64_t flags) override {
SCCDEBUG(owner->name()) << "Sleeping until interrupt";
while(this->pending_trap == 0 && (this->csr[arch::mip] & this->csr[arch::mie]) == 0) {
do {
sc_core::wait(wfi_evt);
}
} while (this->reg.pending_trap == 0);
PLAT::wait_until(flags);
}
@ -204,7 +218,7 @@ public:
this->csr[arch::mip] &= ~mask;
this->check_interrupt();
if(value)
SCCTRACE(owner->name()) << "Triggering interrupt " << id << " Pending trap: " << this->pending_trap;
SCCTRACE(owner->name()) << "Triggering interrupt " << id << " Pending trap: " << this->reg.pending_trap;
}
private:
@ -289,11 +303,8 @@ public:
#ifdef CORE_TGC_D
CREATE_CORE(tgc_d)
#endif
#ifdef CORE_TGC_D_XRB_MAC
#ifdef CORE_TGC_D_XRB_MACD
CREATE_CORE(tgc_d_xrb_mac)
#endif
#ifdef CORE_TGC_D_XRB_NN
CREATE_CORE(tgc_d_xrb_nn)
#endif
{
LOG(ERR) << "Illegal argument value for core type: " << type << std::endl;
@ -404,10 +415,6 @@ void core_complex::before_end_of_elaboration() {
auto *plugin = new iss::plugin::cycle_estimate(filename);
cpu->vm->register_plugin(*plugin);
plugin_list.push_back(plugin);
} else if (plugin_name == "pctrace") {
auto *plugin = new iss::plugin::cov(filename);
cpu->vm->register_plugin(*plugin);
plugin_list.push_back(plugin);
} else {
std::array<char const*, 1> a{{filename.c_str()}};
iss::plugin::loader l(plugin_name, {{"initPlugin"}});

File diff suppressed because it is too large Load Diff