Compare commits
	
		
			40 Commits
		
	
	
		
			8b6e3abd23
			...
			feature/re
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 58311b37db | |||
| ad8dc09bee | |||
| 2bba5645c3 | |||
| bf0a5a80de | |||
| b37ef973de | |||
| 4c363f4073 | |||
| b8fa5fbbda | |||
| ac86f14a54 | |||
| 68b5697c8f | |||
| 09b0f0d0c8 | |||
| 98b418ff43 | |||
| 059bd0d371 | |||
| ef2a4df925 | |||
| 7578906310 | |||
| afe8905ac9 | |||
| ecc6091d1e | |||
| 3563ba80d0 | |||
| 09955be90f | |||
| dd4c19a15c | |||
| 07d5af1dde | |||
| 6f8595759e | |||
| 86da31033c | |||
| 974d103381 | |||
| 309758b994 | |||
| 965929d1eb | |||
| d47375a70e | |||
| d31b4ef5a8 | |||
| 7452c5df43 | |||
| 43d7b99905 | |||
| f90c48e881 | |||
| 2d7973520b | |||
| fd98ad95f6 | |||
| bfa8166223 | |||
| c42e336509 | |||
| 49d09a05d7 | |||
| 459794b863 | |||
| 039746112b | |||
| ac6d7ea5d4 | |||
| a89f00da19 | |||
| ff04ee7807 | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -32,3 +32,4 @@ language.settings.xml
 | 
			
		||||
/dump.json
 | 
			
		||||
/src-gen/
 | 
			
		||||
/*.yaml
 | 
			
		||||
/*.json
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ project(dbt-rise-tgc VERSION 1.0.0)
 | 
			
		||||
include(GNUInstallDirs)
 | 
			
		||||
 | 
			
		||||
find_package(elfio)
 | 
			
		||||
find_package(Boost COMPONENTS coroutine)
 | 
			
		||||
 | 
			
		||||
if(WITH_LLVM)
 | 
			
		||||
    if(DEFINED ENV{LLVM_HOME})
 | 
			
		||||
@@ -28,16 +29,20 @@ endif()
 | 
			
		||||
add_subdirectory(softfloat)
 | 
			
		||||
 | 
			
		||||
# library files
 | 
			
		||||
FILE(GLOB TGC_SOURCES
 | 
			
		||||
    ${CMAKE_CURRENT_SOURCE_DIR}/src/iss/*.cpp 
 | 
			
		||||
    ${CMAKE_CURRENT_SOURCE_DIR}/src/vm/interp/vm_*.cpp
 | 
			
		||||
)
 | 
			
		||||
FILE(GLOB TGC_SOURCES    ${CMAKE_CURRENT_SOURCE_DIR}/src/iss/*.cpp) 
 | 
			
		||||
FILE(GLOB TGC_VM_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/vm/interp/vm_*.cpp)
 | 
			
		||||
 | 
			
		||||
set(LIB_SOURCES 
 | 
			
		||||
    src/vm/fp_functions.cpp
 | 
			
		||||
    src/plugin/instruction_count.cpp
 | 
			
		||||
    src/plugin/cycle_estimate.cpp
 | 
			
		||||
    src/plugin/pctrace.cpp
 | 
			
		||||
    
 | 
			
		||||
    ${TGC_SOURCES}
 | 
			
		||||
    ${TGC_VM_SOURCES}
 | 
			
		||||
)
 | 
			
		||||
if(TARGET RapidJSON)
 | 
			
		||||
    list(APPEND LIB_SOURCES src/plugin/cycle_estimate.cpp)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
if(WITH_LLVM)
 | 
			
		||||
	FILE(GLOB TGC_LLVM_SOURCES
 | 
			
		||||
@@ -66,7 +71,7 @@ elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
 | 
			
		||||
    target_compile_options(${PROJECT_NAME} PRIVATE /wd4293)
 | 
			
		||||
endif()
 | 
			
		||||
target_include_directories(${PROJECT_NAME} PUBLIC incl)
 | 
			
		||||
target_link_libraries(${PROJECT_NAME} PUBLIC softfloat scc-util jsoncpp)
 | 
			
		||||
target_link_libraries(${PROJECT_NAME} PUBLIC softfloat scc-util jsoncpp Boost::coroutine)
 | 
			
		||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
 | 
			
		||||
    target_link_libraries(${PROJECT_NAME} PUBLIC -Wl,--whole-archive dbt-core -Wl,--no-whole-archive)
 | 
			
		||||
else()
 | 
			
		||||
@@ -79,6 +84,10 @@ elseif(TARGET elfio::elfio)
 | 
			
		||||
else()
 | 
			
		||||
    message(FATAL_ERROR "No elfio library found, maybe a find_package() call is missing")
 | 
			
		||||
endif()
 | 
			
		||||
if(TARGET RapidJSON)
 | 
			
		||||
    target_link_libraries(${PROJECT_NAME} PUBLIC RapidJSON)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
set_target_properties(${PROJECT_NAME} PROPERTIES
 | 
			
		||||
  VERSION ${PROJECT_VERSION}
 | 
			
		||||
@@ -105,8 +114,12 @@ project(tgc-sim)
 | 
			
		||||
find_package(Boost COMPONENTS program_options thread REQUIRED)
 | 
			
		||||
 | 
			
		||||
add_executable(${PROJECT_NAME} src/main.cpp)
 | 
			
		||||
# This sets the include directory for the reference project. This is the -I flag in gcc.
 | 
			
		||||
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
 | 
			
		||||
foreach(F IN LISTS TGC_SOURCES)
 | 
			
		||||
    string(REGEX REPLACE  ".*/([^/]*)\.cpp"  "\\1" CORE_NAME_LC ${F})
 | 
			
		||||
    string(TOUPPER ${CORE_NAME_LC} CORE_NAME)
 | 
			
		||||
    target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
 | 
			
		||||
endforeach()
 | 
			
		||||
 | 
			
		||||
if(WITH_LLVM)
 | 
			
		||||
    target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_LLVM)
 | 
			
		||||
    target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
 | 
			
		||||
@@ -114,9 +127,9 @@ endif()
 | 
			
		||||
# Links the target exe against the libraries
 | 
			
		||||
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc)
 | 
			
		||||
if(TARGET Boost::program_options)
 | 
			
		||||
    target_link_libraries(${PROJECT_NAME} PUBLIC Boost::program_options Boost::thread)
 | 
			
		||||
    target_link_libraries(${PROJECT_NAME} PUBLIC Boost::program_options)
 | 
			
		||||
else()
 | 
			
		||||
    target_link_libraries(${PROJECT_NAME} PUBLIC ${BOOST_program_options_LIBRARY} ${BOOST_thread_LIBRARY})
 | 
			
		||||
    target_link_libraries(${PROJECT_NAME} PUBLIC ${BOOST_program_options_LIBRARY})
 | 
			
		||||
endif()
 | 
			
		||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${CMAKE_DL_LIBS})
 | 
			
		||||
if (Tcmalloc_FOUND)
 | 
			
		||||
@@ -142,15 +155,11 @@ if(SystemC_FOUND)
 | 
			
		||||
    add_library(${PROJECT_NAME} src/sysc/core_complex.cpp)
 | 
			
		||||
    target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_SYSTEMC)
 | 
			
		||||
    target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
 | 
			
		||||
    if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss/arch/tgc_b.h)
 | 
			
		||||
        target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_TGC_B)
 | 
			
		||||
    endif()
 | 
			
		||||
    if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss/arch/tgc_c.h)
 | 
			
		||||
        target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_TGC_C)
 | 
			
		||||
    endif()
 | 
			
		||||
    if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss/arch/tgc_d.h)
 | 
			
		||||
        target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_TGC_D)
 | 
			
		||||
    endif()
 | 
			
		||||
    foreach(F IN LISTS TGC_SOURCES)
 | 
			
		||||
        string(REGEX REPLACE  ".*/([^/]*)\.cpp"  "\\1" CORE_NAME_LC ${F})
 | 
			
		||||
        string(TOUPPER ${CORE_NAME_LC} CORE_NAME)
 | 
			
		||||
        target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
 | 
			
		||||
    endforeach()
 | 
			
		||||
    target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc scc)
 | 
			
		||||
    if(WITH_LLVM)
 | 
			
		||||
        target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
 | 
			
		||||
 
 | 
			
		||||
 Submodule gen_input/CoreDSL-Instruction-Set-Description deleted from e7aaec6ad9
									
								
							@@ -1,14 +0,0 @@
 | 
			
		||||
import "CoreDSL-Instruction-Set-Description/RV32I.core_desc"
 | 
			
		||||
import "CoreDSL-Instruction-Set-Description/RVM.core_desc"
 | 
			
		||||
import "CoreDSL-Instruction-Set-Description/RVC.core_desc"
 | 
			
		||||
 | 
			
		||||
Core TGC_B provides RV32I, Zicsr, Zifencei {
 | 
			
		||||
	architectural_state {
 | 
			
		||||
        XLEN=32;
 | 
			
		||||
        // definitions for the architecture wrapper
 | 
			
		||||
        //                    XL    ZYXWVUTSRQPONMLKJIHGFEDCBA
 | 
			
		||||
        unsigned MISA_VAL = 0b01000000000000000000000100000000;
 | 
			
		||||
        unsigned MARCHID_VAL = 0x80000002;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1,13 +0,0 @@
 | 
			
		||||
import "CoreDSL-Instruction-Set-Description/RV32I.core_desc"
 | 
			
		||||
import "CoreDSL-Instruction-Set-Description/RVM.core_desc"
 | 
			
		||||
import "CoreDSL-Instruction-Set-Description/RVC.core_desc"
 | 
			
		||||
 | 
			
		||||
Core TGC_D provides RV32I, Zicsr, Zifencei, RV32M, RV32IC {
 | 
			
		||||
    architectural_state {
 | 
			
		||||
        XLEN=32;
 | 
			
		||||
        // definitions for the architecture wrapper
 | 
			
		||||
        //                    XL    ZYXWVUTSRQPONMLKJIHGFEDCBA
 | 
			
		||||
        unsigned MISA_VAL = 0b01000000000000000001000100000100;
 | 
			
		||||
        unsigned MARCHID_VAL = 0x80000004;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,73 +0,0 @@
 | 
			
		||||
import "CoreDSL-Instruction-Set-Description/RISCVBase.core_desc"
 | 
			
		||||
import "CoreDSL-Instruction-Set-Description/RV32I.core_desc"
 | 
			
		||||
import "CoreDSL-Instruction-Set-Description/RVM.core_desc"
 | 
			
		||||
import "CoreDSL-Instruction-Set-Description/RVC.core_desc"
 | 
			
		||||
 | 
			
		||||
InstructionSet X_RB_MAC extends RISCVBase {
 | 
			
		||||
  architectural_state {
 | 
			
		||||
    register unsigned<64> ACC;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  instructions {
 | 
			
		||||
    RESET_ACC { // v-- funct7       v-- funct3
 | 
			
		||||
      encoding: 7'd0 :: 10'b0 :: 3'd0 :: 5'b0 :: 7'b0001011;
 | 
			
		||||
      behavior: ACC = 0;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    GET_ACC_LO {
 | 
			
		||||
      encoding: 7'd1 :: 10'b0 :: 3'd0 :: rd[4:0] :: 7'b0001011;
 | 
			
		||||
      behavior: if (rd != 0) X[rd] = ACC[31:0];
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    GET_ACC_HI {
 | 
			
		||||
      encoding: 7'd2 :: 10'b0 :: 3'd0 :: rd[4:0] :: 7'b0001011;
 | 
			
		||||
      behavior: if (rd != 0) X[rd] = ACC[63:32];
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    MACU_32 {
 | 
			
		||||
      encoding: 7'd0 :: rs2[4:0] :: rs1[4:0] :: 3'd1 :: 5'b0 :: 7'b0001011;
 | 
			
		||||
      behavior: {
 | 
			
		||||
        unsigned<64> mul = X[rs1]    * X[rs2];
 | 
			
		||||
        unsigned<33> add = mul[31:0] + ACC[31:0];
 | 
			
		||||
        ACC = add[31:0];
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    MACS_32 {
 | 
			
		||||
      encoding: 7'd1 :: rs2[4:0] :: rs1[4:0] :: 3'd1 :: 5'b0 :: 7'b0001011;
 | 
			
		||||
      behavior: {
 | 
			
		||||
        signed<64> mul = ((signed) X[rs1])    * ((signed) X[rs2]);
 | 
			
		||||
        signed<33> add = ((signed) mul[31:0]) + ((signed) ACC[31:0]);
 | 
			
		||||
        ACC = add[31:0]; // bit range always yields unsigned type
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    MACU_64 {
 | 
			
		||||
      encoding: 7'd0 :: rs2[4:0] :: rs1[4:0] :: 3'd2 :: 5'b0 :: 7'b0001011;
 | 
			
		||||
      behavior: {
 | 
			
		||||
        unsigned<64> mul = X[rs1] * X[rs2];
 | 
			
		||||
        unsigned<65> add = mul    + ACC;
 | 
			
		||||
        ACC = add[63:0];
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    MACS_64 {
 | 
			
		||||
      encoding: 7'd1 :: rs2[4:0] :: rs1[4:0] :: 3'd2 :: 5'b0 :: 7'b0001011;
 | 
			
		||||
      behavior: {
 | 
			
		||||
        signed<64> mul = ((signed) X[rs1]) * ((signed) X[rs2]);
 | 
			
		||||
        signed<65> add =           mul     + ((signed) ACC);
 | 
			
		||||
        ACC = add[63:0];
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Core TGC_D_XRB_MAC provides RV32I, Zicsr, Zifencei, RV32M, RV32IC, X_RB_MAC {
 | 
			
		||||
    architectural_state {
 | 
			
		||||
        XLEN=32;
 | 
			
		||||
        // definitions for the architecture wrapper
 | 
			
		||||
        //                    XL    ZYXWVUTSRQPONMLKJIHGFEDCBA
 | 
			
		||||
        unsigned MISA_VAL = 0b01000000000000000001000100000100;
 | 
			
		||||
        unsigned MARCHID_VAL = 0x80000004;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -161,7 +161,7 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
 | 
			
		||||
 | 
			
		||||
    inline uint32_t get_last_branch() { return reg.last_branch; }
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
 | 
			
		||||
#pragma pack(push, 1)
 | 
			
		||||
    struct ${coreDef.name}_regs {<%
 | 
			
		||||
        registers.each { reg -> if(reg.size>0) {%> 
 | 
			
		||||
@@ -169,7 +169,6 @@ protected:
 | 
			
		||||
        }}%>
 | 
			
		||||
        uint32_t trap_state = 0, pending_trap = 0;
 | 
			
		||||
        uint64_t icount = 0;
 | 
			
		||||
        uint64_t cycle = 0;
 | 
			
		||||
        uint64_t instret = 0;
 | 
			
		||||
        uint32_t last_branch;
 | 
			
		||||
    } reg;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,12 @@
 | 
			
		||||
{
 | 
			
		||||
	"${coreDef.name}" : [<%instructions.eachWithIndex{instr,index -> %>${index==0?"":","}
 | 
			
		||||
		{
 | 
			
		||||
			"name"  : "${instr.name}",
 | 
			
		||||
			"size"  : ${instr.length},
 | 
			
		||||
			"delay" : ${generator.hasAttribute(instr.instruction, com.minres.coredsl.coreDsl.InstrAttribute.COND)?[1,1]:1}
 | 
			
		||||
			"name"  :   "${instr.name}",
 | 
			
		||||
			"size"  :   ${instr.length},
 | 
			
		||||
			"encoding": "${instr.encoding}",
 | 
			
		||||
            "mask":     "${instr.mask}",
 | 
			
		||||
			"branch":   ${instr.modifiesPC},
 | 
			
		||||
			"delay" :   ${instr.isConditional?"[1,1]":"1"}
 | 
			
		||||
		}<%}%>
 | 
			
		||||
	]
 | 
			
		||||
}
 | 
			
		||||
@@ -29,7 +29,13 @@
 | 
			
		||||
 * POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 *
 | 
			
		||||
 *******************************************************************************/
 | 
			
		||||
<%
 | 
			
		||||
import com.minres.coredsl.util.BigIntegerWithRadix
 | 
			
		||||
 | 
			
		||||
def nativeTypeSize(int size){
 | 
			
		||||
    if(size<=8) return 8; else if(size<=16) return 16; else if(size<=32) return 32; else return 64;
 | 
			
		||||
}
 | 
			
		||||
%>
 | 
			
		||||
#include "../fp_functions.h"
 | 
			
		||||
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
 | 
			
		||||
#include <iss/arch/riscv_hart_m_p.h>
 | 
			
		||||
@@ -39,6 +45,8 @@
 | 
			
		||||
#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
 | 
			
		||||
@@ -53,6 +61,7 @@ namespace interp {
 | 
			
		||||
namespace ${coreDef.name.toLowerCase()} {
 | 
			
		||||
using namespace iss::arch;
 | 
			
		||||
using namespace iss::debugger;
 | 
			
		||||
using namespace std::placeholders;
 | 
			
		||||
 | 
			
		||||
template <typename ARCH> class vm_impl : public iss::interp::vm_base<ARCH> {
 | 
			
		||||
public:
 | 
			
		||||
@@ -124,6 +133,10 @@ protected:
 | 
			
		||||
        this->core.wait_until(type);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    using yield_t = boost::coroutines2::coroutine<void>::push_type;
 | 
			
		||||
    using coro_t = boost::coroutines2::coroutine<void>::pull_type;
 | 
			
		||||
    std::vector<coro_t> spawn_blocks;
 | 
			
		||||
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    T& pc_assign(T& val){super::ex_info.branch_taken=true; return val;}
 | 
			
		||||
    inline uint8_t readSpace1(typename super::mem_type_e space, uint64_t addr){
 | 
			
		||||
@@ -169,6 +182,17 @@ protected:
 | 
			
		||||
        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
 | 
			
		||||
@@ -190,11 +214,6 @@ private:
 | 
			
		||||
    /* instruction ${idx}: ${instr.name} */
 | 
			
		||||
    compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr){
 | 
			
		||||
        // pre execution stuff
 | 
			
		||||
        auto* PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
 | 
			
		||||
        auto NEXT_PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
 | 
			
		||||
        *PC=*NEXT_PC;
 | 
			
		||||
        auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]);
 | 
			
		||||
        *trap_state = *reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PENDING_TRAP]);
 | 
			
		||||
        if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, ${idx});
 | 
			
		||||
        <%instr.fields.eachLine{%>${it}
 | 
			
		||||
        <%}%>if(this->disass_enabled){
 | 
			
		||||
@@ -202,10 +221,13 @@ private:
 | 
			
		||||
            <%instr.disass.eachLine{%>${it}
 | 
			
		||||
            <%}%>
 | 
			
		||||
        }
 | 
			
		||||
        auto* PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
 | 
			
		||||
        auto* NEXT_PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
 | 
			
		||||
        auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]);
 | 
			
		||||
        // used registers<%instr.usedVariables.each{ k,v->
 | 
			
		||||
            if(v.isArray) {%>
 | 
			
		||||
        auto* ${k} = reinterpret_cast<uint${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${v.type.size}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}]);
 | 
			
		||||
        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
 | 
			
		||||
@@ -213,6 +235,7 @@ private:
 | 
			
		||||
        <%instr.behavior.eachLine{%>${it}
 | 
			
		||||
        <%}%>} catch(...){}
 | 
			
		||||
        // post execution stuff
 | 
			
		||||
        process_spawn_blocks();
 | 
			
		||||
        if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, ${idx});
 | 
			
		||||
        // trap check
 | 
			
		||||
        if(*trap_state!=0){
 | 
			
		||||
@@ -329,6 +352,8 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
 | 
			
		||||
            auto f = decode_inst(insn);
 | 
			
		||||
            auto old_pc = pc.val;
 | 
			
		||||
            pc = (this->*f)(pc, insn);
 | 
			
		||||
            this->core.reg.PC = this->core.reg.NEXT_PC;
 | 
			
		||||
            this->core.reg.trap_state = this->core.reg.pending_trap;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return pc;
 | 
			
		||||
 
 | 
			
		||||
@@ -43,6 +43,8 @@ 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};
 | 
			
		||||
 | 
			
		||||
enum riscv_csr {
 | 
			
		||||
    /* user-level CSR */
 | 
			
		||||
    // User Trap Setup
 | 
			
		||||
@@ -164,7 +166,8 @@ enum riscv_csr {
 | 
			
		||||
    // Debug Mode Registers
 | 
			
		||||
    dcsr = 0x7B0,
 | 
			
		||||
    dpc = 0x7B1,
 | 
			
		||||
    dscratch = 0x7B2
 | 
			
		||||
    dscratch0 = 0x7B2,
 | 
			
		||||
    dscratch1 = 0x7B3
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -66,7 +66,7 @@
 | 
			
		||||
namespace iss {
 | 
			
		||||
namespace arch {
 | 
			
		||||
 | 
			
		||||
template <typename BASE> class riscv_hart_m_p : public BASE {
 | 
			
		||||
template <typename BASE, features_e FEAT=FEAT_NONE> class riscv_hart_m_p : public BASE {
 | 
			
		||||
protected:
 | 
			
		||||
    const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
 | 
			
		||||
    const std::array<const char *, 16> trap_str = {{""
 | 
			
		||||
@@ -92,7 +92,7 @@ protected:
 | 
			
		||||
         "User external interrupt", "Supervisor external interrupt", "Reserved", "Machine external interrupt"}};
 | 
			
		||||
public:
 | 
			
		||||
    using core = BASE;
 | 
			
		||||
    using this_class = riscv_hart_m_p<BASE>;
 | 
			
		||||
    using this_class = riscv_hart_m_p<BASE, FEAT>;
 | 
			
		||||
    using phys_addr_t = typename core::phys_addr_t;
 | 
			
		||||
    using reg_t = typename core::reg_t;
 | 
			
		||||
    using addr_t = typename core::addr_t;
 | 
			
		||||
@@ -201,7 +201,7 @@ public:
 | 
			
		||||
 | 
			
		||||
    void disass_output(uint64_t pc, const std::string instr) override {
 | 
			
		||||
        CLOG(INFO, disass) << fmt::format("0x{:016x}    {:40} [s:0x{:x};c:{}]",
 | 
			
		||||
                pc, instr, (reg_t)state.mstatus, this->reg.icount);
 | 
			
		||||
                pc, instr, (reg_t)state.mstatus, this->reg.icount + cycle_offset);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
 | 
			
		||||
@@ -218,10 +218,13 @@ 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 {
 | 
			
		||||
 | 
			
		||||
        riscv_instrumentation_if(riscv_hart_m_p<BASE> &arch)
 | 
			
		||||
        riscv_instrumentation_if(riscv_hart_m_p<BASE, FEAT> &arch)
 | 
			
		||||
        : arch(arch) {}
 | 
			
		||||
        /**
 | 
			
		||||
         * get the name of this architecture
 | 
			
		||||
@@ -230,13 +233,17 @@ protected:
 | 
			
		||||
         */
 | 
			
		||||
        const std::string core_type_name() const override { return traits<BASE>::core_type; }
 | 
			
		||||
 | 
			
		||||
        virtual uint64_t get_pc() { return arch.get_pc(); };
 | 
			
		||||
        uint64_t get_pc() override { return arch.get_pc(); };
 | 
			
		||||
 | 
			
		||||
        virtual uint64_t get_next_pc() { return arch.get_next_pc(); };
 | 
			
		||||
        uint64_t get_next_pc() override { return arch.get_next_pc(); };
 | 
			
		||||
 | 
			
		||||
        virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; };
 | 
			
		||||
        uint64_t get_instr_count() { return arch.reg.icount; }
 | 
			
		||||
 | 
			
		||||
        riscv_hart_m_p<BASE> &arch;
 | 
			
		||||
        uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
 | 
			
		||||
 | 
			
		||||
        void set_curr_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; };
 | 
			
		||||
 | 
			
		||||
        riscv_hart_m_p<BASE, FEAT> &arch;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    friend struct riscv_instrumentation_if;
 | 
			
		||||
@@ -246,6 +253,9 @@ protected:
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
    iss::status read_clic(uint64_t addr, unsigned length, uint8_t *const data);
 | 
			
		||||
    iss::status write_clic(uint64_t addr, unsigned length, const uint8_t *const data);
 | 
			
		||||
 | 
			
		||||
    virtual iss::status read_csr(unsigned addr, reg_t &val);
 | 
			
		||||
    virtual iss::status write_csr(unsigned addr, reg_t val);
 | 
			
		||||
 | 
			
		||||
@@ -270,10 +280,22 @@ protected:
 | 
			
		||||
    std::unordered_map<uint64_t, uint8_t> atomic_reservation;
 | 
			
		||||
    std::unordered_map<unsigned, rd_csr_f> csr_rd_cb;
 | 
			
		||||
    std::unordered_map<unsigned, wr_csr_f> csr_wr_cb;
 | 
			
		||||
    uint8_t clic_cfg_reg{0};
 | 
			
		||||
    uint32_t clic_info_reg{0};
 | 
			
		||||
    std::array<uint32_t, 32> clic_inttrig_reg;
 | 
			
		||||
    union clic_int_reg_t {
 | 
			
		||||
        struct{
 | 
			
		||||
            uint8_t ip;
 | 
			
		||||
            uint8_t ie;
 | 
			
		||||
            uint8_t attr;
 | 
			
		||||
            uint8_t ctl;
 | 
			
		||||
        };
 | 
			
		||||
        uint32_t raw;
 | 
			
		||||
    };
 | 
			
		||||
    std::vector<clic_int_reg_t> clic_int_reg;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    iss::status read_reg(unsigned addr, reg_t &val);
 | 
			
		||||
    iss::status write_reg(unsigned addr, reg_t val);
 | 
			
		||||
    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);
 | 
			
		||||
    iss::status write_null(unsigned addr, reg_t val){return iss::status::Ok;}
 | 
			
		||||
    iss::status read_cycle(unsigned addr, reg_t &val);
 | 
			
		||||
@@ -291,17 +313,29 @@ private:
 | 
			
		||||
    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);
 | 
			
		||||
    iss::status write_intthresh(unsigned addr, reg_t val);
 | 
			
		||||
    iss::status write_dcsr_dcsr(unsigned addr, reg_t val);
 | 
			
		||||
    iss::status read_dcsr_reg(unsigned addr, reg_t &val);
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    void check_interrupt();
 | 
			
		||||
    bool pmp_check(const access_type type, const uint64_t addr, const unsigned len);
 | 
			
		||||
    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>
 | 
			
		||||
riscv_hart_m_p<BASE>::riscv_hart_m_p()
 | 
			
		||||
template <typename BASE, features_e FEAT>
 | 
			
		||||
riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p()
 | 
			
		||||
: state()
 | 
			
		||||
, instr_if(*this) {
 | 
			
		||||
    // reset values
 | 
			
		||||
@@ -309,32 +343,33 @@ riscv_hart_m_p<BASE>::riscv_hart_m_p()
 | 
			
		||||
    csr[mvendorid] = 0x669;
 | 
			
		||||
    csr[marchid] = traits<BASE>::MARCHID_VAL;
 | 
			
		||||
    csr[mimpid] = 1;
 | 
			
		||||
    csr[mclicbase] = 0xc0000000; // TODO: should be taken from YAML file
 | 
			
		||||
 | 
			
		||||
    uart_buf.str("");
 | 
			
		||||
    for (unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr){
 | 
			
		||||
        csr_rd_cb[addr] = &this_class::read_null;
 | 
			
		||||
        csr_wr_cb[addr] = &this_class::write_reg;
 | 
			
		||||
        csr_wr_cb[addr] = &this_class::write_csr_reg;
 | 
			
		||||
    }
 | 
			
		||||
    for (unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr){
 | 
			
		||||
        csr_rd_cb[addr] = &this_class::read_null;
 | 
			
		||||
        csr_wr_cb[addr] = &this_class::write_reg;
 | 
			
		||||
        csr_wr_cb[addr] = &this_class::write_csr_reg;
 | 
			
		||||
    }
 | 
			
		||||
    for (unsigned addr = mhpmevent3; addr <= mhpmevent31; ++addr){
 | 
			
		||||
        csr_rd_cb[addr] = &this_class::read_null;
 | 
			
		||||
        csr_wr_cb[addr] = &this_class::write_reg;
 | 
			
		||||
        csr_wr_cb[addr] = &this_class::write_csr_reg;
 | 
			
		||||
    }
 | 
			
		||||
    for (unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr){
 | 
			
		||||
        csr_rd_cb[addr] = &this_class::read_null;
 | 
			
		||||
    }
 | 
			
		||||
    for (unsigned addr = hpmcounter3h; addr <= hpmcounter31h; ++addr){
 | 
			
		||||
        csr_rd_cb[addr] = &this_class::read_null;
 | 
			
		||||
        //csr_wr_cb[addr] = &this_class::write_reg;
 | 
			
		||||
        //csr_wr_cb[addr] = &this_class::write_csr_reg;
 | 
			
		||||
    }
 | 
			
		||||
    // common regs
 | 
			
		||||
    const std::array<unsigned, 10> addrs{{misa, mvendorid, marchid, mimpid, mepc, mtvec, mscratch, mcause, mtval, mscratch}};
 | 
			
		||||
    for(auto addr: addrs) {
 | 
			
		||||
        csr_rd_cb[addr] = &this_class::read_reg;
 | 
			
		||||
        csr_wr_cb[addr] = &this_class::write_reg;
 | 
			
		||||
        csr_rd_cb[addr] = &this_class::read_csr_reg;
 | 
			
		||||
        csr_wr_cb[addr] = &this_class::write_csr_reg;
 | 
			
		||||
    }
 | 
			
		||||
    // special handling & overrides
 | 
			
		||||
    csr_rd_cb[time] = &this_class::read_time;
 | 
			
		||||
@@ -362,15 +397,23 @@ riscv_hart_m_p<BASE>::riscv_hart_m_p()
 | 
			
		||||
    csr_rd_cb[mie] = &this_class::read_ie;
 | 
			
		||||
    csr_wr_cb[mie] = &this_class::write_ie;
 | 
			
		||||
    csr_rd_cb[mhartid] = &this_class::read_hartid;
 | 
			
		||||
//    csr_rd_cb[mcounteren] = &this_class::read_null;
 | 
			
		||||
//    csr_wr_cb[mcounteren] = &this_class::write_null;
 | 
			
		||||
    csr_wr_cb[misa] = &this_class::write_null;
 | 
			
		||||
    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_DEBUG){
 | 
			
		||||
        csr_wr_cb[dscratch0] = &this_class::write_dcsr_reg;
 | 
			
		||||
        csr_rd_cb[dscratch0] = &this_class::read_dcsr_reg;
 | 
			
		||||
        csr_wr_cb[dscratch1] = &this_class::write_dcsr_reg;
 | 
			
		||||
        csr_rd_cb[dscratch1] = &this_class::read_dcsr_reg;
 | 
			
		||||
        csr_wr_cb[dpc] = &this_class::write_dpc_reg;
 | 
			
		||||
        csr_rd_cb[dpc] = &this_class::read_dpc_reg;
 | 
			
		||||
        csr_wr_cb[dcsr] = &this_class::write_dcsr_dcsr;
 | 
			
		||||
        csr_rd_cb[dcsr] = &this_class::read_dcsr_reg;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> std::pair<uint64_t, bool> riscv_hart_m_p<BASE>::load_file(std::string name, int type) {
 | 
			
		||||
template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m_p<BASE, FEAT>::load_file(std::string name, int type) {
 | 
			
		||||
    FILE *fp = fopen(name.c_str(), "r");
 | 
			
		||||
    if (fp) {
 | 
			
		||||
        std::array<char, 5> buf;
 | 
			
		||||
@@ -436,8 +479,8 @@ template <typename BASE> std::pair<uint64_t, bool> riscv_hart_m_p<BASE>::load_fi
 | 
			
		||||
    throw std::runtime_error("memory load file not found");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE>
 | 
			
		||||
iss::status riscv_hart_m_p<BASE>::read(const address_type type, const access_type access, const uint32_t space,
 | 
			
		||||
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) {
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
    if (access && iss::access_type::DEBUG) {
 | 
			
		||||
@@ -505,8 +548,8 @@ iss::status riscv_hart_m_p<BASE>::read(const address_type type, const access_typ
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE>
 | 
			
		||||
iss::status riscv_hart_m_p<BASE>::write(const address_type type, const access_type access, const uint32_t space,
 | 
			
		||||
template <typename BASE, features_e FEAT>
 | 
			
		||||
iss::status riscv_hart_m_p<BASE, FEAT>::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) {
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
    const char *prefix = (access && iss::access_type::DEBUG) ? "debug " : "";
 | 
			
		||||
@@ -621,7 +664,7 @@ iss::status riscv_hart_m_p<BASE>::write(const address_type type, const access_ty
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_csr(unsigned addr, reg_t &val) {
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_csr(unsigned addr, reg_t &val) {
 | 
			
		||||
    if (addr >= csr.size()) return iss::Err;
 | 
			
		||||
    auto req_priv_lvl = (addr >> 8) & 0x3;
 | 
			
		||||
    if (this->reg.PRIV < req_priv_lvl) // not having required privileges
 | 
			
		||||
@@ -632,7 +675,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_csr(unsigned add
 | 
			
		||||
    return (this->*(it->second))(addr, val);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_csr(unsigned addr, reg_t val) {
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_csr(unsigned addr, reg_t val) {
 | 
			
		||||
    if (addr >= csr.size()) return iss::Err;
 | 
			
		||||
    auto req_priv_lvl = (addr >> 8) & 0x3;
 | 
			
		||||
    if (this->reg.PRIV < req_priv_lvl) // not having required privileges
 | 
			
		||||
@@ -645,22 +688,22 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_csr(unsigned ad
 | 
			
		||||
    return (this->*(it->second))(addr, val);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_reg(unsigned addr, reg_t &val) {
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_csr_reg(unsigned addr, reg_t &val) {
 | 
			
		||||
    val = csr[addr];
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_null(unsigned addr, reg_t &val) {
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_null(unsigned addr, reg_t &val) {
 | 
			
		||||
    val = 0;
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_reg(unsigned addr, reg_t val) {
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_csr_reg(unsigned addr, reg_t val) {
 | 
			
		||||
    csr[addr] = val;
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_cycle(unsigned addr, reg_t &val) {
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_cycle(unsigned addr, reg_t &val) {
 | 
			
		||||
    auto cycle_val = this->reg.icount + cycle_offset;
 | 
			
		||||
    if (addr == mcycle) {
 | 
			
		||||
        val = static_cast<reg_t>(cycle_val);
 | 
			
		||||
@@ -671,7 +714,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_cycle(unsigned a
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_cycle(unsigned addr, reg_t val) {
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_cycle(unsigned addr, reg_t val) {
 | 
			
		||||
    if (sizeof(typename traits<BASE>::reg_t) != 4) {
 | 
			
		||||
        if (addr == mcycleh)
 | 
			
		||||
            return iss::Err;
 | 
			
		||||
@@ -687,7 +730,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_cycle(unsigned
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_instret(unsigned addr, reg_t &val) {
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_instret(unsigned addr, reg_t &val) {
 | 
			
		||||
    if ((addr&0xff) == (minstret&0xff)) {
 | 
			
		||||
        val = static_cast<reg_t>(this->reg.instret);
 | 
			
		||||
    } else if ((addr&0xff) == (minstreth&0xff)) {
 | 
			
		||||
@@ -697,7 +740,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_instret(unsigned
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_instret(unsigned addr, reg_t val) {
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_instret(unsigned addr, reg_t val) {
 | 
			
		||||
    if (sizeof(typename traits<BASE>::reg_t) != 4) {
 | 
			
		||||
        if ((addr&0xff) == (minstreth&0xff))
 | 
			
		||||
            return iss::Err;
 | 
			
		||||
@@ -713,7 +756,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_instret(unsigne
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_time(unsigned addr, reg_t &val) {
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_time(unsigned addr, reg_t &val) {
 | 
			
		||||
    uint64_t time_val = this->reg.icount / (100000000 / 32768 - 1); //-> ~3052;
 | 
			
		||||
    if (addr == time) {
 | 
			
		||||
        val = static_cast<reg_t>(time_val);
 | 
			
		||||
@@ -724,64 +767,105 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_time(unsigned ad
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_tvec(unsigned addr, reg_t &val) {
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_tvec(unsigned addr, reg_t &val) {
 | 
			
		||||
    val = csr[mtvec] & ~2;
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_status(unsigned addr, reg_t &val) {
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_status(unsigned addr, reg_t &val) {
 | 
			
		||||
    val = state.mstatus & hart_state_type::get_mask();
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_status(unsigned addr, reg_t val) {
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_status(unsigned addr, reg_t val) {
 | 
			
		||||
    state.write_mstatus(val);
 | 
			
		||||
    check_interrupt();
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_cause(unsigned addr, reg_t val) {
 | 
			
		||||
    csr[mcause] = val & ((1UL<<(traits<BASE>::XLEN-1))|0xf); //TODO: make exception code size configurable
 | 
			
		||||
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));
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_ie(unsigned addr, reg_t &val) {
 | 
			
		||||
    val = csr[mie];
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_hartid(unsigned addr, reg_t &val) {
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_hartid(unsigned addr, reg_t &val) {
 | 
			
		||||
    val = mhartid_reg;
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_ie(unsigned addr, reg_t val) {
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_ie(unsigned addr, reg_t &val) {
 | 
			
		||||
    auto mask = get_irq_mask();
 | 
			
		||||
    val = csr[mie] & mask;
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_ie(unsigned addr, reg_t val) {
 | 
			
		||||
    auto mask = get_irq_mask();
 | 
			
		||||
    csr[mie] = (csr[mie] & ~mask) | (val & mask);
 | 
			
		||||
    check_interrupt();
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_ip(unsigned addr, reg_t &val) {
 | 
			
		||||
    val = csr[mip];
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_ip(unsigned addr, reg_t &val) {
 | 
			
		||||
    auto mask = get_irq_mask();
 | 
			
		||||
    val = csr[mip] & mask;
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_ip(unsigned addr, reg_t val) {
 | 
			
		||||
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 &= ~(1 << 7); // MTIP is read only
 | 
			
		||||
    mask &= 0xf; // only xSIP is writable
 | 
			
		||||
    csr[mip] = (csr[mip] & ~mask) | (val & mask);
 | 
			
		||||
    check_interrupt();
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_epc(unsigned addr, reg_t val) {
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE>
 | 
			
		||||
iss::status riscv_hart_m_p<BASE>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_dcsr_dcsr(unsigned addr, reg_t val) {
 | 
			
		||||
    if(!debug_mode_active())
 | 
			
		||||
        throw illegal_instruction_fault(this->fault_data);
 | 
			
		||||
    //                  +-------------- ebreakm
 | 
			
		||||
    //                  |   +---------- stepi
 | 
			
		||||
    //                  |   |  +++----- cause
 | 
			
		||||
    //                  |   |  |||   +- step
 | 
			
		||||
    csr[addr] = val & 0b1000100111000100U;
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_dcsr_reg(unsigned addr, reg_t &val) {
 | 
			
		||||
    if(!debug_mode_active())
 | 
			
		||||
        throw illegal_instruction_fault(this->fault_data);
 | 
			
		||||
    val = csr[addr];
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_dcsr_reg(unsigned addr, reg_t val) {
 | 
			
		||||
    if(!debug_mode_active())
 | 
			
		||||
        throw illegal_instruction_fault(this->fault_data);
 | 
			
		||||
    csr[addr] = val;
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_dpc_reg(unsigned addr, reg_t &val) {
 | 
			
		||||
    if(!debug_mode_active())
 | 
			
		||||
        throw illegal_instruction_fault(this->fault_data);
 | 
			
		||||
    val = this->reg.DPC;
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_dpc_reg(unsigned addr, reg_t val) {
 | 
			
		||||
    if(!debug_mode_active())
 | 
			
		||||
        throw illegal_instruction_fault(this->fault_data);
 | 
			
		||||
    this->reg.DPC = val;
 | 
			
		||||
    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);
 | 
			
		||||
    switch (paddr.val) {
 | 
			
		||||
    case 0x0200BFF8: { // CLINT base, mtime reg
 | 
			
		||||
@@ -805,8 +889,8 @@ iss::status riscv_hart_m_p<BASE>::read_mem(phys_addr_t paddr, unsigned length, u
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE>
 | 
			
		||||
iss::status riscv_hart_m_p<BASE>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) {
 | 
			
		||||
template <typename BASE, features_e FEAT>
 | 
			
		||||
iss::status riscv_hart_m_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) {
 | 
			
		||||
    if(mem_write_cb) return mem_write_cb(paddr, length, data);
 | 
			
		||||
    switch (paddr.val) {
 | 
			
		||||
    case 0x10013000: // UART0 base, TXFIFO reg
 | 
			
		||||
@@ -883,12 +967,12 @@ iss::status riscv_hart_m_p<BASE>::write_mem(phys_addr_t paddr, unsigned length,
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> inline void riscv_hart_m_p<BASE>::reset(uint64_t address) {
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> void riscv_hart_m_p<BASE>::check_interrupt() {
 | 
			
		||||
template <typename BASE, features_e FEAT> void riscv_hart_m_p<BASE, FEAT>::check_interrupt() {
 | 
			
		||||
    //auto ideleg = csr[mideleg];
 | 
			
		||||
    // Multiple simultaneous interrupts and traps at the same privilege level are
 | 
			
		||||
    // handled in the following decreasing priority order:
 | 
			
		||||
@@ -910,32 +994,49 @@ template <typename BASE> void riscv_hart_m_p<BASE>::check_interrupt() {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> uint64_t riscv_hart_m_p<BASE>::enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) {
 | 
			
		||||
template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_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
 | 
			
		||||
    auto trap_id = bit_sub<0, 16>(flags);
 | 
			
		||||
    auto cause = bit_sub<16, 15>(flags);
 | 
			
		||||
    if (trap_id == 0 && cause == 11) cause = 0x8 + PRIV_M; // adjust environment call cause
 | 
			
		||||
    // calculate effective privilege level
 | 
			
		||||
    if (trap_id == 0) { // exception
 | 
			
		||||
        if (cause == 11) cause = 0x8 + PRIV_M; // adjust environment call cause
 | 
			
		||||
        // store ret addr in xepc register
 | 
			
		||||
        csr[mepc] = static_cast<reg_t>(addr) & get_pc_mask(); // store actual address instruction of exception
 | 
			
		||||
        /*
 | 
			
		||||
         * write mtval if new_priv=M_MODE, spec says:
 | 
			
		||||
         * When a hardware breakpoint is triggered, or an instruction-fetch, load,
 | 
			
		||||
         * or store address-misaligned,
 | 
			
		||||
         * access, or page-fault exception occurs, mtval is written with the
 | 
			
		||||
         * faulting effective address.
 | 
			
		||||
         */
 | 
			
		||||
        switch(cause){
 | 
			
		||||
        case 0:
 | 
			
		||||
            csr[mtval] = addr;
 | 
			
		||||
            csr[mtval] = static_cast<reg_t>(addr);
 | 
			
		||||
            break;
 | 
			
		||||
        case 2:
 | 
			
		||||
            csr[mtval] = (instr & 0x3)==3?instr:instr&0xffff;
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
        case 3:
 | 
			
		||||
            //TODO: implement debug mode behavior
 | 
			
		||||
            // csr[dpc] = addr;
 | 
			
		||||
            // csr[dcsr] = (csr[dcsr] & ~0x1c3) | (1<<6) | PRIV_M; //FIXME: cause should not be 4 (stepi)
 | 
			
		||||
            csr[mtval] = addr;
 | 
			
		||||
            break;
 | 
			
		||||
        case 4:
 | 
			
		||||
        case 6:
 | 
			
		||||
            csr[mtval] = fault_data;
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            csr[mtval] = 0;
 | 
			
		||||
        }
 | 
			
		||||
        fault_data = 0;
 | 
			
		||||
    } else {
 | 
			
		||||
        csr[mepc] = this->reg.NEXT_PC & get_pc_mask(); // store next address if interrupt
 | 
			
		||||
        this->reg.pending_trap = 0;
 | 
			
		||||
    }
 | 
			
		||||
    csr[mcause] = (trap_id << 31) + cause;
 | 
			
		||||
    csr[mcause] = (trap_id << (traits<BASE>::XLEN-1)) + cause;
 | 
			
		||||
    // update mstatus
 | 
			
		||||
    // xPP field of mstatus is written with the active privilege mode at the time
 | 
			
		||||
    // of the trap; the x PIE field of mstatus
 | 
			
		||||
@@ -969,7 +1070,7 @@ template <typename BASE> uint64_t riscv_hart_m_p<BASE>::enter_trap(uint64_t flag
 | 
			
		||||
    return this->reg.NEXT_PC;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE> uint64_t riscv_hart_m_p<BASE>::leave_trap(uint64_t flags) {
 | 
			
		||||
template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::leave_trap(uint64_t flags) {
 | 
			
		||||
    state.mstatus.MIE = state.mstatus.MPIE;
 | 
			
		||||
    state.mstatus.MPIE = 1;
 | 
			
		||||
    // sets the pc to the value stored in the x epc register.
 | 
			
		||||
 
 | 
			
		||||
@@ -293,21 +293,21 @@ public:
 | 
			
		||||
 | 
			
		||||
    std::pair<uint64_t, bool> load_file(std::string name, int type = -1) override;
 | 
			
		||||
 | 
			
		||||
    virtual phys_addr_t virt2phys(const iss::addr_t &addr) override;
 | 
			
		||||
    phys_addr_t virt2phys(const iss::addr_t &addr) override;
 | 
			
		||||
 | 
			
		||||
    iss::status read(const address_type type, const access_type access, const uint32_t space,
 | 
			
		||||
            const uint64_t addr, const unsigned length, uint8_t *const data) override;
 | 
			
		||||
    iss::status write(const address_type type, const access_type access, const uint32_t space,
 | 
			
		||||
            const uint64_t addr, const unsigned length, const uint8_t *const data) override;
 | 
			
		||||
 | 
			
		||||
    virtual uint64_t enter_trap(uint64_t flags) override { return riscv_hart_msu_vp::enter_trap(flags, fault_data, fault_data); }
 | 
			
		||||
    virtual uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override;
 | 
			
		||||
    virtual uint64_t leave_trap(uint64_t flags) override;
 | 
			
		||||
    uint64_t enter_trap(uint64_t flags) override { return riscv_hart_msu_vp::enter_trap(flags, fault_data, fault_data); }
 | 
			
		||||
    uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override;
 | 
			
		||||
    uint64_t leave_trap(uint64_t flags) override;
 | 
			
		||||
    void wait_until(uint64_t flags) override;
 | 
			
		||||
 | 
			
		||||
    void disass_output(uint64_t pc, const std::string instr) override {
 | 
			
		||||
        CLOG(INFO, disass) << fmt::format("0x{:016x}    {:40} [p:{};s:0x{:x};c:{}]",
 | 
			
		||||
                pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.ccount);
 | 
			
		||||
                pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.ccount + cycle_offset);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
 | 
			
		||||
@@ -340,6 +340,10 @@ protected:
 | 
			
		||||
 | 
			
		||||
        virtual uint64_t get_next_pc() { return arch.get_next_pc(); };
 | 
			
		||||
 | 
			
		||||
        uint64_t get_instr_count() { return arch.reg.icount; }
 | 
			
		||||
 | 
			
		||||
        uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
 | 
			
		||||
 | 
			
		||||
        virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; };
 | 
			
		||||
 | 
			
		||||
        riscv_hart_msu_vp<BASE> &arch;
 | 
			
		||||
@@ -1276,7 +1280,27 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f
 | 
			
		||||
         * access, or page-fault exception occurs, mtval is written with the
 | 
			
		||||
         * faulting effective address.
 | 
			
		||||
         */
 | 
			
		||||
        csr[utval | (new_priv << 8)] = cause==2?((instr & 0x3)==3?instr:instr&0xffff):fault_data;
 | 
			
		||||
        switch(cause){
 | 
			
		||||
        case 0:
 | 
			
		||||
            csr[utval | (new_priv << 8)] = static_cast<reg_t>(addr);
 | 
			
		||||
            break;
 | 
			
		||||
        case 2:
 | 
			
		||||
            csr[utval | (new_priv << 8)] = (instr & 0x3)==3?instr:instr&0xffff;
 | 
			
		||||
            break;
 | 
			
		||||
        case 3:
 | 
			
		||||
            //TODO: implement debug mode behavior
 | 
			
		||||
            // csr[dpc] = addr;
 | 
			
		||||
            // csr[dcsr] = (csr[dcsr] & ~0x1c3) | (1<<6) | PRIV_M; //FIXME: cause should not be 4 (stepi)
 | 
			
		||||
            csr[utval | (new_priv << 8)] = addr;
 | 
			
		||||
            break;
 | 
			
		||||
        case 4:
 | 
			
		||||
        case 6:
 | 
			
		||||
        case 7:
 | 
			
		||||
            csr[utval | (new_priv << 8)] = fault_data;
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            csr[utval | (new_priv << 8)] = 0;
 | 
			
		||||
        }
 | 
			
		||||
        fault_data = 0;
 | 
			
		||||
    } else {
 | 
			
		||||
        if (cur_priv != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0)
 | 
			
		||||
 
 | 
			
		||||
@@ -66,8 +66,6 @@
 | 
			
		||||
namespace iss {
 | 
			
		||||
namespace arch {
 | 
			
		||||
 | 
			
		||||
enum features_e{FEAT_NONE, FEAT_PMP, FEAT_EXT_N, FEAT_CLIC};
 | 
			
		||||
 | 
			
		||||
template <typename BASE, features_e FEAT=FEAT_NONE> class riscv_hart_mu_p : public BASE {
 | 
			
		||||
protected:
 | 
			
		||||
    const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
 | 
			
		||||
@@ -183,7 +181,7 @@ public:
 | 
			
		||||
    };
 | 
			
		||||
    using hart_state_type = hart_state<reg_t>;
 | 
			
		||||
 | 
			
		||||
    constexpr reg_t get_irq_wrmask(size_t mode) {
 | 
			
		||||
    constexpr reg_t get_irq_mask(size_t mode) {
 | 
			
		||||
        std::array<const reg_t, 4> m = {{
 | 
			
		||||
            0b000100010001, // U mode
 | 
			
		||||
            0b001100110011, // S mode
 | 
			
		||||
@@ -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;
 | 
			
		||||
 | 
			
		||||
    virtual uint64_t enter_trap(uint64_t flags) override { return riscv_hart_mu_p::enter_trap(flags, fault_data, fault_data); }
 | 
			
		||||
    virtual uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override;
 | 
			
		||||
    virtual uint64_t leave_trap(uint64_t flags) override;
 | 
			
		||||
    uint64_t enter_trap(uint64_t flags) override { return riscv_hart_mu_p::enter_trap(flags, fault_data, fault_data); }
 | 
			
		||||
    uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override;
 | 
			
		||||
    uint64_t leave_trap(uint64_t flags) override;
 | 
			
		||||
 | 
			
		||||
    const reg_t& get_mhartid() const { return mhartid_reg;	}
 | 
			
		||||
	void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; };
 | 
			
		||||
 | 
			
		||||
    void disass_output(uint64_t pc, const std::string instr) override {
 | 
			
		||||
        CLOG(INFO, disass) << fmt::format("0x{:016x}    {:40} [p:{};s:0x{:x};c:{}]",
 | 
			
		||||
                pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.icount);
 | 
			
		||||
                pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.icount + cycle_offset);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
 | 
			
		||||
@@ -235,6 +233,9 @@ public:
 | 
			
		||||
        csr[addr & csr.page_addr_mask] = val;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void set_irq_num(unsigned i) {
 | 
			
		||||
        mcause_max_irq=1<<util::ilog2(i);
 | 
			
		||||
    }
 | 
			
		||||
protected:
 | 
			
		||||
    struct riscv_instrumentation_if : public iss::instrumentation_if {
 | 
			
		||||
 | 
			
		||||
@@ -251,6 +252,10 @@ protected:
 | 
			
		||||
 | 
			
		||||
        virtual uint64_t get_next_pc() { return arch.get_next_pc(); };
 | 
			
		||||
 | 
			
		||||
        uint64_t get_instr_count() { return arch.reg.icount; }
 | 
			
		||||
 | 
			
		||||
        uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
 | 
			
		||||
 | 
			
		||||
        virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; };
 | 
			
		||||
 | 
			
		||||
        riscv_hart_mu_p<BASE, FEAT> &arch;
 | 
			
		||||
@@ -304,7 +309,6 @@ protected:
 | 
			
		||||
    };
 | 
			
		||||
    std::vector<clic_int_reg_t> clic_int_reg;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    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);
 | 
			
		||||
@@ -328,18 +332,24 @@ private:
 | 
			
		||||
    iss::status write_epc(unsigned addr, reg_t val);
 | 
			
		||||
    iss::status write_intstatus(unsigned addr, reg_t val);
 | 
			
		||||
    iss::status write_intthresh(unsigned addr, reg_t val);
 | 
			
		||||
    iss::status write_dcsr_dcsr(unsigned addr, reg_t val);
 | 
			
		||||
    iss::status read_dcsr_reg(unsigned addr, reg_t &val);
 | 
			
		||||
    iss::status write_dcsr_reg(unsigned addr, reg_t val);
 | 
			
		||||
    iss::status read_dpc_reg(unsigned addr, reg_t &val);
 | 
			
		||||
    iss::status write_dpc_reg(unsigned addr, reg_t val);
 | 
			
		||||
    iss::status write_pmpcfg_reg(unsigned addr, reg_t val);
 | 
			
		||||
 | 
			
		||||
    reg_t mhartid_reg{0x0};
 | 
			
		||||
    std::function<iss::status(phys_addr_t, unsigned, uint8_t *const)>mem_read_cb;
 | 
			
		||||
    std::function<iss::status(phys_addr_t, unsigned, const uint8_t *const)> mem_write_cb;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    void check_interrupt();
 | 
			
		||||
    bool pmp_check(const access_type type, const uint64_t addr, const unsigned len);
 | 
			
		||||
    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>
 | 
			
		||||
@@ -423,7 +433,7 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p()
 | 
			
		||||
        }
 | 
			
		||||
        for(size_t i=pmpcfg0; i<=pmpcfg3; ++i){
 | 
			
		||||
            csr_rd_cb[i] = &this_class::read_csr_reg;
 | 
			
		||||
            csr_wr_cb[i] = &this_class::write_csr_reg;
 | 
			
		||||
            csr_wr_cb[i] = &this_class::write_pmpcfg_reg;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if(FEAT & FEAT_EXT_N){
 | 
			
		||||
@@ -464,6 +474,16 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p()
 | 
			
		||||
        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;
 | 
			
		||||
        csr_rd_cb[dscratch0] = &this_class::read_dcsr_reg;
 | 
			
		||||
        csr_wr_cb[dscratch1] = &this_class::write_dcsr_reg;
 | 
			
		||||
        csr_rd_cb[dscratch1] = &this_class::read_dcsr_reg;
 | 
			
		||||
        csr_wr_cb[dpc] = &this_class::write_dpc_reg;
 | 
			
		||||
        csr_rd_cb[dpc] = &this_class::read_dpc_reg;
 | 
			
		||||
        csr_wr_cb[dcsr] = &this_class::write_dcsr_dcsr;
 | 
			
		||||
        csr_rd_cb[dcsr] = &this_class::read_dcsr_reg;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_mu_p<BASE, FEAT>::load_file(std::string name, int type) {
 | 
			
		||||
@@ -532,6 +552,12 @@ template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m
 | 
			
		||||
    throw std::runtime_error("memory load file not found");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename BASE, features_e FEAT>
 | 
			
		||||
inline iss::status riscv_hart_mu_p<BASE, FEAT>::write_pmpcfg_reg(unsigned addr, reg_t val) {
 | 
			
		||||
    csr[addr] = val & 0x9f9f9f9f;
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE, features_e FEAT> bool riscv_hart_mu_p<BASE, FEAT>::pmp_check(const access_type type, const uint64_t addr, const unsigned len) {
 | 
			
		||||
    constexpr auto PMP_SHIFT=2U;
 | 
			
		||||
    constexpr auto PMP_R = 0x1U;
 | 
			
		||||
@@ -562,7 +588,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 && cur_addr < tor;
 | 
			
		||||
                auto tor_match = base <= (cur_addr+len-1) && cur_addr < tor;
 | 
			
		||||
                auto match = is_tor ? tor_match : napot_match;
 | 
			
		||||
                any_match |= match;
 | 
			
		||||
                all_match &= match;
 | 
			
		||||
@@ -579,6 +605,37 @@ template <typename BASE, features_e FEAT> bool riscv_hart_mu_p<BASE, FEAT>::pmp_
 | 
			
		||||
        }
 | 
			
		||||
        base = tor;
 | 
			
		||||
    }
 | 
			
		||||
//    constexpr auto pmp_num_regs = 16;
 | 
			
		||||
//    reg_t tor_base = 0;
 | 
			
		||||
//    auto any_active = false;
 | 
			
		||||
//    auto lower_addr = addr >>2;
 | 
			
		||||
//    auto upper_addr = (addr+len-1)>>2;
 | 
			
		||||
//    for (size_t i = 0; i < pmp_num_regs; i++) {
 | 
			
		||||
//        uint8_t cfg = csr[pmpcfg0+(i/4)]>>(i%4);
 | 
			
		||||
//        uint8_t cfg_next = i==(pmp_num_regs-1)? 0 : csr[pmpcfg0+((i+1)/4)]>>((i+1)%4);
 | 
			
		||||
//        auto pmpaddr = csr[pmpaddr0+i];
 | 
			
		||||
//        if (cfg & PMP_A) {
 | 
			
		||||
//            any_active=true;
 | 
			
		||||
//            auto is_tor = bit_sub<3, 2>(cfg) == PMP_TOR;
 | 
			
		||||
//            auto is_napot = bit_sub<4, 1>(cfg) && bit_sub<3, 2>(cfg_next)!= PMP_TOR;
 | 
			
		||||
//            if(is_napot) {
 | 
			
		||||
//                reg_t mask = bit_sub<3, 1>(cfg)?~( pmpaddr & ~(pmpaddr + 1)): 0x3fffffff;
 | 
			
		||||
//                auto mpmpaddr = pmpaddr & mask;
 | 
			
		||||
//                if((lower_addr&mask) == mpmpaddr && (upper_addr&mask)==mpmpaddr)
 | 
			
		||||
//                    return  (this->reg.PRIV == PRIV_M && !(cfg & PMP_L)) ||
 | 
			
		||||
//                            (type == access_type::READ && (cfg & PMP_R)) ||
 | 
			
		||||
//                            (type == access_type::WRITE && (cfg & PMP_W)) ||
 | 
			
		||||
//                            (type == access_type::FETCH && (cfg & PMP_X));
 | 
			
		||||
//            } else if(is_tor) {
 | 
			
		||||
//                if(lower_addr>=tor_base && upper_addr<=pmpaddr)
 | 
			
		||||
//                    return  (this->reg.PRIV == PRIV_M && !(cfg & PMP_L)) ||
 | 
			
		||||
//                            (type == access_type::READ && (cfg & PMP_R)) ||
 | 
			
		||||
//                            (type == access_type::WRITE && (cfg & PMP_W)) ||
 | 
			
		||||
//                            (type == access_type::FETCH && (cfg & PMP_X));
 | 
			
		||||
//            }
 | 
			
		||||
//        }
 | 
			
		||||
//        tor_base = pmpaddr;
 | 
			
		||||
//    }
 | 
			
		||||
    return !any_active || this->reg.PRIV == PRIV_M;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -909,7 +966,7 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_cause(unsigned addr, reg_t val) {
 | 
			
		||||
    csr[addr] = val & ((1UL<<(traits<BASE>::XLEN-1))|(mcause_max_irq-1)); //TODO: make exception code size configurable
 | 
			
		||||
    csr[addr] = val & ((1UL<<(traits<BASE>::XLEN-1))|(mcause_max_irq-1));
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -919,7 +976,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_ie(unsigned addr, reg_t &val) {
 | 
			
		||||
    auto mask = get_irq_wrmask((addr >> 8) & 0x3);
 | 
			
		||||
    auto mask = get_irq_mask((addr >> 8) & 0x3);
 | 
			
		||||
    val = csr[mie] & mask;
 | 
			
		||||
    if(this->reg.PRIV!=3)
 | 
			
		||||
        val &= csr[mideleg];
 | 
			
		||||
@@ -927,14 +984,14 @@ 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_ie(unsigned addr, reg_t val) {
 | 
			
		||||
    auto mask = get_irq_wrmask((addr >> 8) & 0x3);
 | 
			
		||||
    auto mask = get_irq_mask((addr >> 8) & 0x3);
 | 
			
		||||
    csr[mie] = (csr[mie] & ~mask) | (val & mask);
 | 
			
		||||
    check_interrupt();
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_ip(unsigned addr, reg_t &val) {
 | 
			
		||||
    auto mask = get_irq_wrmask((addr >> 8) & 0x3);
 | 
			
		||||
    auto mask = get_irq_mask((addr >> 8) & 0x3);
 | 
			
		||||
    val = csr[mip] & mask;
 | 
			
		||||
    if(this->reg.PRIV!=3)
 | 
			
		||||
        val &= csr[mideleg];
 | 
			
		||||
@@ -942,10 +999,8 @@ 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_ip(unsigned addr, reg_t val) {
 | 
			
		||||
    auto mask = get_irq_wrmask((addr >> 8) & 0x3);
 | 
			
		||||
    mask &= ~(8 << 4); // MTIP is read only
 | 
			
		||||
    if(this->reg.PRIV!=3)
 | 
			
		||||
        mask &= ~(3 << 4); // STIP and UTIP are read only in user and supervisor mode
 | 
			
		||||
    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;
 | 
			
		||||
@@ -968,6 +1023,45 @@ 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_dcsr_dcsr(unsigned addr, reg_t val) {
 | 
			
		||||
    if(!debug_mode_active())
 | 
			
		||||
        throw illegal_instruction_fault(this->fault_data);
 | 
			
		||||
    //                  +-------------- ebreakm
 | 
			
		||||
    //                  |   +---------- stepi
 | 
			
		||||
    //                  |   |  +++----- cause
 | 
			
		||||
    //                  |   |  |||   +- step
 | 
			
		||||
    csr[addr] = val & 0b1000100111000100U;
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_dcsr_reg(unsigned addr, reg_t &val) {
 | 
			
		||||
    if(!debug_mode_active())
 | 
			
		||||
        throw illegal_instruction_fault(this->fault_data);
 | 
			
		||||
    val = csr[addr];
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_dcsr_reg(unsigned addr, reg_t val) {
 | 
			
		||||
    if(!debug_mode_active())
 | 
			
		||||
        throw illegal_instruction_fault(this->fault_data);
 | 
			
		||||
    csr[addr] = val;
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_dpc_reg(unsigned addr, reg_t &val) {
 | 
			
		||||
    if(!debug_mode_active())
 | 
			
		||||
        throw illegal_instruction_fault(this->fault_data);
 | 
			
		||||
    val = this->reg.DPC;
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_dpc_reg(unsigned addr, reg_t val) {
 | 
			
		||||
    if(!debug_mode_active())
 | 
			
		||||
        throw illegal_instruction_fault(this->fault_data);
 | 
			
		||||
    this->reg.DPC = val;
 | 
			
		||||
    return iss::Ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename BASE, features_e FEAT>
 | 
			
		||||
iss::status riscv_hart_mu_p<BASE, FEAT>::write_intthresh(unsigned addr, reg_t val) {
 | 
			
		||||
    csr[addr]= val &0xff;
 | 
			
		||||
@@ -1142,7 +1236,7 @@ template<typename BASE, features_e FEAT>
 | 
			
		||||
iss::status riscv_hart_mu_p<BASE, FEAT>::write_clic(uint64_t addr, unsigned length, const uint8_t *const data) {
 | 
			
		||||
    if(addr==clic_base_addr) { // cliccfg
 | 
			
		||||
        clic_cfg_reg = *data;
 | 
			
		||||
        clic_cfg_reg&= 0x7f;
 | 
			
		||||
        clic_cfg_reg&= 0x7e;
 | 
			
		||||
//    } else if(addr>=(clic_base_addr+4) && (addr+length)<=(clic_base_addr+4)){ // clicinfo
 | 
			
		||||
//        write_uint32(addr, clic_info_reg, data, length);
 | 
			
		||||
    } else if(addr>=(clic_base_addr+0x40) && (addr+length)<=(clic_base_addr+0xC0)){ // clicinttrig
 | 
			
		||||
@@ -1203,7 +1297,27 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
 | 
			
		||||
         * access, or page-fault exception occurs, mtval is written with the
 | 
			
		||||
         * faulting effective address.
 | 
			
		||||
         */
 | 
			
		||||
        csr[utval | (new_priv << 8)] = cause==2?((instr & 0x3)==3?instr:instr&0xffff):fault_data;
 | 
			
		||||
        switch(cause){
 | 
			
		||||
        case 0:
 | 
			
		||||
            csr[utval | (new_priv << 8)] = static_cast<reg_t>(addr);
 | 
			
		||||
            break;
 | 
			
		||||
        case 2:
 | 
			
		||||
            csr[utval | (new_priv << 8)] = (instr & 0x3)==3?instr:instr&0xffff;
 | 
			
		||||
            break;
 | 
			
		||||
        case 3:
 | 
			
		||||
            //TODO: implement debug mode behavior
 | 
			
		||||
            // csr[dpc] = addr;
 | 
			
		||||
            // csr[dcsr] = (csr[dcsr] & ~0x1c3) | (1<<6) | PRIV_M; //FIXME: cause should not be 4 (stepi)
 | 
			
		||||
            csr[utval | (new_priv << 8)] = addr;
 | 
			
		||||
            break;
 | 
			
		||||
        case 4:
 | 
			
		||||
        case 6:
 | 
			
		||||
        case 7:
 | 
			
		||||
            csr[utval | (new_priv << 8)] = fault_data;
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            csr[utval | (new_priv << 8)] = 0;
 | 
			
		||||
        }
 | 
			
		||||
        fault_data = 0;
 | 
			
		||||
    } else {
 | 
			
		||||
        if (this->reg.PRIV != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0)
 | 
			
		||||
@@ -1212,7 +1326,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
 | 
			
		||||
        this->reg.pending_trap = 0;
 | 
			
		||||
    }
 | 
			
		||||
    size_t adr = ucause | (new_priv << 8);
 | 
			
		||||
    csr[adr] = (trap_id << 31) + cause;
 | 
			
		||||
    csr[adr] = (trap_id << (traits<BASE>::XLEN-1)) + cause;
 | 
			
		||||
    // update mstatus
 | 
			
		||||
    // xPP field of mstatus is written with the active privilege mode at the time
 | 
			
		||||
    // of the trap; the x PIE field of mstatus
 | 
			
		||||
 
 | 
			
		||||
@@ -47,18 +47,18 @@ template <> struct traits<tgc_c> {
 | 
			
		||||
 | 
			
		||||
    constexpr static char const* const core_type = "TGC_C";
 | 
			
		||||
    
 | 
			
		||||
    static constexpr std::array<const char*, 35> reg_names{
 | 
			
		||||
        {"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"}};
 | 
			
		||||
    static constexpr std::array<const char*, 36> reg_names{
 | 
			
		||||
        {"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"}};
 | 
			
		||||
 
 | 
			
		||||
    static constexpr std::array<const char*, 35> 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"}};
 | 
			
		||||
    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, 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, 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,
 | 
			
		||||
@@ -76,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, 40> 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,64,64,64}};
 | 
			
		||||
    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, 40> 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,153,161}};
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
@@ -133,51 +133,52 @@ template <> struct traits<tgc_c> {
 | 
			
		||||
        SRET = 41,
 | 
			
		||||
        MRET = 42,
 | 
			
		||||
        WFI = 43,
 | 
			
		||||
        CSRRW = 44,
 | 
			
		||||
        CSRRS = 45,
 | 
			
		||||
        CSRRC = 46,
 | 
			
		||||
        CSRRWI = 47,
 | 
			
		||||
        CSRRSI = 48,
 | 
			
		||||
        CSRRCI = 49,
 | 
			
		||||
        FENCE_I = 50,
 | 
			
		||||
        MUL = 51,
 | 
			
		||||
        MULH = 52,
 | 
			
		||||
        MULHSU = 53,
 | 
			
		||||
        MULHU = 54,
 | 
			
		||||
        DIV = 55,
 | 
			
		||||
        DIVU = 56,
 | 
			
		||||
        REM = 57,
 | 
			
		||||
        REMU = 58,
 | 
			
		||||
        CADDI4SPN = 59,
 | 
			
		||||
        CLW = 60,
 | 
			
		||||
        CSW = 61,
 | 
			
		||||
        CADDI = 62,
 | 
			
		||||
        CNOP = 63,
 | 
			
		||||
        CJAL = 64,
 | 
			
		||||
        CLI = 65,
 | 
			
		||||
        CLUI = 66,
 | 
			
		||||
        CADDI16SP = 67,
 | 
			
		||||
        __reserved_clui = 68,
 | 
			
		||||
        CSRLI = 69,
 | 
			
		||||
        CSRAI = 70,
 | 
			
		||||
        CANDI = 71,
 | 
			
		||||
        CSUB = 72,
 | 
			
		||||
        CXOR = 73,
 | 
			
		||||
        COR = 74,
 | 
			
		||||
        CAND = 75,
 | 
			
		||||
        CJ = 76,
 | 
			
		||||
        CBEQZ = 77,
 | 
			
		||||
        CBNEZ = 78,
 | 
			
		||||
        CSLLI = 79,
 | 
			
		||||
        CLWSP = 80,
 | 
			
		||||
        CMV = 81,
 | 
			
		||||
        CJR = 82,
 | 
			
		||||
        __reserved_cmv = 83,
 | 
			
		||||
        CADD = 84,
 | 
			
		||||
        CJALR = 85,
 | 
			
		||||
        CEBREAK = 86,
 | 
			
		||||
        CSWSP = 87,
 | 
			
		||||
        DII = 88,
 | 
			
		||||
        DRET = 44,
 | 
			
		||||
        CSRRW = 45,
 | 
			
		||||
        CSRRS = 46,
 | 
			
		||||
        CSRRC = 47,
 | 
			
		||||
        CSRRWI = 48,
 | 
			
		||||
        CSRRSI = 49,
 | 
			
		||||
        CSRRCI = 50,
 | 
			
		||||
        FENCE_I = 51,
 | 
			
		||||
        MUL = 52,
 | 
			
		||||
        MULH = 53,
 | 
			
		||||
        MULHSU = 54,
 | 
			
		||||
        MULHU = 55,
 | 
			
		||||
        DIV = 56,
 | 
			
		||||
        DIVU = 57,
 | 
			
		||||
        REM = 58,
 | 
			
		||||
        REMU = 59,
 | 
			
		||||
        CADDI4SPN = 60,
 | 
			
		||||
        CLW = 61,
 | 
			
		||||
        CSW = 62,
 | 
			
		||||
        CADDI = 63,
 | 
			
		||||
        CNOP = 64,
 | 
			
		||||
        CJAL = 65,
 | 
			
		||||
        CLI = 66,
 | 
			
		||||
        CLUI = 67,
 | 
			
		||||
        CADDI16SP = 68,
 | 
			
		||||
        __reserved_clui = 69,
 | 
			
		||||
        CSRLI = 70,
 | 
			
		||||
        CSRAI = 71,
 | 
			
		||||
        CANDI = 72,
 | 
			
		||||
        CSUB = 73,
 | 
			
		||||
        CXOR = 74,
 | 
			
		||||
        COR = 75,
 | 
			
		||||
        CAND = 76,
 | 
			
		||||
        CJ = 77,
 | 
			
		||||
        CBEQZ = 78,
 | 
			
		||||
        CBNEZ = 79,
 | 
			
		||||
        CSLLI = 80,
 | 
			
		||||
        CLWSP = 81,
 | 
			
		||||
        CMV = 82,
 | 
			
		||||
        CJR = 83,
 | 
			
		||||
        __reserved_cmv = 84,
 | 
			
		||||
        CADD = 85,
 | 
			
		||||
        CJALR = 86,
 | 
			
		||||
        CEBREAK = 87,
 | 
			
		||||
        CSWSP = 88,
 | 
			
		||||
        DII = 89,
 | 
			
		||||
        MAX_OPCODE
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
@@ -216,7 +217,7 @@ struct tgc_c: public arch_if {
 | 
			
		||||
 | 
			
		||||
    inline uint32_t get_last_branch() { return reg.last_branch; }
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
 | 
			
		||||
#pragma pack(push, 1)
 | 
			
		||||
    struct TGC_C_regs { 
 | 
			
		||||
        uint32_t X0 = 0; 
 | 
			
		||||
@@ -254,9 +255,9 @@ protected:
 | 
			
		||||
        uint32_t PC = 0; 
 | 
			
		||||
        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;
 | 
			
		||||
 
 | 
			
		||||
@@ -37,9 +37,9 @@
 | 
			
		||||
 | 
			
		||||
#include "iss/instrumentation_if.h"
 | 
			
		||||
#include "iss/vm_plugin.h"
 | 
			
		||||
#include <json/json.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
namespace iss {
 | 
			
		||||
 | 
			
		||||
@@ -49,11 +49,13 @@ class cycle_estimate: public iss::vm_plugin {
 | 
			
		||||
	BEGIN_BF_DECL(instr_desc, uint32_t)
 | 
			
		||||
		BF_FIELD(taken, 24, 8)
 | 
			
		||||
		BF_FIELD(not_taken, 16, 8)
 | 
			
		||||
		BF_FIELD(size, 0, 16)
 | 
			
		||||
		instr_desc(uint32_t size, uint32_t taken, uint32_t not_taken): instr_desc() {
 | 
			
		||||
        BF_FIELD(is_branch, 8, 8)
 | 
			
		||||
        BF_FIELD(size, 0, 8)
 | 
			
		||||
		instr_desc(uint32_t size, uint32_t taken, uint32_t not_taken, bool branch): instr_desc() {
 | 
			
		||||
			this->size=size;
 | 
			
		||||
			this->taken=taken;
 | 
			
		||||
			this->not_taken=not_taken;
 | 
			
		||||
			this->is_branch=branch;
 | 
			
		||||
		}
 | 
			
		||||
	END_BF_DECL();
 | 
			
		||||
 | 
			
		||||
@@ -64,7 +66,7 @@ public:
 | 
			
		||||
 | 
			
		||||
    cycle_estimate(const cycle_estimate &&) = delete;
 | 
			
		||||
 | 
			
		||||
    cycle_estimate(std::string config_file_name);
 | 
			
		||||
    cycle_estimate(std::string const& config_file_name);
 | 
			
		||||
 | 
			
		||||
    virtual ~cycle_estimate();
 | 
			
		||||
 | 
			
		||||
@@ -88,7 +90,7 @@ private:
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    std::unordered_map<std::pair<uint64_t, uint64_t>, uint64_t, pair_hash> blocks;
 | 
			
		||||
    Json::Value root;
 | 
			
		||||
    std::string config_file_name;
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										99
									
								
								incl/iss/plugin/pctrace.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								incl/iss/plugin/pctrace.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,99 @@
 | 
			
		||||
/*******************************************************************************
 | 
			
		||||
 * Copyright (C) 2017, 2018, MINRES Technologies GmbH
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright notice,
 | 
			
		||||
 *    this list of conditions and the following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 | 
			
		||||
 *    this list of conditions and the following disclaimer in the documentation
 | 
			
		||||
 *    and/or other materials provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 * 3. Neither the name of the copyright holder nor the names of its contributors
 | 
			
		||||
 *    may be used to endorse or promote products derived from this software
 | 
			
		||||
 *    without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 | 
			
		||||
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 | 
			
		||||
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 | 
			
		||||
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | 
			
		||||
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | 
			
		||||
 * POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 *
 | 
			
		||||
 * Contributors:
 | 
			
		||||
 *       eyck@minres.com - initial API and implementation
 | 
			
		||||
 ******************************************************************************/
 | 
			
		||||
 | 
			
		||||
#ifndef _ISS_PLUGIN_COV_H_
 | 
			
		||||
#define _ISS_PLUGIN_COV_H_
 | 
			
		||||
 | 
			
		||||
#include <iss/vm_plugin.h>
 | 
			
		||||
#include "iss/instrumentation_if.h"
 | 
			
		||||
#include <json/json.h>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace iss {
 | 
			
		||||
namespace plugin {
 | 
			
		||||
 | 
			
		||||
class cov : public iss::vm_plugin {
 | 
			
		||||
    struct instr_delay {
 | 
			
		||||
        std::string instr_name;
 | 
			
		||||
        size_t size;
 | 
			
		||||
        size_t not_taken_delay;
 | 
			
		||||
        size_t taken_delay;
 | 
			
		||||
    };
 | 
			
		||||
    BEGIN_BF_DECL(instr_desc, uint32_t)
 | 
			
		||||
        BF_FIELD(taken, 24, 8)
 | 
			
		||||
        BF_FIELD(not_taken, 16, 8)
 | 
			
		||||
        BF_FIELD(is_branch, 8, 8)
 | 
			
		||||
        BF_FIELD(size, 0, 8)
 | 
			
		||||
        instr_desc(uint32_t size, uint32_t taken, uint32_t not_taken, bool branch): instr_desc() {
 | 
			
		||||
            this->size=size;
 | 
			
		||||
            this->taken=taken;
 | 
			
		||||
            this->not_taken=not_taken;
 | 
			
		||||
            this->is_branch=branch;
 | 
			
		||||
        }
 | 
			
		||||
    END_BF_DECL();
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
    cov(const cov &) = delete;
 | 
			
		||||
 | 
			
		||||
    cov(const cov &&) = delete;
 | 
			
		||||
 | 
			
		||||
    cov(std::string const &);
 | 
			
		||||
 | 
			
		||||
    virtual ~cov();
 | 
			
		||||
 | 
			
		||||
    cov &operator=(const cov &) = delete;
 | 
			
		||||
 | 
			
		||||
    cov &operator=(const cov &&) = delete;
 | 
			
		||||
 | 
			
		||||
    bool registration(const char *const version, vm_if &arch) override;
 | 
			
		||||
 | 
			
		||||
    sync_type get_sync() override { return POST_SYNC; };
 | 
			
		||||
 | 
			
		||||
    void callback(instr_info_t, exec_info const&) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    iss::instrumentation_if *instr_if  {nullptr};
 | 
			
		||||
    std::ofstream output;
 | 
			
		||||
    std::string filename;
 | 
			
		||||
    std::vector<instr_desc> delays;
 | 
			
		||||
    bool jumped, first;
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* _ISS_PLUGIN_COV_H_ */
 | 
			
		||||
@@ -39,10 +39,10 @@
 | 
			
		||||
 | 
			
		||||
using namespace iss::arch;
 | 
			
		||||
 | 
			
		||||
constexpr std::array<const char*, 35>    iss::arch::traits<iss::arch::tgc_c>::reg_names;
 | 
			
		||||
constexpr std::array<const char*, 35>    iss::arch::traits<iss::arch::tgc_c>::reg_aliases;
 | 
			
		||||
constexpr std::array<const uint32_t, 40> iss::arch::traits<iss::arch::tgc_c>::reg_bit_widths;
 | 
			
		||||
constexpr std::array<const uint32_t, 40> iss::arch::traits<iss::arch::tgc_c>::reg_byte_offsets;
 | 
			
		||||
constexpr std::array<const char*, 36>    iss::arch::traits<iss::arch::tgc_c>::reg_names;
 | 
			
		||||
constexpr std::array<const char*, 36>    iss::arch::traits<iss::arch::tgc_c>::reg_aliases;
 | 
			
		||||
constexpr std::array<const uint32_t, 41> iss::arch::traits<iss::arch::tgc_c>::reg_bit_widths;
 | 
			
		||||
constexpr std::array<const uint32_t, 41> iss::arch::traits<iss::arch::tgc_c>::reg_byte_offsets;
 | 
			
		||||
 | 
			
		||||
tgc_c::tgc_c() {
 | 
			
		||||
    reg.icount = 0;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										35
									
								
								src/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								src/main.cpp
									
									
									
									
									
								
							@@ -44,6 +44,11 @@ using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>;
 | 
			
		||||
#include "iss/arch/tgc_b.h"
 | 
			
		||||
using tgc_b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_b>;
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef CORE_TGC_C_XRB_NN
 | 
			
		||||
#include "iss/arch/riscv_hart_m_p.h"
 | 
			
		||||
#include "iss/arch/tgc_c_xrb_nn.h"
 | 
			
		||||
using tgc_c_xrb_nn_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c_xrb_nn>;
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef CORE_TGC_D
 | 
			
		||||
#include "iss/arch/riscv_hart_mu_p.h"
 | 
			
		||||
#include "iss/arch/tgc_d.h"
 | 
			
		||||
@@ -54,6 +59,16 @@ using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d, (iss::arch:
 | 
			
		||||
#include "iss/arch/tgc_d_xrb_mac.h"
 | 
			
		||||
using tgc_d_xrb_mac_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_mac, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef CORE_TGC_D_XRB_NN
 | 
			
		||||
#include "iss/arch/riscv_hart_mu_p.h"
 | 
			
		||||
#include "iss/arch/tgc_d_xrb_nn.h"
 | 
			
		||||
using tgc_d_xrb_nn_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_nn, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef CORE_TGC_E
 | 
			
		||||
#include "iss/arch/riscv_hart_mu_p.h"
 | 
			
		||||
#include "iss/arch/tgc_e.h"
 | 
			
		||||
using tgc_e_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_e, (iss::arch::features_e)(iss::arch::FEAT_PMP | iss::arch::FEAT_CLIC | iss::arch::FEAT_EXT_N)>;
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef WITH_LLVM
 | 
			
		||||
#include <iss/llvm/jit_helper.h>
 | 
			
		||||
#endif
 | 
			
		||||
@@ -142,6 +157,12 @@ int main(int argc, char *argv[]) {
 | 
			
		||||
                iss::create_cpu<tgc_b_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
 | 
			
		||||
        } else
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef CORE_TGC_C_XRB_NN
 | 
			
		||||
        if (isa_opt == "tgc_c_xrb_nn") {
 | 
			
		||||
            std::tie(cpu, vm) =
 | 
			
		||||
                iss::create_cpu<tgc_c_xrb_nn_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
 | 
			
		||||
        } else
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef CORE_TGC_D
 | 
			
		||||
        if (isa_opt == "tgc_d") {
 | 
			
		||||
            std::tie(cpu, vm) =
 | 
			
		||||
@@ -153,9 +174,21 @@ int main(int argc, char *argv[]) {
 | 
			
		||||
            std::tie(cpu, vm) =
 | 
			
		||||
                iss::create_cpu<tgc_d_xrb_mac_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
 | 
			
		||||
        } else
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef CORE_TGC_D_XRB_NN
 | 
			
		||||
        if (isa_opt == "tgc_d_xrb_nn") {
 | 
			
		||||
            std::tie(cpu, vm) =
 | 
			
		||||
                iss::create_cpu<tgc_d_xrb_nn_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
 | 
			
		||||
        } else
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef CORE_TGC_E
 | 
			
		||||
        if (isa_opt == "tgc_e") {
 | 
			
		||||
            std::tie(cpu, vm) =
 | 
			
		||||
                iss::create_cpu<tgc_e_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
 | 
			
		||||
        } else
 | 
			
		||||
#endif
 | 
			
		||||
        {
 | 
			
		||||
            LOG(ERR) << "Illegal argument value for '--isa': " << clim["isa"].as<std::string>() << std::endl;
 | 
			
		||||
            LOG(ERR) << "Illegal argument value for '--isa': " << isa_opt << std::endl;
 | 
			
		||||
            return 127;
 | 
			
		||||
        }
 | 
			
		||||
        if (clim.count("plugin")) {
 | 
			
		||||
 
 | 
			
		||||
@@ -36,58 +36,82 @@
 | 
			
		||||
 | 
			
		||||
#include <iss/arch_if.h>
 | 
			
		||||
#include <util/logging.h>
 | 
			
		||||
#include <rapidjson/document.h>
 | 
			
		||||
#include <rapidjson/istreamwrapper.h>
 | 
			
		||||
#include "rapidjson/writer.h"
 | 
			
		||||
#include "rapidjson/stringbuffer.h"
 | 
			
		||||
#include <rapidjson/ostreamwrapper.h>
 | 
			
		||||
#include <rapidjson/error/en.h>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
 | 
			
		||||
iss::plugin::cycle_estimate::cycle_estimate(std::string config_file_name)
 | 
			
		||||
using namespace rapidjson;
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
iss::plugin::cycle_estimate::cycle_estimate(string const& config_file_name)
 | 
			
		||||
: arch_instr(nullptr)
 | 
			
		||||
, config_file_name(config_file_name)
 | 
			
		||||
{
 | 
			
		||||
    if (config_file_name.length() > 0) {
 | 
			
		||||
        std::ifstream is(config_file_name);
 | 
			
		||||
        if (is.is_open()) {
 | 
			
		||||
            try {
 | 
			
		||||
                is >> root;
 | 
			
		||||
            } catch (Json::RuntimeError &e) {
 | 
			
		||||
                LOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            LOG(ERR) << "Could not open input file " << config_file_name;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
iss::plugin::cycle_estimate::~cycle_estimate() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if& vm) {
 | 
			
		||||
	arch_instr = vm.get_arch()->get_instrumentation_if();
 | 
			
		||||
	if(!arch_instr) return false;
 | 
			
		||||
	const std::string  core_name = arch_instr->core_type_name();
 | 
			
		||||
    Json::Value &val = root[core_name];
 | 
			
		||||
    if(!val.isNull() && val.isArray()){
 | 
			
		||||
    	delays.reserve(val.size());
 | 
			
		||||
    	for(auto it:val){
 | 
			
		||||
    		auto name = it["name"];
 | 
			
		||||
    		auto size = it["size"];
 | 
			
		||||
    		auto delay = it["delay"];
 | 
			
		||||
    		if(!name.isString() || !size.isUInt() || !(delay.isUInt() || delay.isArray())) throw std::runtime_error("JSON parse error");
 | 
			
		||||
    		if(delay.isUInt()){
 | 
			
		||||
				delays.push_back(instr_desc{size.asUInt(), delay.asUInt(), 0});
 | 
			
		||||
    		} else {
 | 
			
		||||
				delays.push_back(instr_desc{size.asUInt(), delay[0].asUInt(), delay[1].asUInt()});
 | 
			
		||||
    		}
 | 
			
		||||
    	}
 | 
			
		||||
    } else {
 | 
			
		||||
        LOG(ERR)<<"plugin cycle_estimate: could not find an entry for "<<core_name<<" in JSON file"<<std::endl;
 | 
			
		||||
    arch_instr = vm.get_arch()->get_instrumentation_if();
 | 
			
		||||
    if(!arch_instr) return false;
 | 
			
		||||
    const string  core_name = arch_instr->core_type_name();
 | 
			
		||||
    if (config_file_name.length() > 0) {
 | 
			
		||||
        ifstream is(config_file_name);
 | 
			
		||||
        if (is.is_open()) {
 | 
			
		||||
            try {
 | 
			
		||||
                IStreamWrapper isw(is);
 | 
			
		||||
                Document d;
 | 
			
		||||
                ParseResult ok = d.ParseStream(isw);
 | 
			
		||||
                if(ok) {
 | 
			
		||||
                    Value& val = d[core_name.c_str()];
 | 
			
		||||
                    if(val.IsArray()){
 | 
			
		||||
                        delays.reserve(val.Size());
 | 
			
		||||
                        for (auto it = val.Begin(); it != val.End(); ++it) {
 | 
			
		||||
                            auto& name = (*it)["name"];
 | 
			
		||||
                            auto& size = (*it)["size"];
 | 
			
		||||
                            auto& delay = (*it)["delay"];
 | 
			
		||||
                            auto& branch = (*it)["branch"];
 | 
			
		||||
                            if(delay.IsArray()) {
 | 
			
		||||
                                auto dt = delay[0].Get<unsigned>();
 | 
			
		||||
                                auto dnt = delay[1].Get<unsigned>();
 | 
			
		||||
                                delays.push_back(instr_desc{size.Get<unsigned>(), dt, dnt, branch.Get<bool>()});
 | 
			
		||||
                            } else if(delay.Is<unsigned>()) {
 | 
			
		||||
                                auto d = delay.Get<unsigned>();
 | 
			
		||||
                                delays.push_back(instr_desc{size.Get<unsigned>(), d, d, branch.Get<bool>()});
 | 
			
		||||
                            } else
 | 
			
		||||
                                throw runtime_error("JSON parse error");
 | 
			
		||||
                       }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        LOG(ERR)<<"plugin cycle_estimate: could not find an entry for "<<core_name<<" in JSON file"<<endl;
 | 
			
		||||
                        return false;
 | 
			
		||||
                   }
 | 
			
		||||
                } else {
 | 
			
		||||
                    LOG(ERR)<<"plugin cycle_estimate: could not parse in JSON file at "<< ok.Offset()<<": "<<GetParseError_En(ok.Code())<<endl;
 | 
			
		||||
                    return false;
 | 
			
		||||
               }
 | 
			
		||||
            } catch (runtime_error &e) {
 | 
			
		||||
                LOG(ERR) << "Could not parse input file " << config_file_name << ", reason: " << e.what();
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            LOG(ERR) << "Could not open input file " << config_file_name;
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
	return true;
 | 
			
		||||
    return true;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void iss::plugin::cycle_estimate::callback(instr_info_t instr_info, exec_info const&) {
 | 
			
		||||
void iss::plugin::cycle_estimate::callback(instr_info_t instr_info, exec_info const& exc_info) {
 | 
			
		||||
    assert(arch_instr && "No instrumentation interface available but callback executed");
 | 
			
		||||
	auto entry = delays[instr_info.instr_id];
 | 
			
		||||
	bool taken = (arch_instr->get_next_pc()-arch_instr->get_pc()) != (entry.size/8);
 | 
			
		||||
    if (taken && entry.taken > 1)
 | 
			
		||||
    auto entry = delays[instr_info.instr_id];
 | 
			
		||||
    bool taken = exc_info.branch_taken;
 | 
			
		||||
    if (exc_info.branch_taken && (entry.taken > 1))
 | 
			
		||||
        arch_instr->set_curr_instr_cycles(entry.taken);
 | 
			
		||||
    else if (entry.not_taken > 1)
 | 
			
		||||
        arch_instr->set_curr_instr_cycles(entry.not_taken);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										133
									
								
								src/plugin/pctrace.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								src/plugin/pctrace.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,133 @@
 | 
			
		||||
#include <iss/arch_if.h>
 | 
			
		||||
#include <iss/plugin/pctrace.h>
 | 
			
		||||
#include <util/logging.h>
 | 
			
		||||
#include <rapidjson/document.h>
 | 
			
		||||
#include <rapidjson/istreamwrapper.h>
 | 
			
		||||
#include "rapidjson/writer.h"
 | 
			
		||||
#include "rapidjson/stringbuffer.h"
 | 
			
		||||
#include <rapidjson/ostreamwrapper.h>
 | 
			
		||||
#include <rapidjson/error/en.h>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
using namespace rapidjson;
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
iss::plugin::cov::cov(std::string const &filename)
 | 
			
		||||
    : instr_if(nullptr)
 | 
			
		||||
    , filename(filename)
 | 
			
		||||
{
 | 
			
		||||
    output.open("output.trc");
 | 
			
		||||
    jumped = false;
 | 
			
		||||
    first = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
iss::plugin::cov::~cov() {
 | 
			
		||||
    output.close();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool iss::plugin::cov::registration(const char *const version, vm_if& vm) {
 | 
			
		||||
    instr_if = vm.get_arch()->get_instrumentation_if();
 | 
			
		||||
    if(!instr_if) return false;
 | 
			
		||||
    const string  core_name = instr_if->core_type_name();
 | 
			
		||||
    if (filename.length() > 0) {
 | 
			
		||||
        ifstream is(filename);
 | 
			
		||||
        if (is.is_open()) {
 | 
			
		||||
            try {
 | 
			
		||||
                IStreamWrapper isw(is);
 | 
			
		||||
                Document d;
 | 
			
		||||
                ParseResult ok = d.ParseStream(isw);
 | 
			
		||||
                if(ok) {
 | 
			
		||||
                    Value& val = d[core_name.c_str()];
 | 
			
		||||
                    if(val.IsArray()){
 | 
			
		||||
                        delays.reserve(val.Size());
 | 
			
		||||
                        for (auto it = val.Begin(); it != val.End(); ++it) {
 | 
			
		||||
                            auto& name = (*it)["name"];
 | 
			
		||||
                            auto& size = (*it)["size"];
 | 
			
		||||
                            auto& delay = (*it)["delay"];
 | 
			
		||||
                            auto& branch = (*it)["branch"];
 | 
			
		||||
                            if(delay.IsArray()) {
 | 
			
		||||
                                auto dt = delay[0].Get<unsigned>();
 | 
			
		||||
                                auto dnt = delay[1].Get<unsigned>();
 | 
			
		||||
                                delays.push_back(instr_desc{size.Get<unsigned>(), dt, dnt, branch.Get<bool>()});
 | 
			
		||||
                            } else if(delay.Is<unsigned>()) {
 | 
			
		||||
                                auto d = delay.Get<unsigned>();
 | 
			
		||||
                                delays.push_back(instr_desc{size.Get<unsigned>(), d, d, branch.Get<bool>()});
 | 
			
		||||
                            } else
 | 
			
		||||
                                throw runtime_error("JSON parse error");
 | 
			
		||||
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        LOG(ERR)<<"plugin cycle_estimate: could not find an entry for "<<core_name<<" in JSON file"<<endl;
 | 
			
		||||
                        return false;
 | 
			
		||||
                   }
 | 
			
		||||
                } else {
 | 
			
		||||
                    LOG(ERR)<<"plugin cycle_estimate: could not parse in JSON file at "<< ok.Offset()<<": "<<GetParseError_En(ok.Code())<<endl;
 | 
			
		||||
                    return false;
 | 
			
		||||
               }
 | 
			
		||||
            } catch (runtime_error &e) {
 | 
			
		||||
                LOG(ERR) << "Could not parse input file " << filename << ", reason: " << e.what();
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            LOG(ERR) << "Could not open input file " << filename;
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline string formatPC(uint64_t pc) {
 | 
			
		||||
    stringstream stream;
 | 
			
		||||
    stream << "0x" << std::hex << pc;
 | 
			
		||||
    return stream.str();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void iss::plugin::cov::callback(instr_info_t iinfo, const exec_info& einfo) {
 | 
			
		||||
//    auto delay = 0;
 | 
			
		||||
//    auto entry = delays[iinfo.instr_id];
 | 
			
		||||
//    bool taken = einfo.branch_taken;
 | 
			
		||||
//    if (einfo.branch_taken)
 | 
			
		||||
//        delay = entry.taken;
 | 
			
		||||
//    else
 | 
			
		||||
//        delay = entry.not_taken;
 | 
			
		||||
//
 | 
			
		||||
//    if (first){
 | 
			
		||||
//        output << formatPC(instr_if->get_pc()) << "," << delay;
 | 
			
		||||
//        first = false;
 | 
			
		||||
//    }
 | 
			
		||||
//    if(instr_if->get_next_pc()-instr_if->get_pc() != delays[iinfo.instr_id].size/8){
 | 
			
		||||
//        //The goal is to keep the output in start-target pairs, so after a jump the target address needs to get written
 | 
			
		||||
//        //to the output. If the target happens to also be a start, we keep the pairing by adding a 0-delay entry.
 | 
			
		||||
//        if (jumped)
 | 
			
		||||
//            output <<"\n" <<formatPC(instr_if->get_pc()) << "," << 0;
 | 
			
		||||
//        output <<"\n" << formatPC(instr_if->get_pc()) << "," << delay;
 | 
			
		||||
//        jumped = true;
 | 
			
		||||
//    }
 | 
			
		||||
//    else{
 | 
			
		||||
//        if (jumped){
 | 
			
		||||
//            output <<"\n" << formatPC(instr_if->get_pc()) << "," << delay;
 | 
			
		||||
//            jumped = false;
 | 
			
		||||
//        }
 | 
			
		||||
//        else if(delay!=1){
 | 
			
		||||
//            output <<"\n" << formatPC(instr_if->get_pc()) << "," << delay;
 | 
			
		||||
//            output <<"\n" << formatPC(instr_if->get_pc()) << "," << 0;
 | 
			
		||||
//        }
 | 
			
		||||
//
 | 
			
		||||
//    }
 | 
			
		||||
 | 
			
		||||
//source code for the full output
 | 
			
		||||
    auto delay = 0;
 | 
			
		||||
    auto entry = delays[iinfo.instr_id];
 | 
			
		||||
    bool taken = einfo.branch_taken;
 | 
			
		||||
    if (einfo.branch_taken)
 | 
			
		||||
        delay = entry.taken;
 | 
			
		||||
    else
 | 
			
		||||
       delay = entry.not_taken;
 | 
			
		||||
    output<<std::hex <<"0x" << instr_if->get_pc() <<"," << delay << "\n";
 | 
			
		||||
}
 | 
			
		||||
@@ -57,6 +57,11 @@ using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d, iss::arch::
 | 
			
		||||
#include "iss/arch/tgc_d_xrb_mac.h"
 | 
			
		||||
using tgc_d_xrb_mac_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_mac, iss::arch::FEAT_PMP>;
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef CORE_TGC_D_XRB_NN
 | 
			
		||||
#include "iss/arch/riscv_hart_mu_p.h"
 | 
			
		||||
#include "iss/arch/tgc_d_xrb_nn.h"
 | 
			
		||||
using tgc_d_xrb_nn_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_nn, iss::arch::FEAT_PMP>;
 | 
			
		||||
#endif
 | 
			
		||||
#include <scc/report.h>
 | 
			
		||||
#include <util/ities.h>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
@@ -64,13 +69,15 @@ using tgc_d_xrb_mac_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d_xrb_
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <iss/plugin/cycle_estimate.h>
 | 
			
		||||
#include <iss/plugin/instruction_count.h>
 | 
			
		||||
#include <iss/plugin/pctrace.h>
 | 
			
		||||
 | 
			
		||||
// clang-format on
 | 
			
		||||
 | 
			
		||||
#define STR(X) #X
 | 
			
		||||
#define CREATE_CORE(CN) \
 | 
			
		||||
if (type == STR(CN)) { std::tie(cpu, vm) = create_core<CN ## _plat_type>(backend, gdb_port, hart_id); } else
 | 
			
		||||
 | 
			
		||||
#ifdef WITH_SCV
 | 
			
		||||
#ifdef HAS_SCV
 | 
			
		||||
#include <scv.h>
 | 
			
		||||
#else
 | 
			
		||||
#include <scv-tr.h>
 | 
			
		||||
@@ -129,7 +136,8 @@ public:
 | 
			
		||||
        if (!owner->disass_output(pc, instr)) {
 | 
			
		||||
            std::stringstream s;
 | 
			
		||||
            s << "[p:" << lvl[this->reg.PRIV] << ";s:0x" << std::hex << std::setfill('0')
 | 
			
		||||
              << std::setw(sizeof(reg_t) * 2) << (reg_t)this->state.mstatus << std::dec << ";c:" << this->reg.icount << "]";
 | 
			
		||||
              << std::setw(sizeof(reg_t) * 2) << (reg_t)this->state.mstatus << std::dec << ";c:"
 | 
			
		||||
              << this->reg.icount + this->cycle_offset << "]";
 | 
			
		||||
            SCCDEBUG(owner->name())<<"disass: "
 | 
			
		||||
                << "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t" << std::setw(40)
 | 
			
		||||
                << std::setfill(' ') << std::left << instr << s.str();
 | 
			
		||||
@@ -303,8 +311,11 @@ public:
 | 
			
		||||
#ifdef CORE_TGC_D
 | 
			
		||||
        CREATE_CORE(tgc_d)
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef CORE_TGC_D_XRB_MACD
 | 
			
		||||
#ifdef CORE_TGC_D_XRB_MAC
 | 
			
		||||
        CREATE_CORE(tgc_d_xrb_mac)
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef CORE_TGC_D_XRB_NN
 | 
			
		||||
        CREATE_CORE(tgc_d_xrb_nn)
 | 
			
		||||
#endif
 | 
			
		||||
        {
 | 
			
		||||
            LOG(ERR) << "Illegal argument value for core type: " << type << std::endl;
 | 
			
		||||
@@ -397,7 +408,7 @@ void core_complex::before_end_of_elaboration() {
 | 
			
		||||
    cpu->create_cpu(GET_PROP_VALUE(core_type), GET_PROP_VALUE(backend), GET_PROP_VALUE(gdb_server_port), GET_PROP_VALUE(mhartid));
 | 
			
		||||
    sc_assert(cpu->vm!=nullptr);
 | 
			
		||||
    cpu->vm->setDisassEnabled(GET_PROP_VALUE(enable_disass) || trc->m_db != nullptr);
 | 
			
		||||
    if (GET_PROP_VALUE(core_type).length()) {
 | 
			
		||||
    if (GET_PROP_VALUE(plugins).length()) {
 | 
			
		||||
        auto p = util::split(GET_PROP_VALUE(plugins), ';');
 | 
			
		||||
        for (std::string const& opt_val : p) {
 | 
			
		||||
            std::string plugin_name=opt_val;
 | 
			
		||||
@@ -415,6 +426,10 @@ void core_complex::before_end_of_elaboration() {
 | 
			
		||||
                auto *plugin = new iss::plugin::cycle_estimate(filename);
 | 
			
		||||
                cpu->vm->register_plugin(*plugin);
 | 
			
		||||
                plugin_list.push_back(plugin);
 | 
			
		||||
            } else if (plugin_name == "pctrace") {
 | 
			
		||||
                auto *plugin = new iss::plugin::cov(filename);
 | 
			
		||||
                cpu->vm->register_plugin(*plugin);
 | 
			
		||||
                plugin_list.push_back(plugin);
 | 
			
		||||
            } else {
 | 
			
		||||
                std::array<char const*, 1> a{{filename.c_str()}};
 | 
			
		||||
                iss::plugin::loader l(plugin_name, {{"initPlugin"}});
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Reference in New Issue
	
	Block a user