Compare commits
50 Commits
hotfix/lat
...
e432dd8208
Author | SHA1 | Date | |
---|---|---|---|
e432dd8208 | |||
8c385647dd | |||
aaceecd5dc | |||
4b3f5a6b0c | |||
d41e1d816a | |||
a35974c9f5 | |||
9c456ba8f2 | |||
c57884caee | |||
cf7b62a3f9 | |||
f2bf6d682a | |||
a1fa8877f7 | |||
391f9bb808 | |||
ef02dba8c5 | |||
2f4cfb68dc | |||
7009943106 | |||
0a76ccbdac | |||
32e4aa83b8 | |||
78c7064295 | |||
412a4bd9bb | |||
b0bcb7febb | |||
51fbc34fb3 | |||
4e0f20eba0 | |||
ff3fa19208 | |||
80057eef32 | |||
a5186ff88d | |||
f4ec21007b | |||
ac8eab6e25 | |||
768716b064 | |||
bea0dcc387 | |||
a6691bcd3c | |||
40db74ce02 | |||
c171e3c1ba | |||
c251fe15d5 | |||
dae8acb8a3 | |||
f7cec99fa6 | |||
be0e7db185 | |||
4aa26b85a0 | |||
9534d58d01 | |||
1668df0531 | |||
d8e009c72b | |||
d07c8679ed | |||
3d5b61f301 | |||
337f1634c0 | |||
72b09472d5 | |||
3261055871 | |||
34bb8e62ae | |||
da7e29fbb7 | |||
c4da47cedd | |||
ab554539e3 | |||
d43b35949e |
104
CMakeLists.txt
104
CMakeLists.txt
@ -1,6 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
|
||||
project("riscv" VERSION 1.0.0)
|
||||
project(dbt-core-tgc VERSION 1.0.0)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
@ -27,78 +27,90 @@ endif()
|
||||
add_subdirectory(softfloat)
|
||||
|
||||
# library files
|
||||
FILE(GLOB RiscVSCHeaders ${CMAKE_CURRENT_SOURCE_DIR}/incl/sysc/*.h ${CMAKE_CURRENT_SOURCE_DIR}/incl/sysc/*/*.h)
|
||||
set(LIB_HEADERS ${RiscVSCHeaders} )
|
||||
FILE(GLOB TGC_SOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/iss/*.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/vm/interp/vm_*.cpp
|
||||
)
|
||||
set(LIB_SOURCES
|
||||
src/iss/tgf_b.cpp
|
||||
src/iss/tgf_c.cpp
|
||||
src/vm/fp_functions.cpp
|
||||
src/vm/tcc/vm_tgf_b.cpp
|
||||
src/vm/tcc/vm_tgf_c.cpp
|
||||
src/vm/interp/vm_tgf_b.cpp
|
||||
src/vm/interp/vm_tgf_c.cpp
|
||||
src/plugin/instruction_count.cpp
|
||||
src/plugin/cycle_estimate.cpp
|
||||
${TGC_SOURCES}
|
||||
)
|
||||
|
||||
if(WITH_LLVM)
|
||||
set(LIB_SOURCES ${LIB_SOURCES}
|
||||
set(LIB_SOURCES ${LIB_SOURCES}
|
||||
src/vm/llvm/fp_impl.cpp
|
||||
src/vm/llvm/vm_tgf_b.cpp
|
||||
src/vm/llvm/vm_tgf_c.cpp
|
||||
)
|
||||
#src/vm/llvm/vm_tgf_b.cpp
|
||||
#src/vm/llvm/vm_tgf_c.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
# Define the library
|
||||
add_library(riscv SHARED ${LIB_SOURCES})
|
||||
target_compile_options(riscv PRIVATE -Wno-shift-count-overflow)
|
||||
target_include_directories(riscv PUBLIC incl ../external/elfio)
|
||||
target_link_libraries(riscv PUBLIC softfloat scc-util jsoncpp)
|
||||
target_link_libraries(riscv PUBLIC -Wl,--whole-archive dbt-core -Wl,--no-whole-archive)
|
||||
set_target_properties(riscv PROPERTIES
|
||||
add_library(${PROJECT_NAME} SHARED ${LIB_SOURCES})
|
||||
# list code gen dependencies
|
||||
if(TARGET ${CORE_NAME}_cpp)
|
||||
add_dependencies(${PROJECT_NAME} ${CORE_NAME}_cpp)
|
||||
endif()
|
||||
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE -Wno-shift-count-overflow)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC incl)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC softfloat scc-util jsoncpp)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC -Wl,--whole-archive dbt-core -Wl,--no-whole-archive)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${Boost_LIBRARIES} )
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
FRAMEWORK FALSE
|
||||
PUBLIC_HEADER "${LIB_HEADERS}" # specify the public headers
|
||||
)
|
||||
|
||||
if(SystemC_FOUND)
|
||||
add_library(riscv_sc src/sysc/core_complex.cpp)
|
||||
target_compile_definitions(riscv_sc PUBLIC WITH_SYSTEMC)
|
||||
target_include_directories(riscv_sc PUBLIC ../incl ${SystemC_INCLUDE_DIRS} ${CCI_INCLUDE_DIRS})
|
||||
add_library(${PROJECT_NAME}_sc src/sysc/core_complex.cpp)
|
||||
target_compile_definitions(${PROJECT_NAME}_sc 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}_sc PRIVATE CORE_TGC_B)
|
||||
endif()
|
||||
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss/arch/tgc_c.h)
|
||||
target_compile_definitions(${PROJECT_NAME}_sc PRIVATE CORE_TGC_C)
|
||||
endif()
|
||||
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/incl/iss/arch/tgc_d.h)
|
||||
target_compile_definitions(${PROJECT_NAME}_sc PRIVATE CORE_TGC_D)
|
||||
endif()
|
||||
target_include_directories(${PROJECT_NAME}_sc PUBLIC ../incl ${SystemC_INCLUDE_DIRS} ${CCI_INCLUDE_DIRS})
|
||||
|
||||
if(SCV_FOUND)
|
||||
target_compile_definitions(riscv_sc PUBLIC WITH_SCV)
|
||||
target_include_directories(riscv_sc PUBLIC ${SCV_INCLUDE_DIRS})
|
||||
target_compile_definitions(${PROJECT_NAME}_sc PUBLIC WITH_SCV)
|
||||
target_include_directories(${PROJECT_NAME}_sc PUBLIC ${SCV_INCLUDE_DIRS})
|
||||
endif()
|
||||
target_link_libraries(riscv_sc PUBLIC riscv scc )
|
||||
target_link_libraries(${PROJECT_NAME}_sc PUBLIC ${PROJECT_NAME} scc)
|
||||
if(WITH_LLVM)
|
||||
target_link_libraries(riscv_sc PUBLIC ${llvm_libs})
|
||||
target_link_libraries(${PROJECT_NAME}_sc PUBLIC ${llvm_libs})
|
||||
endif()
|
||||
target_link_libraries(riscv_sc PUBLIC ${Boost_LIBRARIES} )
|
||||
set_target_properties(riscv_sc PROPERTIES
|
||||
set_target_properties(${PROJECT_NAME}_sc PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
FRAMEWORK FALSE
|
||||
PUBLIC_HEADER "${LIB_HEADERS}" # specify the public headers
|
||||
)
|
||||
endif()
|
||||
|
||||
project("riscv-sim")
|
||||
add_executable(riscv-sim src/main.cpp)
|
||||
project(tgc-sim)
|
||||
add_executable(${PROJECT_NAME} src/main.cpp)
|
||||
# This sets the include directory for the reference project. This is the -I flag in gcc.
|
||||
target_include_directories(riscv-sim PRIVATE ../external/libGIS)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
|
||||
if(WITH_LLVM)
|
||||
target_compile_definitions(riscv-sim PRIVATE WITH_LLVM)
|
||||
target_link_libraries(riscv-sim PUBLIC ${llvm_libs})
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_LLVM)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
|
||||
endif()
|
||||
# Links the target exe against the libraries
|
||||
target_link_libraries(riscv-sim riscv)
|
||||
target_link_libraries(riscv-sim jsoncpp)
|
||||
target_link_libraries(riscv-sim external)
|
||||
target_link_libraries(riscv-sim ${Boost_LIBRARIES} )
|
||||
target_link_libraries(${PROJECT_NAME} dbt-core-tgc)
|
||||
target_link_libraries(${PROJECT_NAME} jsoncpp)
|
||||
target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES} )
|
||||
if (Tcmalloc_FOUND)
|
||||
target_link_libraries(riscv-sim ${Tcmalloc_LIBRARIES})
|
||||
target_link_libraries(${PROJECT_NAME} ${Tcmalloc_LIBRARIES})
|
||||
endif(Tcmalloc_FOUND)
|
||||
|
||||
install(TARGETS riscv riscv-sim
|
||||
install(TARGETS dbt-core-tgc tgc-sim
|
||||
EXPORT ${PROJECT_NAME}Targets # for downstream dependencies
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libs # static lib
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT libs # binaries
|
||||
@ -107,17 +119,3 @@ install(TARGETS riscv riscv-sim
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} COMPONENT devel # headers for mac (note the different component -> different package)
|
||||
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} # headers
|
||||
)
|
||||
|
||||
|
||||
|
||||
#
|
||||
# SYSTEM PACKAGING (RPM, TGZ, ...)
|
||||
# _____________________________________________________________________________
|
||||
|
||||
#include(CPackConfig)
|
||||
|
||||
#
|
||||
# CMAKE PACKAGING (for other CMake projects to use this one easily)
|
||||
# _____________________________________________________________________________
|
||||
|
||||
#include(PackageConfigurator)
|
||||
|
Submodule gen_input/CoreDSL-Instruction-Set-Description updated: 3bb3763e92...cf601042ed
@ -2,27 +2,36 @@ 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 TGF_B provides RV32I {
|
||||
constants {
|
||||
XLEN:=32;
|
||||
PCLEN:=32;
|
||||
Core TGC_B provides RV32I {
|
||||
architectural_state {
|
||||
unsigned XLEN=32;
|
||||
unsigned PCLEN=32;
|
||||
// definitions for the architecture wrapper
|
||||
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
|
||||
MISA_VAL:=0b01000000000000000000000100000000;
|
||||
PGSIZE := 0x1000; //1 << 12;
|
||||
PGMASK := 0xfff; //PGSIZE-1
|
||||
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
|
||||
unsigned MISA_VAL = 0b01000000000000000000000100000000;
|
||||
unsigned PGSIZE = 0x1000; //1 << 12;
|
||||
unsigned PGMASK = 0xfff; //PGSIZE-1
|
||||
}
|
||||
}
|
||||
|
||||
Core TGF_C provides RV32I, RV32M, RV32IC {
|
||||
constants {
|
||||
XLEN:=32;
|
||||
PCLEN:=32;
|
||||
MUL_LEN:=64;
|
||||
Core TGC_C provides RV32I, RV32M, RV32IC {
|
||||
architectural_state {
|
||||
unsigned XLEN=32;
|
||||
unsigned PCLEN=32;
|
||||
// definitions for the architecture wrapper
|
||||
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
|
||||
MISA_VAL:=0b01000000000000000001000100000100;
|
||||
PGSIZE := 0x1000; //1 << 12;
|
||||
PGMASK := 0xfff; //PGSIZE-1
|
||||
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
|
||||
unsigned MISA_VAL = 0b01000000000000000001000100000100;
|
||||
unsigned PGSIZE = 0x1000; //1 << 12;
|
||||
unsigned PGMASK = 0xfff; //PGSIZE-1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Core TGC_D provides RV32I, RV32M, RV32IC {
|
||||
architectural_state {
|
||||
unsigned XLEN=32;
|
||||
unsigned PCLEN=32;
|
||||
// definitions for the architecture wrapper
|
||||
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
|
||||
unsigned MISA_VAL = 0b01000000000000000001000100000100;
|
||||
}
|
||||
}
|
||||
|
@ -1,74 +0,0 @@
|
||||
import "RV32I.core_desc"
|
||||
import "RV64I.core_desc"
|
||||
import "RVM.core_desc"
|
||||
import "RVA.core_desc"
|
||||
import "RVC.core_desc"
|
||||
import "RVF.core_desc"
|
||||
import "RVD.core_desc"
|
||||
|
||||
|
||||
Core MNRV32 provides RV32I, RV32IC {
|
||||
constants {
|
||||
XLEN:=32;
|
||||
PCLEN:=32;
|
||||
// definitions for the architecture wrapper
|
||||
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
|
||||
MISA_VAL:=0b01000000000101000001000100000101;
|
||||
PGSIZE := 0x1000; //1 << 12;
|
||||
PGMASK := 0xfff; //PGSIZE-1
|
||||
}
|
||||
}
|
||||
|
||||
Core RV32IMAC provides RV32I, RV32M, RV32A, RV32IC {
|
||||
constants {
|
||||
XLEN:=32;
|
||||
PCLEN:=32;
|
||||
MUL_LEN:=64;
|
||||
// definitions for the architecture wrapper
|
||||
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
|
||||
MISA_VAL:=0b01000000000101000001000100000101;
|
||||
PGSIZE := 0x1000; //1 << 12;
|
||||
PGMASK := 0xfff; //PGSIZE-1
|
||||
}
|
||||
}
|
||||
|
||||
Core RV32GC provides RV32I, RV32M, RV32A, RV32F, RV32D, RV32IC, RV32FC, RV32DC {
|
||||
constants {
|
||||
XLEN:=32;
|
||||
FLEN:=64;
|
||||
PCLEN:=32;
|
||||
MUL_LEN:=64;
|
||||
// definitions for the architecture wrapper
|
||||
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
|
||||
MISA_VAL:=0b01000000000101000001000100101101;
|
||||
PGSIZE := 0x1000; //1 << 12;
|
||||
PGMASK := 0xfff; //PGSIZE-1
|
||||
}
|
||||
}
|
||||
|
||||
Core RV64I provides RV64I {
|
||||
constants {
|
||||
XLEN:=64;
|
||||
PCLEN:=64;
|
||||
// definitions for the architecture wrapper
|
||||
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
|
||||
MISA_VAL:=0b10000000000001000000000100000000;
|
||||
PGSIZE := 0x1000; //1 << 12;
|
||||
PGMASK := 0xfff; //PGSIZE-1
|
||||
}
|
||||
}
|
||||
|
||||
Core RV64GC provides RV64I, RV64M, RV64A, RV64F, RV64D, RV32FC, RV32DC, RV64IC {
|
||||
constants {
|
||||
XLEN:=64;
|
||||
FLEN:=64;
|
||||
PCLEN:=64;
|
||||
MUL_LEN:=128;
|
||||
// definitions for the architecture wrapper
|
||||
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA
|
||||
MISA_VAL:=0b01000000000101000001000100101101;
|
||||
PGSIZE := 0x1000; //1 << 12;
|
||||
PGMASK := 0xfff; //PGSIZE-1
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
|
||||
* Copyright (C) 2017 - 2020 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -29,43 +29,12 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*******************************************************************************/
|
||||
<%
|
||||
import com.minres.coredsl.coreDsl.Register
|
||||
import com.minres.coredsl.coreDsl.RegisterFile
|
||||
import com.minres.coredsl.coreDsl.RegisterAlias
|
||||
def getOriginalName(reg){
|
||||
if( reg.original instanceof RegisterFile) {
|
||||
if( reg.index != null ) {
|
||||
return reg.original.name+generator.generateHostCode(reg.index)
|
||||
} else {
|
||||
return reg.original.name
|
||||
}
|
||||
} else if(reg.original instanceof Register){
|
||||
return reg.original.name
|
||||
}
|
||||
}
|
||||
def getRegisterNames(){
|
||||
def regNames = []
|
||||
allRegs.each { reg ->
|
||||
if( reg instanceof RegisterFile) {
|
||||
(reg.range.right..reg.range.left).each{
|
||||
regNames+=reg.name.toLowerCase()+it
|
||||
}
|
||||
} else if(reg instanceof Register){
|
||||
regNames+=reg.name.toLowerCase()
|
||||
}
|
||||
}
|
||||
return regNames
|
||||
}
|
||||
def getRegisterAliasNames(){
|
||||
def regMap = allRegs.findAll{it instanceof RegisterAlias }.collectEntries {[getOriginalName(it), it.name]}
|
||||
return allRegs.findAll{it instanceof Register || it instanceof RegisterFile}.collect{reg ->
|
||||
if( reg instanceof RegisterFile) {
|
||||
return (reg.range.right..reg.range.left).collect{ (regMap[reg.name]?:regMap[reg.name+it]?:reg.name.toLowerCase()+it).toLowerCase() }
|
||||
} else if(reg instanceof Register){
|
||||
regMap[reg.name]?:reg.name.toLowerCase()
|
||||
}
|
||||
}.flatten()
|
||||
<%
|
||||
def getRegisterSizes(){
|
||||
def regs = registers.collect{it.size}
|
||||
regs[-1]=64 // correct for NEXT_PC
|
||||
regs+=[32, 32, 64] // append TRAP_STATE, PENDING_TRAP, ICOUNT
|
||||
return regs
|
||||
}
|
||||
%>
|
||||
#include "util/ities.h"
|
||||
@ -77,10 +46,10 @@ def getRegisterAliasNames(){
|
||||
|
||||
using namespace iss::arch;
|
||||
|
||||
constexpr std::array<const char*, ${getRegisterNames().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_names;
|
||||
constexpr std::array<const char*, ${getRegisterAliasNames().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_aliases;
|
||||
constexpr std::array<const uint32_t, ${regSizes.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_bit_widths;
|
||||
constexpr std::array<const uint32_t, ${regOffsets.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_byte_offsets;
|
||||
constexpr std::array<const char*, ${registers.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_names;
|
||||
constexpr std::array<const char*, ${registers.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_aliases;
|
||||
constexpr std::array<const uint32_t, ${getRegisterSizes().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_bit_widths;
|
||||
constexpr std::array<const uint32_t, ${getRegisterSizes().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_byte_offsets;
|
||||
|
||||
${coreDef.name.toLowerCase()}::${coreDef.name.toLowerCase()}() {
|
||||
reg.icount = 0;
|
||||
@ -92,8 +61,8 @@ void ${coreDef.name.toLowerCase()}::reset(uint64_t address) {
|
||||
for(size_t i=0; i<traits<${coreDef.name.toLowerCase()}>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<${coreDef.name.toLowerCase()}>::reg_t),0));
|
||||
reg.PC=address;
|
||||
reg.NEXT_PC=reg.PC;
|
||||
reg.PRIV=0x3;
|
||||
reg.trap_state=0;
|
||||
reg.machine_state=0x3;
|
||||
reg.icount=0;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
|
||||
* Copyright (C) 2017 - 2021 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -29,47 +29,38 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*******************************************************************************/
|
||||
<%
|
||||
import com.minres.coredsl.util.BigIntegerWithRadix
|
||||
|
||||
<%
|
||||
import com.minres.coredsl.coreDsl.Register
|
||||
import com.minres.coredsl.coreDsl.RegisterFile
|
||||
import com.minres.coredsl.coreDsl.RegisterAlias
|
||||
def getTypeSize(size){
|
||||
if(size > 32) 64 else if(size > 16) 32 else if(size > 8) 16 else 8
|
||||
def nativeTypeSize(int size){
|
||||
if(size<=8) return 8; else if(size<=16) return 16; else if(size<=32) return 32; else return 64;
|
||||
}
|
||||
def getOriginalName(reg){
|
||||
if( reg.original instanceof RegisterFile) {
|
||||
if( reg.index != null ) {
|
||||
return reg.original.name+generator.generateHostCode(reg.index)
|
||||
} else {
|
||||
return reg.original.name
|
||||
}
|
||||
} else if(reg.original instanceof Register){
|
||||
return reg.original.name
|
||||
def getRegisterSizes(){
|
||||
def regs = registers.collect{nativeTypeSize(it.size)}
|
||||
regs+=[32,32, 64] // append TRAP_STATE, PENDING_TRAP, ICOUNT
|
||||
return regs
|
||||
}
|
||||
def getRegisterOffsets(){
|
||||
def offset = 0
|
||||
def offsets = []
|
||||
getRegisterSizes().each { size ->
|
||||
offsets<<offset
|
||||
offset+=size/8
|
||||
}
|
||||
return offsets
|
||||
}
|
||||
def getRegisterNames(){
|
||||
def regNames = []
|
||||
allRegs.each { reg ->
|
||||
if( reg instanceof RegisterFile) {
|
||||
(reg.range.right..reg.range.left).each{
|
||||
regNames+=reg.name.toLowerCase()+it
|
||||
}
|
||||
} else if(reg instanceof Register){
|
||||
regNames+=reg.name.toLowerCase()
|
||||
}
|
||||
}
|
||||
return regNames
|
||||
def byteSize(int size){
|
||||
if(size<=8) return 8;
|
||||
if(size<=16) return 16;
|
||||
if(size<=32) return 32;
|
||||
if(size<=64) return 64;
|
||||
return 128;
|
||||
}
|
||||
def getRegisterAliasNames(){
|
||||
def regMap = allRegs.findAll{it instanceof RegisterAlias }.collectEntries {[getOriginalName(it), it.name]}
|
||||
return allRegs.findAll{it instanceof Register || it instanceof RegisterFile}.collect{reg ->
|
||||
if( reg instanceof RegisterFile) {
|
||||
return (reg.range.right..reg.range.left).collect{ (regMap[reg.name]?:regMap[reg.name+it]?:reg.name.toLowerCase()+it).toLowerCase() }
|
||||
} else if(reg instanceof Register){
|
||||
regMap[reg.name]?:reg.name.toLowerCase()
|
||||
}
|
||||
}.flatten()
|
||||
def getCString(def val){
|
||||
if(val instanceof BigIntegerWithRadix)
|
||||
return ((BigIntegerWithRadix)val).toCString()
|
||||
else
|
||||
return val.toString()
|
||||
}
|
||||
%>
|
||||
#ifndef _${coreDef.name.toUpperCase()}_H_
|
||||
@ -87,43 +78,26 @@ struct ${coreDef.name.toLowerCase()};
|
||||
|
||||
template <> struct traits<${coreDef.name.toLowerCase()}> {
|
||||
|
||||
constexpr static char const* const core_type = "${coreDef.name}";
|
||||
constexpr static char const* const core_type = "${coreDef.name}";
|
||||
|
||||
static constexpr std::array<const char*, ${getRegisterNames().size}> reg_names{
|
||||
{"${getRegisterNames().join("\", \"")}"}};
|
||||
static constexpr std::array<const char*, ${registers.size}> reg_names{
|
||||
{"${registers.collect{it.name}.join('", "')}"}};
|
||||
|
||||
static constexpr std::array<const char*, ${getRegisterAliasNames().size}> reg_aliases{
|
||||
{"${getRegisterAliasNames().join("\", \"")}"}};
|
||||
static constexpr std::array<const char*, ${registers.size}> reg_aliases{
|
||||
{"${registers.collect{it.alias}.join('", "')}"}};
|
||||
|
||||
enum constants {${coreDef.constants.collect{c -> c.name+"="+c.value}.join(', ')}};
|
||||
enum constants {${constants.collect{c -> c.name+"="+getCString(c.value)}.join(', ')}};
|
||||
|
||||
constexpr static unsigned FP_REGS_SIZE = ${coreDef.constants.find {it.name=='FLEN'}?.value?:0};
|
||||
constexpr static unsigned FP_REGS_SIZE = ${constants.find {it.name=='FLEN'}?.value?:0};
|
||||
|
||||
enum reg_e {<%
|
||||
allRegs.each { reg ->
|
||||
if( reg instanceof RegisterFile) {
|
||||
(reg.range.right..reg.range.left).each{%>
|
||||
${reg.name}${it},<%
|
||||
}
|
||||
} else if(reg instanceof Register){ %>
|
||||
${reg.name},<%
|
||||
}
|
||||
}%>
|
||||
NUM_REGS,
|
||||
NEXT_${pc.name}=NUM_REGS,
|
||||
TRAP_STATE,
|
||||
enum reg_e {
|
||||
${registers.collect{it.name}.join(', ')}, NUM_REGS,
|
||||
TRAP_STATE=NUM_REGS,
|
||||
PENDING_TRAP,
|
||||
MACHINE_STATE,
|
||||
LAST_BRANCH,
|
||||
ICOUNT<%
|
||||
allRegs.each { reg ->
|
||||
if(reg instanceof RegisterAlias){ def aliasname=getOriginalName(reg)%>,
|
||||
${reg.name} = ${aliasname}<%
|
||||
}
|
||||
}%>
|
||||
ICOUNT
|
||||
};
|
||||
|
||||
using reg_t = uint${regDataWidth}_t;
|
||||
using reg_t = uint${addrDataWidth}_t;
|
||||
|
||||
using addr_t = uint${addrDataWidth}_t;
|
||||
|
||||
@ -133,17 +107,22 @@ template <> struct traits<${coreDef.name.toLowerCase()}> {
|
||||
|
||||
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
|
||||
|
||||
static constexpr std::array<const uint32_t, ${regSizes.size}> reg_bit_widths{
|
||||
{${regSizes.join(",")}}};
|
||||
static constexpr std::array<const uint32_t, ${getRegisterSizes().size}> reg_bit_widths{
|
||||
{${getRegisterSizes().join(',')}}};
|
||||
|
||||
static constexpr std::array<const uint32_t, ${regOffsets.size}> reg_byte_offsets{
|
||||
{${regOffsets.join(",")}}};
|
||||
static constexpr std::array<const uint32_t, ${getRegisterOffsets().size}> reg_byte_offsets{
|
||||
{${getRegisterOffsets().join(',')}}};
|
||||
|
||||
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
|
||||
|
||||
enum sreg_flag_e { FLAGS };
|
||||
|
||||
enum mem_type_e { ${allSpaces.collect{s -> s.name}.join(', ')} };
|
||||
enum mem_type_e { ${spaces.collect{it.name}.join(', ')} };
|
||||
|
||||
enum class opcode_e : unsigned short {<%instructions.eachWithIndex{instr, index -> %>
|
||||
${instr.instruction.name} = ${index},<%}%>
|
||||
MAX_OPCODE
|
||||
};
|
||||
};
|
||||
|
||||
struct ${coreDef.name.toLowerCase()}: public arch_if {
|
||||
@ -189,32 +168,27 @@ 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 {<%
|
||||
allRegs.each { reg ->
|
||||
if( reg instanceof RegisterFile) {
|
||||
(reg.range.right..reg.range.left).each{%>
|
||||
uint${generator.getSize(reg)}_t ${reg.name}${it} = 0;<%
|
||||
}
|
||||
} else if(reg instanceof Register){ %>
|
||||
uint${generator.getSize(reg)}_t ${reg.name} = 0;<%
|
||||
}
|
||||
}%>
|
||||
uint${generator.getSize(pc)}_t NEXT_${pc.name} = 0;
|
||||
uint32_t trap_state = 0, pending_trap = 0, machine_state = 0, last_branch = 0;
|
||||
registers.each { reg -> if(reg.size>0) {%>
|
||||
uint${byteSize(reg.size)}_t ${reg.name} = 0;<%
|
||||
}}%>
|
||||
uint32_t trap_state = 0, pending_trap = 0;
|
||||
uint64_t icount = 0;
|
||||
uint32_t last_branch;
|
||||
} reg;
|
||||
|
||||
#pragma pack(pop)
|
||||
std::array<address_type, 4> addr_mode;
|
||||
|
||||
uint64_t interrupt_sim=0;
|
||||
<%
|
||||
def fcsr = allRegs.find {it.name=='FCSR'}
|
||||
def fcsr = registers.find {it.name=='FCSR'}
|
||||
if(fcsr != null) {%>
|
||||
uint${generator.getSize(fcsr)}_t get_fcsr(){return reg.FCSR;}
|
||||
void set_fcsr(uint${generator.getSize(fcsr)}_t val){reg.FCSR = val;}
|
||||
uint${fcsr.size}_t get_fcsr(){return reg.FCSR;}
|
||||
void set_fcsr(uint${fcsr.size}_t val){reg.FCSR = val;}
|
||||
<%} else { %>
|
||||
uint32_t get_fcsr(){return 0;}
|
||||
void set_fcsr(uint32_t val){}
|
||||
uint32_t get_fcsr(){return 0;}
|
||||
void set_fcsr(uint32_t val){}
|
||||
<%}%>
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2020 MINRES Technologies GmbH
|
||||
* Copyright (C) 2021 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -56,13 +56,14 @@ using namespace iss::debugger;
|
||||
|
||||
template <typename ARCH> class vm_impl : public iss::interp::vm_base<ARCH> {
|
||||
public:
|
||||
using super = typename iss::interp::vm_base<ARCH>;
|
||||
using traits = arch::traits<ARCH>;
|
||||
using super = typename iss::interp::vm_base<ARCH>;
|
||||
using virt_addr_t = typename super::virt_addr_t;
|
||||
using phys_addr_t = typename super::phys_addr_t;
|
||||
using code_word_t = typename super::code_word_t;
|
||||
using addr_t = typename super::addr_t;
|
||||
using reg_t = typename traits<ARCH>::reg_t;
|
||||
using iss::interp::vm_base<ARCH>::get_reg;
|
||||
using addr_t = typename super::addr_t;
|
||||
using reg_t = typename traits::reg_t;
|
||||
using mem_type_e = typename traits::mem_type_e;
|
||||
|
||||
vm_impl();
|
||||
|
||||
@ -82,9 +83,9 @@ protected:
|
||||
using compile_ret_t = virt_addr_t;
|
||||
using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr);
|
||||
|
||||
inline const char *name(size_t index){return traits<ARCH>::reg_aliases.at(index);}
|
||||
inline const char *name(size_t index){return traits::reg_aliases.at(index);}
|
||||
|
||||
virt_addr_t execute_inst(virt_addr_t start, std::function<bool(void)> pred) override;
|
||||
virt_addr_t execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit) override;
|
||||
|
||||
// some compile time constants
|
||||
// enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 };
|
||||
@ -138,23 +139,64 @@ protected:
|
||||
return lut_val;
|
||||
}
|
||||
|
||||
void raise_trap(uint16_t trap_id, uint16_t cause){
|
||||
inline void raise(uint16_t trap_id, uint16_t cause){
|
||||
auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id;
|
||||
this->template get_reg<uint32_t>(arch::traits<ARCH>::TRAP_STATE) = trap_val;
|
||||
this->template get_reg<uint32_t>(arch::traits<ARCH>::NEXT_PC) = std::numeric_limits<uint32_t>::max();
|
||||
this->template get_reg<uint32_t>(traits::TRAP_STATE) = trap_val;
|
||||
this->template get_reg<uint32_t>(traits::NEXT_PC) = std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
|
||||
void leave_trap(unsigned lvl){
|
||||
inline void leave(unsigned lvl){
|
||||
this->core.leave_trap(lvl);
|
||||
auto pc_val = super::template read_mem<reg_t>(traits<ARCH>::CSR, (lvl << 8) + 0x41);
|
||||
this->template get_reg<reg_t>(arch::traits<ARCH>::NEXT_PC) = pc_val;
|
||||
this->template get_reg<uint32_t>(arch::traits<ARCH>::LAST_BRANCH) = std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
|
||||
void wait(unsigned type){
|
||||
inline void wait(unsigned type){
|
||||
this->core.wait_until(type);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& pc_assign(T& val){super::ex_info.branch_taken=true; return val;}
|
||||
inline uint8_t readSpace1(typename super::mem_type_e space, uint64_t addr){
|
||||
auto ret = super::template read_mem<uint8_t>(space, addr);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
return ret;
|
||||
}
|
||||
inline uint16_t readSpace2(typename super::mem_type_e space, uint64_t addr){
|
||||
auto ret = super::template read_mem<uint16_t>(space, addr);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
return ret;
|
||||
}
|
||||
inline uint32_t readSpace4(typename super::mem_type_e space, uint64_t addr){
|
||||
auto ret = super::template read_mem<uint32_t>(space, addr);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
return ret;
|
||||
}
|
||||
inline uint64_t readSpace8(typename super::mem_type_e space, uint64_t addr){
|
||||
auto ret = super::template read_mem<uint64_t>(space, addr);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
return ret;
|
||||
}
|
||||
inline void writeSpace1(typename super::mem_type_e space, uint64_t addr, uint8_t data){
|
||||
super::write_mem(space, addr, data);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
}
|
||||
inline void writeSpace2(typename super::mem_type_e space, uint64_t addr, uint16_t data){
|
||||
super::write_mem(space, addr, data);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
}
|
||||
inline void writeSpace4(typename super::mem_type_e space, uint64_t addr, uint32_t data){
|
||||
super::write_mem(space, addr, data);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
}
|
||||
inline void writeSpace8(typename super::mem_type_e space, uint64_t addr, uint64_t data){
|
||||
super::write_mem(space, addr, data);
|
||||
if(this->template get_reg<uint32_t>(traits::TRAP_STATE)) throw 0;
|
||||
}
|
||||
template<unsigned W, typename U, typename S = typename std::make_signed<U>::type>
|
||||
inline S sext(U from) {
|
||||
auto mask = (1ULL<<W) - 1;
|
||||
auto sign_mask = 1ULL<<(W-1);
|
||||
return (from & mask) | ((from & sign_mask) ? ~mask : 0);
|
||||
}
|
||||
|
||||
private:
|
||||
/****************************************************************************
|
||||
@ -170,22 +212,76 @@ private:
|
||||
const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
|
||||
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
|
||||
/* instruction ${instr.instruction.name} */
|
||||
{${instr.length}, ${instr.value}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
|
||||
{${instr.length}, ${instr.encoding}, ${instr.mask}, &this_class::__${generator.functionName(instr.name)}},<%}%>
|
||||
}};
|
||||
|
||||
/* instruction definitions */<%instructions.eachWithIndex{instr, idx -> %>
|
||||
/* instruction ${idx}: ${instr.name} */
|
||||
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr){<%instr.code.eachLine{%>
|
||||
${it}<%}%>
|
||||
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr){
|
||||
// pre execution stuff
|
||||
this->do_sync(PRE_SYNC, ${idx});
|
||||
<%instr.fields.eachLine{%>${it}
|
||||
<%}%>if(this->disass_enabled){
|
||||
/* generate console output when executing the command */
|
||||
<%instr.disass.eachLine{%>${it}
|
||||
<%}%>
|
||||
}
|
||||
// prepare execution
|
||||
uint${addrDataWidth}_t* PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
|
||||
uint${addrDataWidth}_t* NEXT_PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
|
||||
// used registers<%instr.usedVariables.each{ k,v->
|
||||
if(v.isArray) {%>
|
||||
uint${v.type.size}_t* ${k} = reinterpret_cast<uint${v.type.size}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}0]);<% }else{ %>
|
||||
uint${v.type.size}_t* ${k} = reinterpret_cast<uint${v.type.size}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::${k}]);
|
||||
<%}}%>// calculate next pc value
|
||||
*NEXT_PC = *PC + ${instr.length/8};
|
||||
// execute instruction
|
||||
try {
|
||||
<%instr.behavior.eachLine{%>${it}
|
||||
<%}%>} catch(...){}
|
||||
// post execution stuff
|
||||
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, ${idx});
|
||||
auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]);
|
||||
// trap check
|
||||
if(*trap_state!=0){
|
||||
super::core.enter_trap(*trap_state, pc.val);
|
||||
}
|
||||
pc.val=*NEXT_PC;
|
||||
return pc;
|
||||
}
|
||||
<%}%>
|
||||
/****************************************************************************
|
||||
* end opcode definitions
|
||||
****************************************************************************/
|
||||
compile_ret_t illegal_intruction(virt_addr_t &pc, code_word_t instr) {
|
||||
pc = pc + ((instr & 3) == 3 ? 4 : 2);
|
||||
this->do_sync(PRE_SYNC, static_cast<unsigned>(arch::traits<ARCH>::opcode_e::MAX_OPCODE));
|
||||
uint32_t* PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
|
||||
uint32_t* NEXT_PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
|
||||
*NEXT_PC = *PC + ((instr & 3) == 3 ? 4 : 2);
|
||||
raise(0, 2);
|
||||
// post execution stuff
|
||||
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, static_cast<unsigned>(arch::traits<ARCH>::opcode_e::MAX_OPCODE));
|
||||
auto* trap_state = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::TRAP_STATE]);
|
||||
// trap check
|
||||
if(*trap_state!=0){
|
||||
super::core.enter_trap(*trap_state, pc.val);
|
||||
}
|
||||
pc.val=*NEXT_PC;
|
||||
return pc;
|
||||
}
|
||||
|
||||
static constexpr typename traits::addr_t upper_bits = ~traits::PGMASK;
|
||||
iss::status fetch_ins(virt_addr_t pc, uint8_t * data){
|
||||
auto phys_pc = this->core.v2p(pc);
|
||||
//if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
|
||||
// if (this->core.read(phys_pc, 2, data) != iss::Ok) return iss::Err;
|
||||
// if ((data[0] & 0x3) == 0x3) // this is a 32bit instruction
|
||||
// if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok) return iss::Err;
|
||||
//} else {
|
||||
if (this->core.read(phys_pc, 4, data) != iss::Ok) return iss::Err;
|
||||
//}
|
||||
return iss::Ok;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename CODE_WORD> void debug_fn(CODE_WORD insn) {
|
||||
@ -208,24 +304,26 @@ vm_impl<ARCH>::vm_impl(ARCH &core, unsigned core_id, unsigned cluster_id)
|
||||
}
|
||||
}
|
||||
|
||||
inline bool is_count_limit_enabled(finish_cond_e cond){
|
||||
return (cond & finish_cond_e::COUNT_LIMIT) == finish_cond_e::COUNT_LIMIT;
|
||||
}
|
||||
template <typename ARCH>
|
||||
typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(virt_addr_t start, std::function<bool(void)> pred) {
|
||||
typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e cond, virt_addr_t start, uint64_t icount_limit){
|
||||
// we fetch at max 4 byte, alignment is 2
|
||||
enum {TRAP_ID=1<<16};
|
||||
const typename traits<ARCH>::addr_t upper_bits = ~traits<ARCH>::PGMASK;
|
||||
code_word_t insn = 0;
|
||||
auto *const data = (uint8_t *)&insn;
|
||||
auto pc=start;
|
||||
while(pred){
|
||||
auto paddr = this->core.v2p(pc);
|
||||
if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
|
||||
if (this->core.read(paddr, 2, data) != iss::Ok) throw trap_access(TRAP_ID, pc.val);
|
||||
if ((insn & 0x3) == 0x3) // this is a 32bit instruction
|
||||
if (this->core.read(this->core.v2p(pc + 2), 2, data + 2) != iss::Ok) throw trap_access(TRAP_ID, pc.val);
|
||||
} else {
|
||||
if (this->core.read(paddr, 4, data) != iss::Ok) throw trap_access(TRAP_ID, pc.val);
|
||||
while(!this->core.should_stop() &&
|
||||
!(is_count_limit_enabled(cond) && this->core.get_icount() >= icount_limit)){
|
||||
auto res = fetch_ins(pc, data);
|
||||
if(res!=iss::Ok){
|
||||
auto new_pc = super::core.enter_trap(TRAP_ID, pc.val);
|
||||
res = fetch_ins(virt_addr_t{access_type::FETCH, new_pc}, data);
|
||||
if(res!=iss::Ok) throw simulation_stopped(0);
|
||||
}
|
||||
if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
|
||||
if ((cond & finish_cond_e::JUMP_TO_SELF) == finish_cond_e::JUMP_TO_SELF &&
|
||||
(insn == 0x0000006f || (insn&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
|
||||
auto lut_val = extract_fields(insn);
|
||||
auto f = qlut[insn & 0x3][lut_val];
|
||||
if (!f)
|
1
incl/iss/arch/.gitignore
vendored
Normal file
1
incl/iss/arch/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/tgc_*.h
|
235
incl/iss/arch/riscv_hart_common.h
Normal file
235
incl/iss/arch/riscv_hart_common.h
Normal file
@ -0,0 +1,235 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, 2018, 2021 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Contributors:
|
||||
* eyck@minres.com - initial implementation
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _RISCV_HART_COMMON
|
||||
#define _RISCV_HART_COMMON
|
||||
|
||||
#include "iss/arch_if.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace iss {
|
||||
namespace arch {
|
||||
|
||||
enum { tohost_dflt = 0xF0001000, fromhost_dflt = 0xF0001040 };
|
||||
|
||||
enum riscv_csr {
|
||||
/* user-level CSR */
|
||||
// User Trap Setup
|
||||
ustatus = 0x000,
|
||||
uie = 0x004,
|
||||
utvec = 0x005,
|
||||
// User Trap Handling
|
||||
uscratch = 0x040,
|
||||
uepc = 0x041,
|
||||
ucause = 0x042,
|
||||
utval = 0x043,
|
||||
uip = 0x044,
|
||||
// User Floating-Point CSRs
|
||||
fflags = 0x001,
|
||||
frm = 0x002,
|
||||
fcsr = 0x003,
|
||||
// User Counter/Timers
|
||||
cycle = 0xC00,
|
||||
time = 0xC01,
|
||||
instret = 0xC02,
|
||||
hpmcounter3 = 0xC03,
|
||||
hpmcounter4 = 0xC04,
|
||||
/*...*/
|
||||
hpmcounter31 = 0xC1F,
|
||||
cycleh = 0xC80,
|
||||
timeh = 0xC81,
|
||||
instreth = 0xC82,
|
||||
hpmcounter3h = 0xC83,
|
||||
hpmcounter4h = 0xC84,
|
||||
/*...*/
|
||||
hpmcounter31h = 0xC9F,
|
||||
/* supervisor-level CSR */
|
||||
// Supervisor Trap Setup
|
||||
sstatus = 0x100,
|
||||
sedeleg = 0x102,
|
||||
sideleg = 0x103,
|
||||
sie = 0x104,
|
||||
stvec = 0x105,
|
||||
scounteren = 0x106,
|
||||
// Supervisor Trap Handling
|
||||
sscratch = 0x140,
|
||||
sepc = 0x141,
|
||||
scause = 0x142,
|
||||
stval = 0x143,
|
||||
sip = 0x144,
|
||||
// Supervisor Protection and Translation
|
||||
satp = 0x180,
|
||||
/* machine-level CSR */
|
||||
// Machine Information Registers
|
||||
mvendorid = 0xF11,
|
||||
marchid = 0xF12,
|
||||
mimpid = 0xF13,
|
||||
mhartid = 0xF14,
|
||||
// Machine Trap Setup
|
||||
mstatus = 0x300,
|
||||
misa = 0x301,
|
||||
medeleg = 0x302,
|
||||
mideleg = 0x303,
|
||||
mie = 0x304,
|
||||
mtvec = 0x305,
|
||||
mcounteren = 0x306,
|
||||
// Machine Trap Handling
|
||||
mscratch = 0x340,
|
||||
mepc = 0x341,
|
||||
mcause = 0x342,
|
||||
mtval = 0x343,
|
||||
mip = 0x344,
|
||||
// Physical Memory Protection
|
||||
pmpcfg0 = 0x3A0,
|
||||
pmpcfg1 = 0x3A1,
|
||||
pmpcfg2 = 0x3A2,
|
||||
pmpcfg3 = 0x3A3,
|
||||
pmpaddr0 = 0x3B0,
|
||||
pmpaddr1 = 0x3B1,
|
||||
pmpaddr2 = 0x3B2,
|
||||
pmpaddr3 = 0x3B3,
|
||||
pmpaddr4 = 0x3B4,
|
||||
pmpaddr5 = 0x3B5,
|
||||
pmpaddr6 = 0x3B6,
|
||||
pmpaddr7 = 0x3B7,
|
||||
pmpaddr8 = 0x3B8,
|
||||
pmpaddr9 = 0x3B9,
|
||||
pmpaddr10 = 0x3BA,
|
||||
pmpaddr11 = 0x3BB,
|
||||
pmpaddr12 = 0x3BC,
|
||||
pmpaddr13 = 0x3BD,
|
||||
pmpaddr14 = 0x3BE,
|
||||
pmpaddr15 = 0x3BF,
|
||||
// Machine Counter/Timers
|
||||
mcycle = 0xB00,
|
||||
minstret = 0xB02,
|
||||
mhpmcounter3 = 0xB03,
|
||||
mhpmcounter4 = 0xB04,
|
||||
/*...*/
|
||||
mhpmcounter31 = 0xB1F,
|
||||
mcycleh = 0xB80,
|
||||
minstreth = 0xB82,
|
||||
mhpmcounter3h = 0xB83,
|
||||
mhpmcounter4h = 0xB84,
|
||||
/*...*/
|
||||
mhpmcounter31h = 0xB9F,
|
||||
// Machine Counter Setup
|
||||
mhpmevent3 = 0x323,
|
||||
mhpmevent4 = 0x324,
|
||||
/*...*/
|
||||
mhpmevent31 = 0x33F,
|
||||
// Debug/Trace Registers (shared with Debug Mode)
|
||||
tselect = 0x7A0,
|
||||
tdata1 = 0x7A1,
|
||||
tdata2 = 0x7A2,
|
||||
tdata3 = 0x7A3,
|
||||
// Debug Mode Registers
|
||||
dcsr = 0x7B0,
|
||||
dpc = 0x7B1,
|
||||
dscratch = 0x7B2
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
PGSHIFT = 12,
|
||||
PTE_PPN_SHIFT = 10,
|
||||
// page table entry (PTE) fields
|
||||
PTE_V = 0x001, // Valid
|
||||
PTE_R = 0x002, // Read
|
||||
PTE_W = 0x004, // Write
|
||||
PTE_X = 0x008, // Execute
|
||||
PTE_U = 0x010, // User
|
||||
PTE_G = 0x020, // Global
|
||||
PTE_A = 0x040, // Accessed
|
||||
PTE_D = 0x080, // Dirty
|
||||
PTE_SOFT = 0x300 // Reserved for Software
|
||||
};
|
||||
|
||||
template <typename T> inline bool PTE_TABLE(T PTE) { return (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V); }
|
||||
|
||||
enum { PRIV_U = 0, PRIV_S = 1, PRIV_M = 3 };
|
||||
|
||||
enum {
|
||||
ISA_A = 1,
|
||||
ISA_B = 1 << 1,
|
||||
ISA_C = 1 << 2,
|
||||
ISA_D = 1 << 3,
|
||||
ISA_E = 1 << 4,
|
||||
ISA_F = 1 << 5,
|
||||
ISA_G = 1 << 6,
|
||||
ISA_I = 1 << 8,
|
||||
ISA_M = 1 << 12,
|
||||
ISA_N = 1 << 13,
|
||||
ISA_Q = 1 << 16,
|
||||
ISA_S = 1 << 18,
|
||||
ISA_U = 1 << 20
|
||||
};
|
||||
|
||||
struct vm_info {
|
||||
int levels;
|
||||
int idxbits;
|
||||
int ptesize;
|
||||
uint64_t ptbase;
|
||||
bool is_active() { return levels; }
|
||||
};
|
||||
|
||||
class trap_load_access_fault : public trap_access {
|
||||
public:
|
||||
trap_load_access_fault(uint64_t badaddr)
|
||||
: trap_access(5 << 16, badaddr) {}
|
||||
};
|
||||
class illegal_instruction_fault : public trap_access {
|
||||
public:
|
||||
illegal_instruction_fault(uint64_t badaddr)
|
||||
: trap_access(2 << 16, badaddr) {}
|
||||
};
|
||||
class trap_instruction_page_fault : public trap_access {
|
||||
public:
|
||||
trap_instruction_page_fault(uint64_t badaddr)
|
||||
: trap_access(12 << 16, badaddr) {}
|
||||
};
|
||||
class trap_load_page_fault : public trap_access {
|
||||
public:
|
||||
trap_load_page_fault(uint64_t badaddr)
|
||||
: trap_access(13 << 16, badaddr) {}
|
||||
};
|
||||
class trap_store_page_fault : public trap_access {
|
||||
public:
|
||||
trap_store_page_fault(uint64_t badaddr)
|
||||
: trap_access(15 << 16, badaddr) {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, 2018, MINRES Technologies GmbH
|
||||
* Copyright (C) 2021, MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -32,11 +32,11 @@
|
||||
* eyck@minres.com - initial implementation
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _RISCV_CORE_H_
|
||||
#define _RISCV_CORE_H_
|
||||
#ifndef _RISCV_HART_M_P_H
|
||||
#define _RISCV_HART_M_P_H
|
||||
|
||||
#include "riscv_hart_common.h"
|
||||
#include "iss/arch/traits.h"
|
||||
#include "iss/arch_if.h"
|
||||
#include "iss/instrumentation_if.h"
|
||||
#include "iss/log_categories.h"
|
||||
#include "iss/vm_if.h"
|
||||
@ -50,6 +50,7 @@
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include <util/bit_field.h>
|
||||
#include <util/ities.h>
|
||||
#include <util/sparse_array.h>
|
||||
@ -65,185 +66,30 @@
|
||||
namespace iss {
|
||||
namespace arch {
|
||||
|
||||
enum { tohost_dflt = 0xF0001000, fromhost_dflt = 0xF0001040 };
|
||||
|
||||
enum riscv_csr {
|
||||
/* user-level CSR */
|
||||
// User Trap Setup
|
||||
ustatus = 0x000,
|
||||
uie = 0x004,
|
||||
utvec = 0x005,
|
||||
// User Trap Handling
|
||||
uscratch = 0x040,
|
||||
uepc = 0x041,
|
||||
ucause = 0x042,
|
||||
utval = 0x043,
|
||||
uip = 0x044,
|
||||
// User Floating-Point CSRs
|
||||
fflags = 0x001,
|
||||
frm = 0x002,
|
||||
fcsr = 0x003,
|
||||
// User Counter/Timers
|
||||
cycle = 0xC00,
|
||||
time = 0xC01,
|
||||
instret = 0xC02,
|
||||
hpmcounter3 = 0xC03,
|
||||
hpmcounter4 = 0xC04,
|
||||
/*...*/
|
||||
hpmcounter31 = 0xC1F,
|
||||
cycleh = 0xC80,
|
||||
timeh = 0xC81,
|
||||
instreth = 0xC82,
|
||||
hpmcounter3h = 0xC83,
|
||||
hpmcounter4h = 0xC84,
|
||||
/*...*/
|
||||
hpmcounter31h = 0xC9F,
|
||||
/* supervisor-level CSR */
|
||||
// Supervisor Trap Setup
|
||||
sstatus = 0x100,
|
||||
sedeleg = 0x102,
|
||||
sideleg = 0x103,
|
||||
sie = 0x104,
|
||||
stvec = 0x105,
|
||||
scounteren = 0x106,
|
||||
// Supervisor Trap Handling
|
||||
sscratch = 0x140,
|
||||
sepc = 0x141,
|
||||
scause = 0x142,
|
||||
stval = 0x143,
|
||||
sip = 0x144,
|
||||
// Supervisor Protection and Translation
|
||||
satp = 0x180,
|
||||
/* machine-level CSR */
|
||||
// Machine Information Registers
|
||||
mvendorid = 0xF11,
|
||||
marchid = 0xF12,
|
||||
mimpid = 0xF13,
|
||||
mhartid = 0xF14,
|
||||
// Machine Trap Setup
|
||||
mstatus = 0x300,
|
||||
misa = 0x301,
|
||||
medeleg = 0x302,
|
||||
mideleg = 0x303,
|
||||
mie = 0x304,
|
||||
mtvec = 0x305,
|
||||
mcounteren = 0x306,
|
||||
// Machine Trap Handling
|
||||
mscratch = 0x340,
|
||||
mepc = 0x341,
|
||||
mcause = 0x342,
|
||||
mtval = 0x343,
|
||||
mip = 0x344,
|
||||
// Machine Protection and Translation
|
||||
pmpcfg0 = 0x3A0,
|
||||
pmpcfg1 = 0x3A1,
|
||||
pmpcfg2 = 0x3A2,
|
||||
pmpcfg3 = 0x3A3,
|
||||
pmpaddr0 = 0x3B0,
|
||||
pmpaddr1 = 0x3B1,
|
||||
/*...*/
|
||||
pmpaddr15 = 0x3BF,
|
||||
// Machine Counter/Timers
|
||||
mcycle = 0xB00,
|
||||
minstret = 0xB02,
|
||||
mhpmcounter3 = 0xB03,
|
||||
mhpmcounter4 = 0xB04,
|
||||
/*...*/
|
||||
mhpmcounter31 = 0xB1F,
|
||||
mcycleh = 0xB80,
|
||||
minstreth = 0xB82,
|
||||
mhpmcounter3h = 0xB83,
|
||||
mhpmcounter4h = 0xB84,
|
||||
/*...*/
|
||||
mhpmcounter31h = 0xB9F,
|
||||
// Machine Counter Setup
|
||||
mhpmevent3 = 0x323,
|
||||
mhpmevent4 = 0x324,
|
||||
/*...*/
|
||||
mhpmevent31 = 0x33F,
|
||||
// Debug/Trace Registers (shared with Debug Mode)
|
||||
tselect = 0x7A0,
|
||||
tdata1 = 0x7A1,
|
||||
tdata2 = 0x7A2,
|
||||
tdata3 = 0x7A3,
|
||||
// Debug Mode Registers
|
||||
dcsr = 0x7B0,
|
||||
dpc = 0x7B1,
|
||||
dscratch = 0x7B2
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
std::array<const char *, 16> trap_str = {{""
|
||||
"Instruction address misaligned", // 0
|
||||
"Instruction access fault", // 1
|
||||
"Illegal instruction", // 2
|
||||
"Breakpoint", // 3
|
||||
"Load address misaligned", // 4
|
||||
"Load access fault", // 5
|
||||
"Store/AMO address misaligned", // 6
|
||||
"Store/AMO access fault", // 7
|
||||
"Environment call from U-mode", // 8
|
||||
"Environment call from S-mode", // 9
|
||||
"Reserved", // a
|
||||
"Environment call from M-mode", // b
|
||||
"Instruction page fault", // c
|
||||
"Load page fault", // d
|
||||
"Reserved", // e
|
||||
"Store/AMO page fault"}};
|
||||
std::array<const char *, 12> irq_str = {
|
||||
{"User software interrupt", "Supervisor software interrupt", "Reserved", "Machine software interrupt",
|
||||
"User timer interrupt", "Supervisor timer interrupt", "Reserved", "Machine timer interrupt",
|
||||
"User external interrupt", "Supervisor external interrupt", "Reserved", "Machine external interrupt"}};
|
||||
|
||||
enum {
|
||||
PGSHIFT = 12,
|
||||
PTE_PPN_SHIFT = 10,
|
||||
// page table entry (PTE) fields
|
||||
PTE_V = 0x001, // Valid
|
||||
PTE_R = 0x002, // Read
|
||||
PTE_W = 0x004, // Write
|
||||
PTE_X = 0x008, // Execute
|
||||
PTE_U = 0x010, // User
|
||||
PTE_G = 0x020, // Global
|
||||
PTE_A = 0x040, // Accessed
|
||||
PTE_D = 0x080, // Dirty
|
||||
PTE_SOFT = 0x300 // Reserved for Software
|
||||
};
|
||||
|
||||
template <typename T> inline bool PTE_TABLE(T PTE) { return (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V); }
|
||||
|
||||
enum { PRIV_U = 0, PRIV_S = 1, PRIV_M = 3 };
|
||||
|
||||
enum {
|
||||
ISA_A = 1,
|
||||
ISA_B = 1 << 1,
|
||||
ISA_C = 1 << 2,
|
||||
ISA_D = 1 << 3,
|
||||
ISA_E = 1 << 4,
|
||||
ISA_F = 1 << 5,
|
||||
ISA_G = 1 << 6,
|
||||
ISA_I = 1 << 8,
|
||||
ISA_M = 1 << 12,
|
||||
ISA_N = 1 << 13,
|
||||
ISA_Q = 1 << 16,
|
||||
ISA_S = 1 << 18,
|
||||
ISA_U = 1 << 20
|
||||
};
|
||||
|
||||
class trap_load_access_fault : public trap_access {
|
||||
public:
|
||||
trap_load_access_fault(uint64_t badaddr)
|
||||
: trap_access(5 << 16, badaddr) {}
|
||||
};
|
||||
class illegal_instruction_fault : public trap_access {
|
||||
public:
|
||||
illegal_instruction_fault(uint64_t badaddr)
|
||||
: trap_access(2 << 16, badaddr) {}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
template <typename BASE> 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 = {{""
|
||||
"Instruction address misaligned", // 0
|
||||
"Instruction access fault", // 1
|
||||
"Illegal instruction", // 2
|
||||
"Breakpoint", // 3
|
||||
"Load address misaligned", // 4
|
||||
"Load access fault", // 5
|
||||
"Store/AMO address misaligned", // 6
|
||||
"Store/AMO access fault", // 7
|
||||
"Environment call from U-mode", // 8
|
||||
"Environment call from S-mode", // 9
|
||||
"Reserved", // a
|
||||
"Environment call from M-mode", // b
|
||||
"Instruction page fault", // c
|
||||
"Load page fault", // d
|
||||
"Reserved", // e
|
||||
"Store/AMO page fault"}};
|
||||
const std::array<const char *, 12> irq_str = {
|
||||
{"User software interrupt", "Supervisor software interrupt", "Reserved", "Machine software interrupt",
|
||||
"User timer interrupt", "Supervisor timer interrupt", "Reserved", "Machine timer interrupt",
|
||||
"User external interrupt", "Supervisor external interrupt", "Reserved", "Machine external interrupt"}};
|
||||
public:
|
||||
using super = BASE;
|
||||
using this_class = riscv_hart_m_p<BASE>;
|
||||
@ -308,12 +154,11 @@ public:
|
||||
|
||||
T satp;
|
||||
|
||||
static constexpr T get_misa() { return (1UL << 30) | ISA_I | ISA_M | ISA_A | ISA_U | ISA_S | ISA_M; }
|
||||
|
||||
static constexpr uint32_t get_mask() {
|
||||
return 0x807ff9ddUL; // 0b1000 0000 0111 1111 1111 1001 1011 1011 // only machine mode is supported
|
||||
}
|
||||
};
|
||||
using hart_state_type = hart_state<reg_t>;
|
||||
|
||||
constexpr reg_t get_irq_mask() {
|
||||
return 0b101110111011; // only machine mode is supported
|
||||
@ -344,7 +189,19 @@ public:
|
||||
};
|
||||
|
||||
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
|
||||
|
||||
|
||||
void setMemReadCb(std::function<iss::status(phys_addr_t, unsigned, uint8_t* const)> const& memReadCb) {
|
||||
mem_read_cb = memReadCb;
|
||||
}
|
||||
|
||||
void setMemWriteCb(std::function<iss::status(phys_addr_t, unsigned, const uint8_t* const)> const& memWriteCb) {
|
||||
mem_write_cb = memWriteCb;
|
||||
}
|
||||
|
||||
void set_csr(unsigned addr, reg_t val){
|
||||
csr[addr & csr.page_addr_mask] = val;
|
||||
}
|
||||
|
||||
protected:
|
||||
struct riscv_instrumentation_if : public iss::instrumentation_if {
|
||||
|
||||
@ -376,7 +233,7 @@ protected:
|
||||
virtual iss::status read_csr(unsigned addr, reg_t &val);
|
||||
virtual iss::status write_csr(unsigned addr, reg_t val);
|
||||
|
||||
hart_state<reg_t> state;
|
||||
hart_state_type state;
|
||||
uint64_t cycle_offset;
|
||||
reg_t fault_data;
|
||||
uint64_t tohost = tohost_dflt;
|
||||
@ -396,6 +253,8 @@ protected:
|
||||
std::unordered_map<unsigned, wr_csr_f> csr_wr_cb;
|
||||
|
||||
private:
|
||||
iss::status read_reg(unsigned addr, reg_t &val);
|
||||
iss::status write_reg(unsigned addr, reg_t val);
|
||||
iss::status read_cycle(unsigned addr, reg_t &val);
|
||||
iss::status read_time(unsigned addr, reg_t &val);
|
||||
iss::status read_status(unsigned addr, reg_t &val);
|
||||
@ -406,7 +265,9 @@ private:
|
||||
iss::status write_ip(unsigned addr, reg_t val);
|
||||
iss::status read_hartid(unsigned addr, reg_t &val);
|
||||
|
||||
reg_t mhartid_reg{0xF};
|
||||
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();
|
||||
@ -417,10 +278,8 @@ riscv_hart_m_p<BASE>::riscv_hart_m_p()
|
||||
: state()
|
||||
, cycle_offset(0)
|
||||
, instr_if(*this) {
|
||||
csr[misa] = hart_state<reg_t>::get_misa();
|
||||
csr[misa] = traits<BASE>::MISA_VAL;
|
||||
uart_buf.str("");
|
||||
// read-only registers
|
||||
csr_wr_cb[misa] = nullptr;
|
||||
for (unsigned addr = mcycle; addr <= hpmcounter31; ++addr) csr_wr_cb[addr] = nullptr;
|
||||
for (unsigned addr = mcycleh; addr <= hpmcounter31h; ++addr) csr_wr_cb[addr] = nullptr;
|
||||
// special handling
|
||||
@ -439,6 +298,15 @@ riscv_hart_m_p<BASE>::riscv_hart_m_p()
|
||||
csr_rd_cb[mie] = &riscv_hart_m_p<BASE>::read_ie;
|
||||
csr_wr_cb[mie] = &riscv_hart_m_p<BASE>::write_ie;
|
||||
csr_rd_cb[mhartid] = &riscv_hart_m_p<BASE>::read_hartid;
|
||||
// common regs
|
||||
const std::array<unsigned, 6> addrs{{mepc, mtvec, mscratch, mcause, mtval, mscratch}};
|
||||
for(auto addr: addrs) {
|
||||
csr_rd_cb[addr] = &riscv_hart_m_p<BASE>::read_reg;
|
||||
csr_wr_cb[addr] = &riscv_hart_m_p<BASE>::write_reg;
|
||||
}
|
||||
// read-only registers
|
||||
csr_rd_cb[misa] = &riscv_hart_m_p<BASE>::read_reg;
|
||||
csr_wr_cb[misa] = nullptr;
|
||||
}
|
||||
|
||||
template <typename BASE> std::pair<uint64_t, bool> riscv_hart_m_p<BASE>::load_file(std::string name, int type) {
|
||||
@ -653,32 +521,35 @@ 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) {
|
||||
if (addr >= csr.size()) return iss::Err;
|
||||
auto req_priv_lvl = (addr >> 8) & 0x3;
|
||||
if (this->reg.machine_state < req_priv_lvl) throw illegal_instruction_fault(this->fault_data);
|
||||
if (this->reg.PRIV < req_priv_lvl) // not having required privileges
|
||||
throw illegal_instruction_fault(this->fault_data);
|
||||
auto it = csr_rd_cb.find(addr);
|
||||
if (it == csr_rd_cb.end()) {
|
||||
val = csr[addr & csr.page_addr_mask];
|
||||
return iss::Ok;
|
||||
}
|
||||
rd_csr_f f = it->second;
|
||||
if (f == nullptr) throw illegal_instruction_fault(this->fault_data);
|
||||
return (this->*f)(addr, val);
|
||||
if (it == csr_rd_cb.end() || !it->second) // non existent register
|
||||
throw illegal_instruction_fault(this->fault_data);
|
||||
return (this->*(it->second))(addr, val);
|
||||
}
|
||||
|
||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_csr(unsigned addr, reg_t val) {
|
||||
if (addr >= csr.size()) return iss::Err;
|
||||
auto req_priv_lvl = (addr >> 8) & 0x3;
|
||||
if (this->reg.machine_state < req_priv_lvl)
|
||||
if (this->reg.PRIV < req_priv_lvl) // not having required privileges
|
||||
throw illegal_instruction_fault(this->fault_data);
|
||||
if((addr&0xc00)==0xc00)
|
||||
if((addr&0xc00)==0xc00) // writing to read-only region
|
||||
throw illegal_instruction_fault(this->fault_data);
|
||||
auto it = csr_wr_cb.find(addr);
|
||||
if (it == csr_wr_cb.end()) {
|
||||
csr[addr & csr.page_addr_mask] = val;
|
||||
return iss::Ok;
|
||||
}
|
||||
wr_csr_f f = it->second;
|
||||
if (f == nullptr) throw illegal_instruction_fault(this->fault_data);
|
||||
return (this->*f)(addr, val);
|
||||
if (it == csr_wr_cb.end() || !it->second) // non existent register
|
||||
throw illegal_instruction_fault(this->fault_data);
|
||||
return (this->*(it->second))(addr, val);
|
||||
}
|
||||
|
||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_reg(unsigned addr, reg_t &val) {
|
||||
val = csr[addr];
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_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) {
|
||||
@ -704,7 +575,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_time(unsigned ad
|
||||
}
|
||||
|
||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_status(unsigned addr, reg_t &val) {
|
||||
val = state.mstatus & hart_state<reg_t>::get_mask();
|
||||
val = state.mstatus & hart_state_type::get_mask();
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
@ -749,6 +620,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_ip(unsigned add
|
||||
template <typename BASE>
|
||||
iss::status riscv_hart_m_p<BASE>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
|
||||
if ((paddr.val + length) > mem.size()) return iss::Err;
|
||||
if(mem_read_cb) return mem_read_cb(paddr, length, data);
|
||||
switch (paddr.val) {
|
||||
case 0x0200BFF8: { // CLINT base, mtime reg
|
||||
if (sizeof(reg_t) < length) return iss::Err;
|
||||
@ -774,6 +646,7 @@ iss::status riscv_hart_m_p<BASE>::read_mem(phys_addr_t paddr, unsigned length, u
|
||||
template <typename BASE>
|
||||
iss::status riscv_hart_m_p<BASE>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) {
|
||||
if ((paddr.val + length) > mem.size()) return iss::Err;
|
||||
if(mem_write_cb) return mem_write_cb(paddr, length, data);
|
||||
switch (paddr.val) {
|
||||
case 0x10013000: // UART0 base, TXFIFO reg
|
||||
case 0x10023000: // UART1 base, TXFIFO reg
|
||||
@ -849,7 +722,7 @@ iss::status riscv_hart_m_p<BASE>::write_mem(phys_addr_t paddr, unsigned length,
|
||||
|
||||
template <typename BASE> inline void riscv_hart_m_p<BASE>::reset(uint64_t address) {
|
||||
BASE::reset(address);
|
||||
state.mstatus = hart_state<reg_t>::mstatus_reset_val;
|
||||
state.mstatus = hart_state_type::mstatus_reset_val;
|
||||
}
|
||||
|
||||
template <typename BASE> void riscv_hart_m_p<BASE>::check_interrupt() {
|
||||
@ -861,12 +734,15 @@ template <typename BASE> void riscv_hart_m_p<BASE>::check_interrupt() {
|
||||
auto ena_irq = csr[mip] & csr[mie];
|
||||
|
||||
bool mie = state.mstatus.MIE;
|
||||
auto m_enabled = this->reg.machine_state < PRIV_M || (this->reg.machine_state == PRIV_M && mie);
|
||||
auto m_enabled = this->reg.PRIV < PRIV_M || (this->reg.PRIV == PRIV_M && mie);
|
||||
auto enabled_interrupts = m_enabled ? ena_irq & ~ideleg : 0;
|
||||
|
||||
if (enabled_interrupts != 0) {
|
||||
int res = 0;
|
||||
while ((enabled_interrupts & 1) == 0) enabled_interrupts >>= 1, res++;
|
||||
while ((enabled_interrupts & 1) == 0) {
|
||||
enabled_interrupts >>= 1;
|
||||
res++;
|
||||
}
|
||||
this->reg.pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
|
||||
}
|
||||
}
|
||||
@ -906,7 +782,7 @@ template <typename BASE> uint64_t riscv_hart_m_p<BASE>::enter_trap(uint64_t flag
|
||||
this->reg.NEXT_PC = ivec & ~0x1UL;
|
||||
if ((ivec & 0x1) == 1 && trap_id != 0) this->reg.NEXT_PC += 4 * cause;
|
||||
// reset trap state
|
||||
this->reg.machine_state = PRIV_M;
|
||||
this->reg.PRIV = PRIV_M;
|
||||
this->reg.trap_state = 0;
|
||||
std::array<char, 32> buffer;
|
||||
sprintf(buffer.data(), "0x%016lx", addr);
|
||||
@ -918,20 +794,7 @@ template <typename BASE> uint64_t riscv_hart_m_p<BASE>::enter_trap(uint64_t flag
|
||||
}
|
||||
|
||||
template <typename BASE> uint64_t riscv_hart_m_p<BASE>::leave_trap(uint64_t flags) {
|
||||
auto cur_priv = this->reg.machine_state;
|
||||
auto inst_priv = flags & 0x3;
|
||||
auto status = state.mstatus;
|
||||
|
||||
// pop the relevant lower-privilege interrupt enable and privilege mode stack
|
||||
// clear respective yIE
|
||||
if (inst_priv == PRIV_M) {
|
||||
this->reg.machine_state = state.mstatus.MPP;
|
||||
state.mstatus.MPP = 0; // clear mpp to U mode
|
||||
state.mstatus.MIE = state.mstatus.MPIE;
|
||||
} else {
|
||||
CLOG(ERROR, disass) << "Unsupported mode:" << inst_priv;
|
||||
}
|
||||
|
||||
state.mstatus.MIE = state.mstatus.MPIE;
|
||||
// sets the pc to the value stored in the x epc register.
|
||||
this->reg.NEXT_PC = csr[mepc];
|
||||
CLOG(INFO, disass) << "Executing xRET";
|
||||
@ -941,4 +804,4 @@ template <typename BASE> uint64_t riscv_hart_m_p<BASE>::leave_trap(uint64_t flag
|
||||
} // namespace arch
|
||||
} // namespace iss
|
||||
|
||||
#endif /* _RISCV_CORE_H_ */
|
||||
#endif /* _RISCV_HART_M_P_H */
|
||||
|
1199
incl/iss/arch/riscv_hart_msu_vp.h
Normal file
1199
incl/iss/arch/riscv_hart_msu_vp.h
Normal file
File diff suppressed because it is too large
Load Diff
889
incl/iss/arch/riscv_hart_mu_p.h
Normal file
889
incl/iss/arch/riscv_hart_mu_p.h
Normal file
@ -0,0 +1,889 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2021 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Contributors:
|
||||
* eyck@minres.com - initial implementation
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _RISCV_HART_MU_P_H
|
||||
#define _RISCV_HART_MU_P_H
|
||||
|
||||
#include "riscv_hart_common.h"
|
||||
#include "iss/arch/traits.h"
|
||||
#include "iss/instrumentation_if.h"
|
||||
#include "iss/log_categories.h"
|
||||
#include "iss/vm_if.h"
|
||||
#ifndef FMT_HEADER_ONLY
|
||||
#define FMT_HEADER_ONLY
|
||||
#endif
|
||||
#include <array>
|
||||
#include <elfio/elfio.hpp>
|
||||
#include <fmt/format.h>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include <util/bit_field.h>
|
||||
#include <util/ities.h>
|
||||
#include <util/sparse_array.h>
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
#define likely(x) x
|
||||
#define unlikely(x) x
|
||||
#endif
|
||||
|
||||
namespace iss {
|
||||
namespace arch {
|
||||
|
||||
enum features_e{FEAT_NONE, FEAT_PMP, FEAT_EXT_N};
|
||||
|
||||
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'}};
|
||||
const std::array<const char *, 16> trap_str = {{""
|
||||
"Instruction address misaligned", // 0
|
||||
"Instruction access fault", // 1
|
||||
"Illegal instruction", // 2
|
||||
"Breakpoint", // 3
|
||||
"Load address misaligned", // 4
|
||||
"Load access fault", // 5
|
||||
"Store/AMO address misaligned", // 6
|
||||
"Store/AMO access fault", // 7
|
||||
"Environment call from U-mode", // 8
|
||||
"Environment call from S-mode", // 9
|
||||
"Reserved", // a
|
||||
"Environment call from M-mode", // b
|
||||
"Instruction page fault", // c
|
||||
"Load page fault", // d
|
||||
"Reserved", // e
|
||||
"Store/AMO page fault"}};
|
||||
const std::array<const char *, 12> irq_str = {
|
||||
{"User software interrupt", "Supervisor software interrupt", "Reserved", "Machine software interrupt",
|
||||
"User timer interrupt", "Supervisor timer interrupt", "Reserved", "Machine timer interrupt",
|
||||
"User external interrupt", "Supervisor external interrupt", "Reserved", "Machine external interrupt"}};
|
||||
public:
|
||||
using super = BASE;
|
||||
using this_class = riscv_hart_mu_p<BASE, FEAT>;
|
||||
using phys_addr_t = typename super::phys_addr_t;
|
||||
using reg_t = typename super::reg_t;
|
||||
using addr_t = typename super::addr_t;
|
||||
|
||||
using rd_csr_f = iss::status (this_class::*)(unsigned addr, reg_t &);
|
||||
using wr_csr_f = iss::status (this_class::*)(unsigned addr, reg_t);
|
||||
|
||||
// primary template
|
||||
template <class T, class Enable = void> struct hart_state {};
|
||||
// specialization 32bit
|
||||
template <typename T> class hart_state<T, typename std::enable_if<std::is_same<T, uint32_t>::value>::type> {
|
||||
public:
|
||||
BEGIN_BF_DECL(mstatus_t, T);
|
||||
// SD bit is read-only and is set when either the FS or XS bits encode a Dirty state (i.e., SD=((FS==11) OR XS==11)))
|
||||
BF_FIELD(SD, 31, 1);
|
||||
// Trap SRET
|
||||
BF_FIELD(TSR, 22, 1);
|
||||
// Timeout Wait
|
||||
BF_FIELD(TW, 21, 1);
|
||||
// Trap Virtual Memory
|
||||
BF_FIELD(TVM, 20, 1);
|
||||
// Make eXecutable Readable
|
||||
BF_FIELD(MXR, 19, 1);
|
||||
// permit Supervisor User Memory access
|
||||
BF_FIELD(SUM, 18, 1);
|
||||
// Modify PRiVilege
|
||||
BF_FIELD(MPRV, 17, 1);
|
||||
// status of additional user-mode extensions and associated state, All off/None dirty or clean, some on/None dirty, some clean/Some dirty
|
||||
BF_FIELD(XS, 15, 2);
|
||||
// floating-point unit status Off/Initial/Clean/Dirty
|
||||
BF_FIELD(FS, 13, 2);
|
||||
// machine previous privilege
|
||||
BF_FIELD(MPP, 11, 2);
|
||||
// supervisor previous privilege
|
||||
BF_FIELD(SPP, 8, 1);
|
||||
// previous machine interrupt-enable
|
||||
BF_FIELD(MPIE, 7, 1);
|
||||
// previous supervisor interrupt-enable
|
||||
BF_FIELD(SPIE, 5, 1);
|
||||
// previous user interrupt-enable
|
||||
BF_FIELD(UPIE, 4, 1);
|
||||
// machine interrupt-enable
|
||||
BF_FIELD(MIE, 3, 1);
|
||||
// supervisor interrupt-enable
|
||||
BF_FIELD(SIE, 1, 1);
|
||||
// user interrupt-enable
|
||||
BF_FIELD(UIE, 0, 1);
|
||||
END_BF_DECL();
|
||||
|
||||
mstatus_t mstatus;
|
||||
|
||||
static const reg_t mstatus_reset_val = 0;
|
||||
|
||||
void write_mstatus(T val, unsigned priv_lvl) {
|
||||
auto mask = get_mask(priv_lvl);
|
||||
auto new_val = (mstatus.backing.val & ~mask) | (val & mask);
|
||||
mstatus = new_val;
|
||||
}
|
||||
|
||||
T satp;
|
||||
|
||||
static constexpr uint32_t get_mask(unsigned priv_lvl) {
|
||||
#if __cplusplus < 201402L
|
||||
return priv_lvl == PRIV_U ? 0x80000011UL : priv_lvl == PRIV_S ? 0x800de133UL : 0x807ff9ddUL;
|
||||
#else
|
||||
switch (priv_lvl) {
|
||||
case PRIV_U: return 0x80000011UL; // 0b1000 0000 0000 0000 0000 0000 0001 0001
|
||||
default: return 0x807ff9ddUL; // 0b1000 0000 0111 1111 1111 1001 1011 1011
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
using hart_state_type = hart_state<reg_t>;
|
||||
|
||||
constexpr reg_t get_irq_mask(size_t mode) {
|
||||
std::array<const reg_t, 4> m = {{
|
||||
0b000100010001, // U mode
|
||||
0b001100110011, // S mode
|
||||
0,
|
||||
0b101110111011 // M mode
|
||||
}};
|
||||
return m[mode];
|
||||
}
|
||||
|
||||
riscv_hart_mu_p();
|
||||
virtual ~riscv_hart_mu_p() = default;
|
||||
|
||||
void reset(uint64_t address) override;
|
||||
|
||||
std::pair<uint64_t, bool> load_file(std::string name, int type = -1) 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_mu_p::enter_trap(flags, fault_data); }
|
||||
virtual uint64_t enter_trap(uint64_t flags, uint64_t addr) override;
|
||||
virtual uint64_t leave_trap(uint64_t flags) override;
|
||||
|
||||
const reg_t& get_mhartid() const { return mhartid_reg; }
|
||||
void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; };
|
||||
|
||||
void disass_output(uint64_t pc, const std::string instr) override {
|
||||
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]",
|
||||
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.icount);
|
||||
};
|
||||
|
||||
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
|
||||
|
||||
void setMemReadCb(std::function<iss::status(phys_addr_t, unsigned, uint8_t* const)> const& memReadCb) {
|
||||
mem_read_cb = memReadCb;
|
||||
}
|
||||
|
||||
void setMemWriteCb(std::function<iss::status(phys_addr_t, unsigned, const uint8_t* const)> const& memWriteCb) {
|
||||
mem_write_cb = memWriteCb;
|
||||
}
|
||||
|
||||
void set_csr(unsigned addr, reg_t val){
|
||||
csr[addr & csr.page_addr_mask] = val;
|
||||
}
|
||||
|
||||
protected:
|
||||
struct riscv_instrumentation_if : public iss::instrumentation_if {
|
||||
|
||||
riscv_instrumentation_if(riscv_hart_mu_p<BASE, FEAT> &arch)
|
||||
: arch(arch) {}
|
||||
/**
|
||||
* get the name of this architecture
|
||||
*
|
||||
* @return the name of this architecture
|
||||
*/
|
||||
const std::string core_type_name() const override { return traits<BASE>::core_type; }
|
||||
|
||||
virtual uint64_t get_pc() { return arch.get_pc(); };
|
||||
|
||||
virtual uint64_t get_next_pc() { return arch.get_next_pc(); };
|
||||
|
||||
virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; };
|
||||
|
||||
riscv_hart_mu_p<BASE, FEAT> &arch;
|
||||
};
|
||||
|
||||
friend struct riscv_instrumentation_if;
|
||||
addr_t get_pc() { return this->reg.PC; }
|
||||
addr_t get_next_pc() { return this->reg.NEXT_PC; }
|
||||
|
||||
virtual iss::status read_mem(phys_addr_t addr, unsigned length, uint8_t *const data);
|
||||
virtual iss::status write_mem(phys_addr_t addr, unsigned length, const uint8_t *const data);
|
||||
|
||||
virtual iss::status read_csr(unsigned addr, reg_t &val);
|
||||
virtual iss::status write_csr(unsigned addr, reg_t val);
|
||||
|
||||
hart_state_type state;
|
||||
uint64_t cycle_offset;
|
||||
reg_t fault_data;
|
||||
uint64_t tohost = tohost_dflt;
|
||||
uint64_t fromhost = fromhost_dflt;
|
||||
unsigned to_host_wr_cnt = 0;
|
||||
riscv_instrumentation_if instr_if;
|
||||
|
||||
using mem_type = util::sparse_array<uint8_t, 1ULL << 32>;
|
||||
using csr_type = util::sparse_array<typename traits<BASE>::reg_t, 1ULL << 12, 12>;
|
||||
using csr_page_type = typename csr_type::page_type;
|
||||
mem_type mem;
|
||||
csr_type csr;
|
||||
std::stringstream uart_buf;
|
||||
std::unordered_map<reg_t, uint64_t> ptw;
|
||||
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;
|
||||
|
||||
private:
|
||||
iss::status read_reg(unsigned addr, reg_t &val);
|
||||
iss::status write_reg(unsigned addr, reg_t val);
|
||||
iss::status read_cycle(unsigned addr, reg_t &val);
|
||||
iss::status read_time(unsigned addr, reg_t &val);
|
||||
iss::status read_status(unsigned addr, reg_t &val);
|
||||
iss::status write_status(unsigned addr, reg_t val);
|
||||
iss::status read_ie(unsigned addr, reg_t &val);
|
||||
iss::status write_ie(unsigned addr, reg_t val);
|
||||
iss::status read_ip(unsigned addr, reg_t &val);
|
||||
iss::status write_ip(unsigned addr, reg_t val);
|
||||
iss::status read_hartid(unsigned addr, reg_t &val);
|
||||
|
||||
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();
|
||||
};
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p()
|
||||
: state()
|
||||
, cycle_offset(0)
|
||||
, instr_if(*this) {
|
||||
csr[misa] = traits<BASE>::MISA_VAL;
|
||||
uart_buf.str("");
|
||||
for (unsigned addr = mcycle; addr <= hpmcounter31; ++addr) csr_wr_cb[addr] = nullptr;
|
||||
for (unsigned addr = mcycleh; addr <= hpmcounter31h; ++addr) csr_wr_cb[addr] = nullptr;
|
||||
// special handling
|
||||
csr_rd_cb[time] = &this_class::read_time;
|
||||
csr_wr_cb[time] = nullptr;
|
||||
csr_rd_cb[timeh] = &this_class::read_time;
|
||||
csr_wr_cb[timeh] = nullptr;
|
||||
csr_rd_cb[mcycle] = &this_class::read_cycle;
|
||||
csr_rd_cb[mcycleh] = &this_class::read_cycle;
|
||||
csr_rd_cb[minstret] = &this_class::read_cycle;
|
||||
csr_rd_cb[minstreth] = &this_class::read_cycle;
|
||||
csr_rd_cb[mstatus] = &this_class::read_status;
|
||||
csr_wr_cb[mstatus] = &this_class::write_status;
|
||||
csr_rd_cb[ustatus] = &this_class::read_status;
|
||||
csr_wr_cb[ustatus] = &this_class::write_status;
|
||||
csr_rd_cb[mip] = &this_class::read_ip;
|
||||
csr_wr_cb[mip] = &this_class::write_ip;
|
||||
csr_rd_cb[uip] = &this_class::read_ip;
|
||||
csr_wr_cb[uip] = &this_class::write_ip;
|
||||
csr_rd_cb[mie] = &this_class::read_ie;
|
||||
csr_wr_cb[mie] = &this_class::write_ie;
|
||||
csr_rd_cb[uie] = &this_class::read_ie;
|
||||
csr_wr_cb[uie] = &this_class::write_ie;
|
||||
csr_rd_cb[mhartid] = &this_class::read_hartid;
|
||||
// common regs
|
||||
const std::array<unsigned, 6> addrs{{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;
|
||||
}
|
||||
// read-only registers
|
||||
csr_rd_cb[misa] = &this_class::read_reg;
|
||||
csr_wr_cb[misa] = nullptr;
|
||||
|
||||
if(FEAT & FEAT_PMP){
|
||||
for(size_t i=pmpaddr0; i<=pmpaddr15; ++i){
|
||||
csr_rd_cb[i] = &this_class::read_reg;
|
||||
csr_wr_cb[i] = &this_class::write_reg;
|
||||
}
|
||||
for(size_t i=pmpcfg0; i<=pmpcfg3; ++i){
|
||||
csr_rd_cb[i] = &this_class::read_reg;
|
||||
csr_wr_cb[i] = &this_class::write_reg;
|
||||
}
|
||||
}
|
||||
if(FEAT & FEAT_EXT_N){
|
||||
csr_rd_cb[mideleg] = &this_class::read_reg;
|
||||
csr_wr_cb[mideleg] = &this_class::write_reg;
|
||||
csr_rd_cb[medeleg] = &this_class::read_reg;
|
||||
csr_wr_cb[medeleg] = &this_class::write_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) {
|
||||
FILE *fp = fopen(name.c_str(), "r");
|
||||
if (fp) {
|
||||
std::array<char, 5> buf;
|
||||
auto n = fread(buf.data(), 1, 4, fp);
|
||||
if (n != 4) throw std::runtime_error("input file has insufficient size");
|
||||
buf[4] = 0;
|
||||
if (strcmp(buf.data() + 1, "ELF") == 0) {
|
||||
fclose(fp);
|
||||
// Create elfio reader
|
||||
ELFIO::elfio reader;
|
||||
// Load ELF data
|
||||
if (!reader.load(name)) throw std::runtime_error("could not process elf file");
|
||||
// check elf properties
|
||||
if (reader.get_class() != ELFCLASS32)
|
||||
if (sizeof(reg_t) == 4) throw std::runtime_error("wrong elf class in file");
|
||||
if (reader.get_type() != ET_EXEC) throw std::runtime_error("wrong elf type in file");
|
||||
if (reader.get_machine() != EM_RISCV) throw std::runtime_error("wrong elf machine in file");
|
||||
for (const auto pseg : reader.segments) {
|
||||
const auto fsize = pseg->get_file_size(); // 0x42c/0x0
|
||||
const auto seg_data = pseg->get_data();
|
||||
if (fsize > 0) {
|
||||
auto res = this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE,
|
||||
traits<BASE>::MEM, pseg->get_physical_address(),
|
||||
fsize, reinterpret_cast<const uint8_t *const>(seg_data));
|
||||
if (res != iss::Ok)
|
||||
LOG(ERROR) << "problem writing " << fsize << "bytes to 0x" << std::hex
|
||||
<< pseg->get_physical_address();
|
||||
}
|
||||
}
|
||||
for (const auto sec : reader.sections) {
|
||||
if (sec->get_name() == ".tohost") {
|
||||
tohost = sec->get_address();
|
||||
fromhost = tohost + 0x40;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair(reader.get_entry(), true);
|
||||
}
|
||||
throw std::runtime_error("memory load file is not a valid elf file");
|
||||
}
|
||||
throw std::runtime_error("memory load file not found");
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_mu_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) {
|
||||
LOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
} else if(access && iss::access_type::FETCH){
|
||||
LOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
} else {
|
||||
LOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr;
|
||||
}
|
||||
#endif
|
||||
try {
|
||||
switch (space) {
|
||||
case traits<BASE>::MEM: {
|
||||
if (unlikely((access == iss::access_type::FETCH || access == iss::access_type::DEBUG_FETCH) && (addr & 0x1) == 1)) {
|
||||
fault_data = addr;
|
||||
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
|
||||
this->reg.trap_state = (1 << 31); // issue trap 0
|
||||
return iss::Err;
|
||||
}
|
||||
try {
|
||||
auto res = type==iss::address_type::PHYSICAL?
|
||||
read_mem( BASE::v2p(phys_addr_t{access, space, addr}), length, data):
|
||||
read_mem( BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
|
||||
if (unlikely(res != iss::Ok)) this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
|
||||
return res;
|
||||
} catch (trap_access &ta) {
|
||||
this->reg.trap_state = (1 << 31) | ta.id;
|
||||
return iss::Err;
|
||||
}
|
||||
} break;
|
||||
case traits<BASE>::CSR: {
|
||||
if (length != sizeof(reg_t)) return iss::Err;
|
||||
return read_csr(addr, *reinterpret_cast<reg_t *const>(data));
|
||||
} break;
|
||||
case traits<BASE>::FENCE: {
|
||||
if ((addr + length) > mem.size()) return iss::Err;
|
||||
return iss::Ok;
|
||||
} break;
|
||||
case traits<BASE>::RES: {
|
||||
auto it = atomic_reservation.find(addr);
|
||||
if (it != atomic_reservation.end() && it->second != 0) {
|
||||
memset(data, 0xff, length);
|
||||
atomic_reservation.erase(addr);
|
||||
} else
|
||||
memset(data, 0, length);
|
||||
} break;
|
||||
default:
|
||||
return iss::Err; // assert("Not supported");
|
||||
}
|
||||
return iss::Ok;
|
||||
} catch (trap_access &ta) {
|
||||
this->reg.trap_state = (1 << 31) | ta.id;
|
||||
return iss::Err;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_mu_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 " : "";
|
||||
switch (length) {
|
||||
case 8:
|
||||
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint64_t *)&data[0] << std::dec
|
||||
<< ") @addr 0x" << std::hex << addr;
|
||||
break;
|
||||
case 4:
|
||||
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint32_t *)&data[0] << std::dec
|
||||
<< ") @addr 0x" << std::hex << addr;
|
||||
break;
|
||||
case 2:
|
||||
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << *(uint16_t *)&data[0] << std::dec
|
||||
<< ") @addr 0x" << std::hex << addr;
|
||||
break;
|
||||
case 1:
|
||||
LOG(TRACE) << prefix << "write of " << length << " bytes (0x" << std::hex << (uint16_t)data[0] << std::dec
|
||||
<< ") @addr 0x" << std::hex << addr;
|
||||
break;
|
||||
default:
|
||||
LOG(TRACE) << prefix << "write of " << length << " bytes @addr " << addr;
|
||||
}
|
||||
#endif
|
||||
try {
|
||||
switch (space) {
|
||||
case traits<BASE>::MEM: {
|
||||
if (unlikely((access && iss::access_type::FETCH) && (addr & 0x1) == 1)) {
|
||||
fault_data = addr;
|
||||
if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
|
||||
this->reg.trap_state = (1 << 31); // issue trap 0
|
||||
return iss::Err;
|
||||
}
|
||||
try {
|
||||
auto res = type==iss::address_type::PHYSICAL?
|
||||
write_mem(phys_addr_t{access, space, addr}, length, data):
|
||||
write_mem(BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
|
||||
if (unlikely(res != iss::Ok))
|
||||
this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 7 (Store/AMO access fault)
|
||||
return res;
|
||||
} catch (trap_access &ta) {
|
||||
this->reg.trap_state = (1 << 31) | ta.id;
|
||||
return iss::Err;
|
||||
}
|
||||
|
||||
phys_addr_t paddr = BASE::v2p(iss::addr_t{access, type, space, addr});
|
||||
if ((paddr.val + length) > mem.size()) return iss::Err;
|
||||
switch (paddr.val) {
|
||||
case 0x10013000: // UART0 base, TXFIFO reg
|
||||
case 0x10023000: // UART1 base, TXFIFO reg
|
||||
uart_buf << (char)data[0];
|
||||
if (((char)data[0]) == '\n' || data[0] == 0) {
|
||||
// LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send
|
||||
// '"<<uart_buf.str()<<"'";
|
||||
std::cout << uart_buf.str();
|
||||
uart_buf.str("");
|
||||
}
|
||||
return iss::Ok;
|
||||
case 0x10008000: { // HFROSC base, hfrosccfg reg
|
||||
auto &p = mem(paddr.val / mem.page_size);
|
||||
auto offs = paddr.val & mem.page_addr_mask;
|
||||
std::copy(data, data + length, p.data() + offs);
|
||||
auto &x = *(p.data() + offs + 3);
|
||||
if (x & 0x40) x |= 0x80; // hfroscrdy = 1 if hfroscen==1
|
||||
return iss::Ok;
|
||||
}
|
||||
case 0x10008008: { // HFROSC base, pllcfg reg
|
||||
auto &p = mem(paddr.val / mem.page_size);
|
||||
auto offs = paddr.val & mem.page_addr_mask;
|
||||
std::copy(data, data + length, p.data() + offs);
|
||||
auto &x = *(p.data() + offs + 3);
|
||||
x |= 0x80; // set pll lock upon writing
|
||||
return iss::Ok;
|
||||
} break;
|
||||
default: {}
|
||||
}
|
||||
} break;
|
||||
case traits<BASE>::CSR: {
|
||||
if (length != sizeof(reg_t)) return iss::Err;
|
||||
return write_csr(addr, *reinterpret_cast<const reg_t *>(data));
|
||||
} break;
|
||||
case traits<BASE>::FENCE: {
|
||||
if ((addr + length) > mem.size()) return iss::Err;
|
||||
switch (addr) {
|
||||
case 2:
|
||||
case 3: {
|
||||
ptw.clear();
|
||||
auto tvm = state.mstatus.TVM;
|
||||
return iss::Ok;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case traits<BASE>::RES: {
|
||||
atomic_reservation[addr] = data[0];
|
||||
} break;
|
||||
default:
|
||||
return iss::Err;
|
||||
}
|
||||
return iss::Ok;
|
||||
} catch (trap_access &ta) {
|
||||
this->reg.trap_state = (1 << 31) | ta.id;
|
||||
return iss::Err;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_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
|
||||
throw illegal_instruction_fault(this->fault_data);
|
||||
auto it = csr_rd_cb.find(addr);
|
||||
if (it == csr_rd_cb.end() || !it->second) // non existent register
|
||||
throw illegal_instruction_fault(this->fault_data);
|
||||
return (this->*(it->second))(addr, val);
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_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
|
||||
throw illegal_instruction_fault(this->fault_data);
|
||||
if((addr&0xc00)==0xc00) // writing to read-only region
|
||||
throw illegal_instruction_fault(this->fault_data);
|
||||
auto it = csr_wr_cb.find(addr);
|
||||
if (it == csr_wr_cb.end() || !it->second) // non existent register
|
||||
throw illegal_instruction_fault(this->fault_data);
|
||||
return (this->*(it->second))(addr, val);
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_reg(unsigned addr, reg_t &val) {
|
||||
val = csr[addr];
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_reg(unsigned addr, reg_t val) {
|
||||
csr[addr] = val;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_cycle(unsigned addr, reg_t &val) {
|
||||
auto cycle_val = this->reg.icount + cycle_offset;
|
||||
if (addr == mcycle) {
|
||||
val = static_cast<reg_t>(cycle_val);
|
||||
} else if (addr == mcycleh) {
|
||||
if (sizeof(typename traits<BASE>::reg_t) != 4) return iss::Err;
|
||||
val = static_cast<reg_t>(cycle_val >> 32);
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_time(unsigned addr, reg_t &val) {
|
||||
uint64_t time_val = (this->reg.icount + cycle_offset) / (100000000 / 32768 - 1); //-> ~3052;
|
||||
if (addr == time) {
|
||||
val = static_cast<reg_t>(time_val);
|
||||
} else if (addr == timeh) {
|
||||
if (sizeof(typename traits<BASE>::reg_t) != 4) return iss::Err;
|
||||
val = static_cast<reg_t>(time_val >> 32);
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_status(unsigned addr, reg_t &val) {
|
||||
auto req_priv_lvl = (addr >> 8) & 0x3;
|
||||
val = state.mstatus & hart_state_type::get_mask(req_priv_lvl);
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_status(unsigned addr, reg_t val) {
|
||||
auto req_priv_lvl = (addr >> 8) & 0x3;
|
||||
state.write_mstatus(val, req_priv_lvl);
|
||||
check_interrupt();
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_ie(unsigned addr, reg_t &val) {
|
||||
val = csr[mie];
|
||||
val &= csr[mideleg];
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_hartid(unsigned addr, reg_t &val) {
|
||||
val = mhartid_reg;
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_ie(unsigned addr, reg_t val) {
|
||||
auto req_priv_lvl = (addr >> 8) & 0x3;
|
||||
auto mask = get_irq_mask(req_priv_lvl);
|
||||
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) {
|
||||
val = csr[mip];
|
||||
val &= csr[mideleg];
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_ip(unsigned addr, reg_t val) {
|
||||
auto req_priv_lvl = (addr >> 8) & 0x3;
|
||||
auto mask = get_irq_mask(req_priv_lvl);
|
||||
mask &= ~(1 << 7); // MTIP is read only
|
||||
csr[mip] = (csr[mip] & ~mask) | (val & mask);
|
||||
check_interrupt();
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
|
||||
if ((paddr.val + length) > mem.size()) return iss::Err;
|
||||
if(mem_read_cb) return mem_read_cb(paddr, length, data);
|
||||
switch (paddr.val) {
|
||||
case 0x0200BFF8: { // CLINT base, mtime reg
|
||||
if (sizeof(reg_t) < length) return iss::Err;
|
||||
reg_t time_val;
|
||||
this->read_csr(time, time_val);
|
||||
std::copy((uint8_t *)&time_val, ((uint8_t *)&time_val) + length, data);
|
||||
} break;
|
||||
case 0x10008000: {
|
||||
const mem_type::page_type &p = mem(paddr.val / mem.page_size);
|
||||
uint64_t offs = paddr.val & mem.page_addr_mask;
|
||||
std::copy(p.data() + offs, p.data() + offs + length, data);
|
||||
if (this->reg.icount > 30000) data[3] |= 0x80;
|
||||
} break;
|
||||
default: {
|
||||
const auto &p = mem(paddr.val / mem.page_size);
|
||||
auto offs = paddr.val & mem.page_addr_mask;
|
||||
std::copy(p.data() + offs, p.data() + offs + length, data);
|
||||
}
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) {
|
||||
if ((paddr.val + length) > mem.size()) return iss::Err;
|
||||
if(mem_write_cb) return mem_write_cb(paddr, length, data);
|
||||
switch (paddr.val) {
|
||||
case 0x10013000: // UART0 base, TXFIFO reg
|
||||
case 0x10023000: // UART1 base, TXFIFO reg
|
||||
uart_buf << (char)data[0];
|
||||
if (((char)data[0]) == '\n' || data[0] == 0) {
|
||||
// LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send
|
||||
// '"<<uart_buf.str()<<"'";
|
||||
std::cout << uart_buf.str();
|
||||
uart_buf.str("");
|
||||
}
|
||||
break;
|
||||
case 0x10008000: { // HFROSC base, hfrosccfg reg
|
||||
mem_type::page_type &p = mem(paddr.val / mem.page_size);
|
||||
size_t offs = paddr.val & mem.page_addr_mask;
|
||||
std::copy(data, data + length, p.data() + offs);
|
||||
uint8_t &x = *(p.data() + offs + 3);
|
||||
if (x & 0x40) x |= 0x80; // hfroscrdy = 1 if hfroscen==1
|
||||
} break;
|
||||
case 0x10008008: { // HFROSC base, pllcfg reg
|
||||
mem_type::page_type &p = mem(paddr.val / mem.page_size);
|
||||
size_t offs = paddr.val & mem.page_addr_mask;
|
||||
std::copy(data, data + length, p.data() + offs);
|
||||
uint8_t &x = *(p.data() + offs + 3);
|
||||
x |= 0x80; // set pll lock upon writing
|
||||
} break;
|
||||
default: {
|
||||
mem_type::page_type &p = mem(paddr.val / mem.page_size);
|
||||
std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask));
|
||||
// tohost handling in case of riscv-test
|
||||
if (paddr.access && iss::access_type::FUNC) {
|
||||
auto tohost_upper = (traits<BASE>::XLEN == 32 && paddr.val == (tohost + 4));
|
||||
auto tohost_lower =
|
||||
(traits<BASE>::XLEN == 32 && paddr.val == tohost);
|
||||
if (tohost_lower || tohost_upper) {
|
||||
uint64_t hostvar = *reinterpret_cast<uint64_t *>(p.data() + (tohost & mem.page_addr_mask));
|
||||
if (tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) {
|
||||
switch (hostvar >> 48) {
|
||||
case 0:
|
||||
if (hostvar != 0x1) {
|
||||
LOG(FATAL) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
|
||||
<< "), stopping simulation";
|
||||
} else {
|
||||
LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
|
||||
<< "), stopping simulation";
|
||||
}
|
||||
this->reg.trap_state=std::numeric_limits<uint32_t>::max();
|
||||
this->interrupt_sim=hostvar;
|
||||
break;
|
||||
//throw(iss::simulation_stopped(hostvar));
|
||||
case 0x0101: {
|
||||
char c = static_cast<char>(hostvar & 0xff);
|
||||
if (c == '\n' || c == 0) {
|
||||
LOG(INFO) << "tohost send '" << uart_buf.str() << "'";
|
||||
uart_buf.str("");
|
||||
} else
|
||||
uart_buf << c;
|
||||
to_host_wr_cnt = 0;
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (tohost_lower)
|
||||
to_host_wr_cnt++;
|
||||
} else if (traits<BASE>::XLEN == 32 && paddr.val == fromhost + 4) {
|
||||
uint64_t fhostvar = *reinterpret_cast<uint64_t *>(p.data() + (fromhost & mem.page_addr_mask));
|
||||
*reinterpret_cast<uint64_t *>(p.data() + (tohost & mem.page_addr_mask)) = fhostvar;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return iss::Ok;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> inline void riscv_hart_mu_p<BASE, FEAT>::reset(uint64_t address) {
|
||||
BASE::reset(address);
|
||||
state.mstatus = hart_state_type::mstatus_reset_val;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> void riscv_hart_mu_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:
|
||||
// external interrupts, software interrupts, timer interrupts, then finally
|
||||
// any synchronous traps.
|
||||
auto ena_irq = csr[mip] & csr[mie];
|
||||
|
||||
bool mie = state.mstatus.MIE;
|
||||
auto m_enabled = this->reg.PRIV < PRIV_M || (this->reg.PRIV == PRIV_M && mie);
|
||||
auto enabled_interrupts = m_enabled ? ena_irq & ~ideleg : 0;
|
||||
|
||||
if (enabled_interrupts != 0) {
|
||||
int res = 0;
|
||||
while ((enabled_interrupts & 1) == 0) {
|
||||
enabled_interrupts >>= 1;
|
||||
res++;
|
||||
}
|
||||
this->reg.pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
|
||||
}
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::enter_trap(uint64_t flags, uint64_t addr) {
|
||||
// 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 + this->reg.PRIV; // adjust environment call cause
|
||||
// calculate effective privilege level
|
||||
auto new_priv = PRIV_M;
|
||||
if (trap_id == 0) { // exception
|
||||
if (this->reg.PRIV != PRIV_M && ((csr[medeleg] >> cause) & 0x1) != 0)
|
||||
new_priv = PRIV_U;
|
||||
// store ret addr in xepc register
|
||||
csr[uepc | (new_priv << 8)] = static_cast<reg_t>(addr); // 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.
|
||||
*/
|
||||
csr[utval | (new_priv << 8)] = fault_data;
|
||||
fault_data = 0;
|
||||
} else {
|
||||
if (this->reg.PRIV != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0)
|
||||
new_priv = PRIV_U;
|
||||
csr[uepc | (new_priv << 8)] = this->reg.NEXT_PC; // store next address if interrupt
|
||||
this->reg.pending_trap = 0;
|
||||
}
|
||||
size_t adr = ucause | (new_priv << 8);
|
||||
csr[adr] = (trap_id << 31) + cause;
|
||||
// update mstatus
|
||||
// xPP field of mstatus is written with the active privilege mode at the time
|
||||
// of the trap; the x PIE field of mstatus
|
||||
// is written with the value of the active interrupt-enable bit at the time of
|
||||
// the trap; and the x IE field of mstatus
|
||||
// is cleared
|
||||
// store the actual privilege level in yPP and store interrupt enable flags
|
||||
switch (new_priv) {
|
||||
case PRIV_M:
|
||||
state.mstatus.MPP = this->reg.PRIV;
|
||||
state.mstatus.MPIE = state.mstatus.MIE;
|
||||
state.mstatus.MIE = false;
|
||||
break;
|
||||
case PRIV_U:
|
||||
state.mstatus.UPIE = state.mstatus.UIE;
|
||||
state.mstatus.UIE = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// get trap vector
|
||||
auto ivec = csr[utvec | (new_priv << 8)];
|
||||
// calculate addr// set NEXT_PC to trap addressess to jump to based on MODE
|
||||
// bits in mtvec
|
||||
this->reg.NEXT_PC = ivec & ~0x1UL;
|
||||
if ((ivec & 0x1) == 1 && trap_id != 0) this->reg.NEXT_PC += 4 * cause;
|
||||
// reset trap state
|
||||
this->reg.PRIV = new_priv;
|
||||
this->reg.trap_state = 0;
|
||||
std::array<char, 32> buffer;
|
||||
sprintf(buffer.data(), "0x%016lx", addr);
|
||||
if((flags&0xffffffff) != 0xffffffff)
|
||||
CLOG(INFO, disass) << (trap_id ? "Interrupt" : "Trap") << " with cause '"
|
||||
<< (trap_id ? irq_str[cause] : trap_str[cause]) << "' (" << cause << ")"
|
||||
<< " at address " << buffer.data() << " occurred, changing privilege level from "
|
||||
<< lvl[this->reg.PRIV] << " to " << lvl[new_priv];
|
||||
return this->reg.NEXT_PC;
|
||||
}
|
||||
|
||||
template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::leave_trap(uint64_t flags) {
|
||||
auto cur_priv = this->reg.PRIV;
|
||||
auto inst_priv = (flags & 0x3)? 3:0;
|
||||
auto status = state.mstatus;
|
||||
// pop the relevant lower-privilege interrupt enable and privilege mode stack
|
||||
// clear respective yIE
|
||||
switch (inst_priv) {
|
||||
case PRIV_M:
|
||||
this->reg.PRIV = state.mstatus.MPP;
|
||||
state.mstatus.MPP = 0; // clear mpp to U mode
|
||||
state.mstatus.MIE = state.mstatus.MPIE;
|
||||
break;
|
||||
case PRIV_U:
|
||||
this->reg.PRIV = 0;
|
||||
state.mstatus.UIE = state.mstatus.UPIE;
|
||||
break;
|
||||
}
|
||||
// sets the pc to the value stored in the x epc register.
|
||||
this->reg.NEXT_PC = csr[uepc | inst_priv << 8];
|
||||
CLOG(INFO, disass) << "Executing xRET , changing privilege level from " << lvl[cur_priv] << " to "
|
||||
<< lvl[this->reg.PRIV];
|
||||
return this->reg.NEXT_PC;
|
||||
}
|
||||
|
||||
} // namespace arch
|
||||
} // namespace iss
|
||||
|
||||
#endif /* _RISCV_HART_MU_P_H */
|
276
incl/iss/arch/tgc_c.h
Normal file
276
incl/iss/arch/tgc_c.h
Normal file
@ -0,0 +1,276 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017 - 2021 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.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef _TGC_C_H_
|
||||
#define _TGC_C_H_
|
||||
|
||||
#include <array>
|
||||
#include <iss/arch/traits.h>
|
||||
#include <iss/arch_if.h>
|
||||
#include <iss/vm_if.h>
|
||||
|
||||
namespace iss {
|
||||
namespace arch {
|
||||
|
||||
struct tgc_c;
|
||||
|
||||
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*, 35> reg_aliases{
|
||||
{"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"}};
|
||||
|
||||
enum constants {XLEN=32, PCLEN=32, MISA_VAL=0b01000000000000000001000100000100, PGSIZE=0x1000, PGMASK=0b111111111111, CSR_SIZE=4096, fence=0, fencei=1, fencevmal=2, fencevmau=3, eei_aligned_addresses=1, 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,
|
||||
TRAP_STATE=NUM_REGS,
|
||||
PENDING_TRAP,
|
||||
ICOUNT
|
||||
};
|
||||
|
||||
using reg_t = uint32_t;
|
||||
|
||||
using addr_t = uint32_t;
|
||||
|
||||
using code_word_t = uint32_t; //TODO: check removal
|
||||
|
||||
using virt_addr_t = iss::typed_addr_t<iss::address_type::VIRTUAL>;
|
||||
|
||||
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
|
||||
|
||||
static constexpr std::array<const uint32_t, 38> 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}};
|
||||
|
||||
static constexpr std::array<const uint32_t, 38> 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}};
|
||||
|
||||
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
|
||||
|
||||
enum sreg_flag_e { FLAGS };
|
||||
|
||||
enum mem_type_e { MEM, CSR, FENCE, RES };
|
||||
|
||||
enum class opcode_e : unsigned short {
|
||||
LUI = 0,
|
||||
AUIPC = 1,
|
||||
JAL = 2,
|
||||
JALR = 3,
|
||||
BEQ = 4,
|
||||
BNE = 5,
|
||||
BLT = 6,
|
||||
BGE = 7,
|
||||
BLTU = 8,
|
||||
BGEU = 9,
|
||||
LB = 10,
|
||||
LH = 11,
|
||||
LW = 12,
|
||||
LBU = 13,
|
||||
LHU = 14,
|
||||
SB = 15,
|
||||
SH = 16,
|
||||
SW = 17,
|
||||
ADDI = 18,
|
||||
SLTI = 19,
|
||||
SLTIU = 20,
|
||||
XORI = 21,
|
||||
ORI = 22,
|
||||
ANDI = 23,
|
||||
SLLI = 24,
|
||||
SRLI = 25,
|
||||
SRAI = 26,
|
||||
ADD = 27,
|
||||
SUB = 28,
|
||||
SLL = 29,
|
||||
SLT = 30,
|
||||
SLTU = 31,
|
||||
XOR = 32,
|
||||
SRL = 33,
|
||||
SRA = 34,
|
||||
OR = 35,
|
||||
AND = 36,
|
||||
FENCE = 37,
|
||||
ECALL = 38,
|
||||
EBREAK = 39,
|
||||
URET = 40,
|
||||
SRET = 41,
|
||||
MRET = 42,
|
||||
WFI = 43,
|
||||
CSRRW = 44,
|
||||
CSRRS = 45,
|
||||
CSRRC = 46,
|
||||
CSRRWI = 47,
|
||||
CSRRSI = 48,
|
||||
CSRRCI = 49,
|
||||
MUL = 50,
|
||||
MULH = 51,
|
||||
MULHSU = 52,
|
||||
MULHU = 53,
|
||||
DIV = 54,
|
||||
DIVU = 55,
|
||||
REM = 56,
|
||||
REMU = 57,
|
||||
CADDI4SPN = 58,
|
||||
CLW = 59,
|
||||
CSW = 60,
|
||||
CADDI = 61,
|
||||
CNOP = 62,
|
||||
CJAL = 63,
|
||||
CLI = 64,
|
||||
CLUI = 65,
|
||||
CADDI16SP = 66,
|
||||
CSRLI = 67,
|
||||
CSRAI = 68,
|
||||
CANDI = 69,
|
||||
CSUB = 70,
|
||||
CXOR = 71,
|
||||
COR = 72,
|
||||
CAND = 73,
|
||||
CJ = 74,
|
||||
CBEQZ = 75,
|
||||
CBNEZ = 76,
|
||||
CSLLI = 77,
|
||||
CLWSP = 78,
|
||||
CMV = 79,
|
||||
CJR = 80,
|
||||
CADD = 81,
|
||||
CJALR = 82,
|
||||
CEBREAK = 83,
|
||||
CSWSP = 84,
|
||||
DII = 85,
|
||||
MAX_OPCODE
|
||||
};
|
||||
};
|
||||
|
||||
struct tgc_c: public arch_if {
|
||||
|
||||
using virt_addr_t = typename traits<tgc_c>::virt_addr_t;
|
||||
using phys_addr_t = typename traits<tgc_c>::phys_addr_t;
|
||||
using reg_t = typename traits<tgc_c>::reg_t;
|
||||
using addr_t = typename traits<tgc_c>::addr_t;
|
||||
|
||||
tgc_c();
|
||||
~tgc_c();
|
||||
|
||||
void reset(uint64_t address=0) override;
|
||||
|
||||
uint8_t* get_regs_base_ptr() override;
|
||||
/// deprecated
|
||||
void get_reg(short idx, std::vector<uint8_t>& value) override {}
|
||||
void set_reg(short idx, const std::vector<uint8_t>& value) override {}
|
||||
/// deprecated
|
||||
bool get_flag(int flag) override {return false;}
|
||||
void set_flag(int, bool value) override {};
|
||||
/// deprecated
|
||||
void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {};
|
||||
|
||||
inline uint64_t get_icount() { return reg.icount; }
|
||||
|
||||
inline bool should_stop() { return interrupt_sim; }
|
||||
|
||||
inline uint64_t stop_code() { return interrupt_sim; }
|
||||
|
||||
inline phys_addr_t v2p(const iss::addr_t& addr){
|
||||
if (addr.space != traits<tgc_c>::MEM || addr.type == iss::address_type::PHYSICAL ||
|
||||
addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL) {
|
||||
return phys_addr_t(addr.access, addr.space, addr.val&traits<tgc_c>::addr_mask);
|
||||
} else
|
||||
return virt2phys(addr);
|
||||
}
|
||||
|
||||
virtual phys_addr_t virt2phys(const iss::addr_t& addr);
|
||||
|
||||
virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
|
||||
|
||||
inline uint32_t get_last_branch() { return reg.last_branch; }
|
||||
|
||||
protected:
|
||||
#pragma pack(push, 1)
|
||||
struct TGC_C_regs {
|
||||
uint32_t X0 = 0;
|
||||
uint32_t X1 = 0;
|
||||
uint32_t X2 = 0;
|
||||
uint32_t X3 = 0;
|
||||
uint32_t X4 = 0;
|
||||
uint32_t X5 = 0;
|
||||
uint32_t X6 = 0;
|
||||
uint32_t X7 = 0;
|
||||
uint32_t X8 = 0;
|
||||
uint32_t X9 = 0;
|
||||
uint32_t X10 = 0;
|
||||
uint32_t X11 = 0;
|
||||
uint32_t X12 = 0;
|
||||
uint32_t X13 = 0;
|
||||
uint32_t X14 = 0;
|
||||
uint32_t X15 = 0;
|
||||
uint32_t X16 = 0;
|
||||
uint32_t X17 = 0;
|
||||
uint32_t X18 = 0;
|
||||
uint32_t X19 = 0;
|
||||
uint32_t X20 = 0;
|
||||
uint32_t X21 = 0;
|
||||
uint32_t X22 = 0;
|
||||
uint32_t X23 = 0;
|
||||
uint32_t X24 = 0;
|
||||
uint32_t X25 = 0;
|
||||
uint32_t X26 = 0;
|
||||
uint32_t X27 = 0;
|
||||
uint32_t X28 = 0;
|
||||
uint32_t X29 = 0;
|
||||
uint32_t X30 = 0;
|
||||
uint32_t X31 = 0;
|
||||
uint32_t PC = 0;
|
||||
uint32_t NEXT_PC = 0;
|
||||
uint8_t PRIV = 0;
|
||||
uint32_t trap_state = 0, pending_trap = 0;
|
||||
uint64_t icount = 0;
|
||||
uint32_t last_branch;
|
||||
} reg;
|
||||
#pragma pack(pop)
|
||||
std::array<address_type, 4> addr_mode;
|
||||
|
||||
uint64_t interrupt_sim=0;
|
||||
|
||||
uint32_t get_fcsr(){return 0;}
|
||||
void set_fcsr(uint32_t val){}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif /* _TGC_C_H_ */
|
@ -1,252 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
#ifndef _TGF_B_H_
|
||||
#define _TGF_B_H_
|
||||
|
||||
#include <array>
|
||||
#include <iss/arch/traits.h>
|
||||
#include <iss/arch_if.h>
|
||||
#include <iss/vm_if.h>
|
||||
|
||||
namespace iss {
|
||||
namespace arch {
|
||||
|
||||
struct tgf_b;
|
||||
|
||||
template <> struct traits<tgf_b> {
|
||||
|
||||
constexpr static char const* const core_type = "TGF_B";
|
||||
|
||||
static constexpr std::array<const char*, 33> 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"}};
|
||||
|
||||
static constexpr std::array<const char*, 33> 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"}};
|
||||
|
||||
enum constants {XLEN=32, PCLEN=32, MISA_VAL=0b1000000000000000000000100000000, PGSIZE=0x1000, PGMASK=0xfff};
|
||||
|
||||
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,
|
||||
NUM_REGS,
|
||||
NEXT_PC=NUM_REGS,
|
||||
TRAP_STATE,
|
||||
PENDING_TRAP,
|
||||
MACHINE_STATE,
|
||||
LAST_BRANCH,
|
||||
ICOUNT,
|
||||
ZERO = X0,
|
||||
RA = X1,
|
||||
SP = X2,
|
||||
GP = X3,
|
||||
TP = X4,
|
||||
T0 = X5,
|
||||
T1 = X6,
|
||||
T2 = X7,
|
||||
S0 = X8,
|
||||
S1 = X9,
|
||||
A0 = X10,
|
||||
A1 = X11,
|
||||
A2 = X12,
|
||||
A3 = X13,
|
||||
A4 = X14,
|
||||
A5 = X15,
|
||||
A6 = X16,
|
||||
A7 = X17,
|
||||
S2 = X18,
|
||||
S3 = X19,
|
||||
S4 = X20,
|
||||
S5 = X21,
|
||||
S6 = X22,
|
||||
S7 = X23,
|
||||
S8 = X24,
|
||||
S9 = X25,
|
||||
S10 = X26,
|
||||
S11 = X27,
|
||||
T3 = X28,
|
||||
T4 = X29,
|
||||
T5 = X30,
|
||||
T6 = X31
|
||||
};
|
||||
|
||||
using reg_t = uint32_t;
|
||||
|
||||
using addr_t = uint32_t;
|
||||
|
||||
using code_word_t = uint32_t; //TODO: check removal
|
||||
|
||||
using virt_addr_t = iss::typed_addr_t<iss::address_type::VIRTUAL>;
|
||||
|
||||
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
|
||||
|
||||
static constexpr std::array<const uint32_t, 39> 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,32,32,32,32,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,140,144,148,152,160}};
|
||||
|
||||
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
|
||||
|
||||
enum sreg_flag_e { FLAGS };
|
||||
|
||||
enum mem_type_e { MEM, CSR, FENCE, RES };
|
||||
};
|
||||
|
||||
struct tgf_b: public arch_if {
|
||||
|
||||
using virt_addr_t = typename traits<tgf_b>::virt_addr_t;
|
||||
using phys_addr_t = typename traits<tgf_b>::phys_addr_t;
|
||||
using reg_t = typename traits<tgf_b>::reg_t;
|
||||
using addr_t = typename traits<tgf_b>::addr_t;
|
||||
|
||||
tgf_b();
|
||||
~tgf_b();
|
||||
|
||||
void reset(uint64_t address=0) override;
|
||||
|
||||
uint8_t* get_regs_base_ptr() override;
|
||||
/// deprecated
|
||||
void get_reg(short idx, std::vector<uint8_t>& value) override {}
|
||||
void set_reg(short idx, const std::vector<uint8_t>& value) override {}
|
||||
/// deprecated
|
||||
bool get_flag(int flag) override {return false;}
|
||||
void set_flag(int, bool value) override {};
|
||||
/// deprecated
|
||||
void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {};
|
||||
|
||||
inline uint64_t get_icount() { return reg.icount; }
|
||||
|
||||
inline bool should_stop() { return interrupt_sim; }
|
||||
|
||||
inline uint64_t stop_code() { return interrupt_sim; }
|
||||
|
||||
inline phys_addr_t v2p(const iss::addr_t& addr){
|
||||
if (addr.space != traits<tgf_b>::MEM || addr.type == iss::address_type::PHYSICAL ||
|
||||
addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL) {
|
||||
return phys_addr_t(addr.access, addr.space, addr.val&traits<tgf_b>::addr_mask);
|
||||
} else
|
||||
return virt2phys(addr);
|
||||
}
|
||||
|
||||
virtual phys_addr_t virt2phys(const iss::addr_t& addr);
|
||||
|
||||
virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
|
||||
|
||||
inline uint32_t get_last_branch() { return reg.last_branch; }
|
||||
|
||||
protected:
|
||||
struct TGF_B_regs {
|
||||
uint32_t X0 = 0;
|
||||
uint32_t X1 = 0;
|
||||
uint32_t X2 = 0;
|
||||
uint32_t X3 = 0;
|
||||
uint32_t X4 = 0;
|
||||
uint32_t X5 = 0;
|
||||
uint32_t X6 = 0;
|
||||
uint32_t X7 = 0;
|
||||
uint32_t X8 = 0;
|
||||
uint32_t X9 = 0;
|
||||
uint32_t X10 = 0;
|
||||
uint32_t X11 = 0;
|
||||
uint32_t X12 = 0;
|
||||
uint32_t X13 = 0;
|
||||
uint32_t X14 = 0;
|
||||
uint32_t X15 = 0;
|
||||
uint32_t X16 = 0;
|
||||
uint32_t X17 = 0;
|
||||
uint32_t X18 = 0;
|
||||
uint32_t X19 = 0;
|
||||
uint32_t X20 = 0;
|
||||
uint32_t X21 = 0;
|
||||
uint32_t X22 = 0;
|
||||
uint32_t X23 = 0;
|
||||
uint32_t X24 = 0;
|
||||
uint32_t X25 = 0;
|
||||
uint32_t X26 = 0;
|
||||
uint32_t X27 = 0;
|
||||
uint32_t X28 = 0;
|
||||
uint32_t X29 = 0;
|
||||
uint32_t X30 = 0;
|
||||
uint32_t X31 = 0;
|
||||
uint32_t PC = 0;
|
||||
uint32_t NEXT_PC = 0;
|
||||
uint32_t trap_state = 0, pending_trap = 0, machine_state = 0, last_branch = 0;
|
||||
uint64_t icount = 0;
|
||||
} reg;
|
||||
|
||||
std::array<address_type, 4> addr_mode;
|
||||
|
||||
uint64_t interrupt_sim=0;
|
||||
|
||||
uint32_t get_fcsr(){return 0;}
|
||||
void set_fcsr(uint32_t val){}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif /* _TGF_B_H_ */
|
@ -1,252 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
#ifndef _TGF_C_H_
|
||||
#define _TGF_C_H_
|
||||
|
||||
#include <array>
|
||||
#include <iss/arch/traits.h>
|
||||
#include <iss/arch_if.h>
|
||||
#include <iss/vm_if.h>
|
||||
|
||||
namespace iss {
|
||||
namespace arch {
|
||||
|
||||
struct tgf_c;
|
||||
|
||||
template <> struct traits<tgf_c> {
|
||||
|
||||
constexpr static char const* const core_type = "TGF_C";
|
||||
|
||||
static constexpr std::array<const char*, 33> 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"}};
|
||||
|
||||
static constexpr std::array<const char*, 33> 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"}};
|
||||
|
||||
enum constants {XLEN=32, PCLEN=32, MUL_LEN=64, MISA_VAL=0b1000000000000000001000100000100, PGSIZE=0x1000, PGMASK=0xfff};
|
||||
|
||||
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,
|
||||
NUM_REGS,
|
||||
NEXT_PC=NUM_REGS,
|
||||
TRAP_STATE,
|
||||
PENDING_TRAP,
|
||||
MACHINE_STATE,
|
||||
LAST_BRANCH,
|
||||
ICOUNT,
|
||||
ZERO = X0,
|
||||
RA = X1,
|
||||
SP = X2,
|
||||
GP = X3,
|
||||
TP = X4,
|
||||
T0 = X5,
|
||||
T1 = X6,
|
||||
T2 = X7,
|
||||
S0 = X8,
|
||||
S1 = X9,
|
||||
A0 = X10,
|
||||
A1 = X11,
|
||||
A2 = X12,
|
||||
A3 = X13,
|
||||
A4 = X14,
|
||||
A5 = X15,
|
||||
A6 = X16,
|
||||
A7 = X17,
|
||||
S2 = X18,
|
||||
S3 = X19,
|
||||
S4 = X20,
|
||||
S5 = X21,
|
||||
S6 = X22,
|
||||
S7 = X23,
|
||||
S8 = X24,
|
||||
S9 = X25,
|
||||
S10 = X26,
|
||||
S11 = X27,
|
||||
T3 = X28,
|
||||
T4 = X29,
|
||||
T5 = X30,
|
||||
T6 = X31
|
||||
};
|
||||
|
||||
using reg_t = uint32_t;
|
||||
|
||||
using addr_t = uint32_t;
|
||||
|
||||
using code_word_t = uint32_t; //TODO: check removal
|
||||
|
||||
using virt_addr_t = iss::typed_addr_t<iss::address_type::VIRTUAL>;
|
||||
|
||||
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
|
||||
|
||||
static constexpr std::array<const uint32_t, 39> 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,32,32,32,32,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,140,144,148,152,160}};
|
||||
|
||||
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
|
||||
|
||||
enum sreg_flag_e { FLAGS };
|
||||
|
||||
enum mem_type_e { MEM, CSR, FENCE, RES };
|
||||
};
|
||||
|
||||
struct tgf_c: public arch_if {
|
||||
|
||||
using virt_addr_t = typename traits<tgf_c>::virt_addr_t;
|
||||
using phys_addr_t = typename traits<tgf_c>::phys_addr_t;
|
||||
using reg_t = typename traits<tgf_c>::reg_t;
|
||||
using addr_t = typename traits<tgf_c>::addr_t;
|
||||
|
||||
tgf_c();
|
||||
~tgf_c();
|
||||
|
||||
void reset(uint64_t address=0) override;
|
||||
|
||||
uint8_t* get_regs_base_ptr() override;
|
||||
/// deprecated
|
||||
void get_reg(short idx, std::vector<uint8_t>& value) override {}
|
||||
void set_reg(short idx, const std::vector<uint8_t>& value) override {}
|
||||
/// deprecated
|
||||
bool get_flag(int flag) override {return false;}
|
||||
void set_flag(int, bool value) override {};
|
||||
/// deprecated
|
||||
void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {};
|
||||
|
||||
inline uint64_t get_icount() { return reg.icount; }
|
||||
|
||||
inline bool should_stop() { return interrupt_sim; }
|
||||
|
||||
inline uint64_t stop_code() { return interrupt_sim; }
|
||||
|
||||
inline phys_addr_t v2p(const iss::addr_t& addr){
|
||||
if (addr.space != traits<tgf_c>::MEM || addr.type == iss::address_type::PHYSICAL ||
|
||||
addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL) {
|
||||
return phys_addr_t(addr.access, addr.space, addr.val&traits<tgf_c>::addr_mask);
|
||||
} else
|
||||
return virt2phys(addr);
|
||||
}
|
||||
|
||||
virtual phys_addr_t virt2phys(const iss::addr_t& addr);
|
||||
|
||||
virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
|
||||
|
||||
inline uint32_t get_last_branch() { return reg.last_branch; }
|
||||
|
||||
protected:
|
||||
struct TGF_C_regs {
|
||||
uint32_t X0 = 0;
|
||||
uint32_t X1 = 0;
|
||||
uint32_t X2 = 0;
|
||||
uint32_t X3 = 0;
|
||||
uint32_t X4 = 0;
|
||||
uint32_t X5 = 0;
|
||||
uint32_t X6 = 0;
|
||||
uint32_t X7 = 0;
|
||||
uint32_t X8 = 0;
|
||||
uint32_t X9 = 0;
|
||||
uint32_t X10 = 0;
|
||||
uint32_t X11 = 0;
|
||||
uint32_t X12 = 0;
|
||||
uint32_t X13 = 0;
|
||||
uint32_t X14 = 0;
|
||||
uint32_t X15 = 0;
|
||||
uint32_t X16 = 0;
|
||||
uint32_t X17 = 0;
|
||||
uint32_t X18 = 0;
|
||||
uint32_t X19 = 0;
|
||||
uint32_t X20 = 0;
|
||||
uint32_t X21 = 0;
|
||||
uint32_t X22 = 0;
|
||||
uint32_t X23 = 0;
|
||||
uint32_t X24 = 0;
|
||||
uint32_t X25 = 0;
|
||||
uint32_t X26 = 0;
|
||||
uint32_t X27 = 0;
|
||||
uint32_t X28 = 0;
|
||||
uint32_t X29 = 0;
|
||||
uint32_t X30 = 0;
|
||||
uint32_t X31 = 0;
|
||||
uint32_t PC = 0;
|
||||
uint32_t NEXT_PC = 0;
|
||||
uint32_t trap_state = 0, pending_trap = 0, machine_state = 0, last_branch = 0;
|
||||
uint64_t icount = 0;
|
||||
} reg;
|
||||
|
||||
std::array<address_type, 4> addr_mode;
|
||||
|
||||
uint64_t interrupt_sim=0;
|
||||
|
||||
uint32_t get_fcsr(){return 0;}
|
||||
void set_fcsr(uint32_t val){}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif /* _TGF_C_H_ */
|
@ -183,7 +183,8 @@ status riscv_target_adapter<ARCH>::read_registers(std::vector<uint8_t> &data, st
|
||||
data.clear();
|
||||
avail.clear();
|
||||
const uint8_t *reg_base = core->get_regs_base_ptr();
|
||||
for (size_t reg_no = 0; reg_no < arch::traits<ARCH>::NUM_REGS; ++reg_no) {
|
||||
auto start_reg=arch::traits<ARCH>::X0;
|
||||
for (size_t reg_no = start_reg; reg_no < start_reg+33/*arch::traits<ARCH>::NUM_REGS*/; ++reg_no) {
|
||||
auto reg_width = arch::traits<ARCH>::reg_bit_widths[reg_no] / 8;
|
||||
unsigned offset = traits<ARCH>::reg_byte_offsets[reg_no];
|
||||
for (size_t j = 0; j < reg_width; ++j) {
|
||||
@ -210,11 +211,11 @@ status riscv_target_adapter<ARCH>::read_registers(std::vector<uint8_t> &data, st
|
||||
}
|
||||
|
||||
template <typename ARCH> status riscv_target_adapter<ARCH>::write_registers(const std::vector<uint8_t> &data) {
|
||||
auto reg_count = arch::traits<ARCH>::NUM_REGS;
|
||||
auto start_reg=arch::traits<ARCH>::X0;
|
||||
auto *reg_base = core->get_regs_base_ptr();
|
||||
auto iter = data.data();
|
||||
for (size_t reg_no = 0; reg_no < reg_count; ++reg_no) {
|
||||
auto reg_width = arch::traits<ARCH>::reg_bit_widths[static_cast<typename arch::traits<ARCH>::reg_e>(reg_no)] / 8;
|
||||
for (size_t reg_no = 0; reg_no < start_reg+33/*arch::traits<ARCH>::NUM_REGS*/; ++reg_no) {
|
||||
auto reg_width = arch::traits<ARCH>::reg_bit_widths[reg_no] / 8;
|
||||
auto offset = traits<ARCH>::reg_byte_offsets[reg_no];
|
||||
std::copy(iter, iter + reg_width, reg_base);
|
||||
iter += 4;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
|
||||
* Copyright (C) 2021 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -29,41 +29,34 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#include "util/ities.h"
|
||||
#include <util/logging.h>
|
||||
#include <iss/arch/tgf_c.h>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
|
||||
using namespace iss::arch;
|
||||
#ifndef _ISS_FACTORY_H_
|
||||
#define _ISS_FACTORY_H_
|
||||
|
||||
constexpr std::array<const char*, 33> iss::arch::traits<iss::arch::tgf_c>::reg_names;
|
||||
constexpr std::array<const char*, 33> iss::arch::traits<iss::arch::tgf_c>::reg_aliases;
|
||||
constexpr std::array<const uint32_t, 39> iss::arch::traits<iss::arch::tgf_c>::reg_bit_widths;
|
||||
constexpr std::array<const uint32_t, 40> iss::arch::traits<iss::arch::tgf_c>::reg_byte_offsets;
|
||||
#include <iss/iss.h>
|
||||
|
||||
tgf_c::tgf_c() {
|
||||
reg.icount = 0;
|
||||
namespace iss {
|
||||
|
||||
using cpu_ptr = std::unique_ptr<iss::arch_if>;
|
||||
using vm_ptr= std::unique_ptr<iss::vm_if>;
|
||||
|
||||
template<typename PLAT>
|
||||
std::tuple<cpu_ptr, vm_ptr> create_cpu(std::string const& backend, unsigned gdb_port){
|
||||
using core_type = typename PLAT::super;
|
||||
core_type* lcpu = new PLAT();
|
||||
if(backend == "interp")
|
||||
return {cpu_ptr{lcpu}, vm_ptr{iss::interp::create(lcpu, gdb_port)}};
|
||||
#ifdef WITH_LLVM
|
||||
if(backend == "llvm")
|
||||
return {cpu_ptr{lcpu}, vm_ptr{iss::llvm::create(lcpu, gdb_port)}};
|
||||
#endif
|
||||
#ifdef WITH_LLVM
|
||||
if(backend == "tcc")
|
||||
return {cpu_ptr{lcpu}, vm_ptr{iss::tcc::create(lcpu, gdb_port)}};
|
||||
#endif
|
||||
return {nullptr, nullptr};
|
||||
}
|
||||
|
||||
tgf_c::~tgf_c() = default;
|
||||
|
||||
void tgf_c::reset(uint64_t address) {
|
||||
for(size_t i=0; i<traits<tgf_c>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<tgf_c>::reg_t),0));
|
||||
reg.PC=address;
|
||||
reg.NEXT_PC=reg.PC;
|
||||
reg.trap_state=0;
|
||||
reg.machine_state=0x3;
|
||||
reg.icount=0;
|
||||
}
|
||||
|
||||
uint8_t *tgf_c::get_regs_base_ptr() {
|
||||
return reinterpret_cast<uint8_t*>(®);
|
||||
}
|
||||
|
||||
tgf_c::phys_addr_t tgf_c::virt2phys(const iss::addr_t &pc) {
|
||||
return phys_addr_t(pc); // change logical address to physical address
|
||||
}
|
||||
|
||||
#endif /* _ISS_FACTORY_H_ */
|
@ -76,7 +76,7 @@ public:
|
||||
|
||||
sync_type get_sync() override { return POST_SYNC; };
|
||||
|
||||
void callback(instr_info_t instr_info) override;
|
||||
void callback(instr_info_t instr_info, exec_info const&) override;
|
||||
|
||||
private:
|
||||
iss::instrumentation_if *arch_instr;
|
||||
|
@ -69,7 +69,7 @@ public:
|
||||
|
||||
sync_type get_sync() override { return POST_SYNC; };
|
||||
|
||||
void callback(instr_info_t instr_info) override;
|
||||
void callback(instr_info_t, exec_info const&) override;
|
||||
|
||||
private:
|
||||
Json::Value root;
|
||||
|
@ -36,7 +36,7 @@
|
||||
#include "tlm/scc/initiator_mixin.h"
|
||||
#include "scc/traceable.h"
|
||||
#include "scc/utilities.h"
|
||||
#include "tlm/scc/scv4tlm/tlm_rec_initiator_socket.h"
|
||||
#include "tlm/scc/scv/tlm_rec_initiator_socket.h"
|
||||
#include <cci_configuration>
|
||||
#include <tlm>
|
||||
#include <tlm_core/tlm_1/tlm_req_rsp/tlm_1_interfaces/tlm_core_ifs.h>
|
||||
@ -48,16 +48,6 @@ class scv_tr_stream;
|
||||
struct _scv_tr_generator_default_data;
|
||||
template <class T_begin, class T_end> class scv_tr_generator;
|
||||
|
||||
namespace iss {
|
||||
class vm_if;
|
||||
namespace arch {
|
||||
template <typename BASE> class riscv_hart_m_p;
|
||||
}
|
||||
namespace debugger {
|
||||
class target_adapter_if;
|
||||
}
|
||||
} // namespace iss
|
||||
|
||||
namespace sysc {
|
||||
|
||||
class tlm_dmi_ext : public tlm::tlm_dmi {
|
||||
@ -70,12 +60,12 @@ public:
|
||||
bool operator!=(const tlm_dmi_ext &o) const { return !operator==(o); }
|
||||
};
|
||||
|
||||
namespace SiFive {
|
||||
namespace tgfs {
|
||||
class core_wrapper;
|
||||
|
||||
class core_complex : public sc_core::sc_module, public scc::traceable {
|
||||
public:
|
||||
tlm::scc::initiator_mixin<scv4tlm::tlm_rec_initiator_socket<32>> initiator{"intor"};
|
||||
tlm::scc::initiator_mixin<tlm::scc::scv::tlm_rec_initiator_socket<32>> initiator{"intor"};
|
||||
|
||||
sc_core::sc_in<sc_core::sc_time> clk_i{"clk_i"};
|
||||
|
||||
@ -97,7 +87,9 @@ public:
|
||||
|
||||
cci::cci_param<uint64_t> reset_address{"reset_address", 0ULL};
|
||||
|
||||
cci::cci_param<std::string> backend{"backend", "tcc"};
|
||||
cci::cci_param<std::string> core_type{"core_type", "tgc_c"};
|
||||
|
||||
cci::cci_param<std::string> backend{"backend", "interp"};
|
||||
|
||||
cci::cci_param<unsigned short> gdb_server_port{"gdb_server_port", 0};
|
||||
|
||||
@ -145,9 +137,7 @@ protected:
|
||||
tlm_utils::tlm_quantumkeeper quantum_keeper;
|
||||
std::vector<uint8_t> write_buf;
|
||||
std::unique_ptr<core_wrapper> cpu;
|
||||
std::unique_ptr<iss::vm_if> vm;
|
||||
sc_core::sc_time curr_clk;
|
||||
iss::debugger::target_adapter_if *tgt_adapter;
|
||||
#ifdef WITH_SCV
|
||||
//! transaction recording database
|
||||
scv_tr_db *m_db;
|
||||
|
1
src/iss/.gitignore
vendored
Normal file
1
src/iss/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/tgc_*.cpp
|
@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
|
||||
* Copyright (C) 2017 - 2020 MINRES Technologies GmbH
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -29,41 +29,41 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
#include "util/ities.h"
|
||||
#include <util/logging.h>
|
||||
#include <iss/arch/tgf_b.h>
|
||||
#include <iss/arch/tgc_c.h>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
|
||||
using namespace iss::arch;
|
||||
|
||||
constexpr std::array<const char*, 33> iss::arch::traits<iss::arch::tgf_b>::reg_names;
|
||||
constexpr std::array<const char*, 33> iss::arch::traits<iss::arch::tgf_b>::reg_aliases;
|
||||
constexpr std::array<const uint32_t, 39> iss::arch::traits<iss::arch::tgf_b>::reg_bit_widths;
|
||||
constexpr std::array<const uint32_t, 40> iss::arch::traits<iss::arch::tgf_b>::reg_byte_offsets;
|
||||
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, 38> iss::arch::traits<iss::arch::tgc_c>::reg_bit_widths;
|
||||
constexpr std::array<const uint32_t, 38> iss::arch::traits<iss::arch::tgc_c>::reg_byte_offsets;
|
||||
|
||||
tgf_b::tgf_b() {
|
||||
tgc_c::tgc_c() {
|
||||
reg.icount = 0;
|
||||
}
|
||||
|
||||
tgf_b::~tgf_b() = default;
|
||||
tgc_c::~tgc_c() = default;
|
||||
|
||||
void tgf_b::reset(uint64_t address) {
|
||||
for(size_t i=0; i<traits<tgf_b>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<tgf_b>::reg_t),0));
|
||||
void tgc_c::reset(uint64_t address) {
|
||||
for(size_t i=0; i<traits<tgc_c>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<tgc_c>::reg_t),0));
|
||||
reg.PC=address;
|
||||
reg.NEXT_PC=reg.PC;
|
||||
reg.PRIV=0x3;
|
||||
reg.trap_state=0;
|
||||
reg.machine_state=0x3;
|
||||
reg.icount=0;
|
||||
}
|
||||
|
||||
uint8_t *tgf_b::get_regs_base_ptr() {
|
||||
uint8_t *tgc_c::get_regs_base_ptr() {
|
||||
return reinterpret_cast<uint8_t*>(®);
|
||||
}
|
||||
|
||||
tgf_b::phys_addr_t tgf_b::virt2phys(const iss::addr_t &pc) {
|
||||
tgc_c::phys_addr_t tgc_c::virt2phys(const iss::addr_t &pc) {
|
||||
return phys_addr_t(pc); // change logical address to physical address
|
||||
}
|
||||
|
60
src/main.cpp
60
src/main.cpp
@ -31,13 +31,24 @@
|
||||
*******************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <iss/iss.h>
|
||||
#include <iss/factory.h>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <iss/arch/riscv_hart_m_p.h>
|
||||
#include <iss/arch/tgf_b.h>
|
||||
#include <iss/arch/tgf_c.h>
|
||||
#include "iss/arch/riscv_hart_m_p.h"
|
||||
#include "iss/arch/tgc_c.h"
|
||||
using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>;
|
||||
#ifdef CORE_TGC_B
|
||||
#include "iss/arch/riscv_hart_m_p.h"
|
||||
#include "iss/arch/tgc_b.h"
|
||||
using tgc_b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_b>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_D
|
||||
#include "iss/arch/riscv_hart_mu_p.h"
|
||||
#include "iss/arch/tgc_d.h"
|
||||
using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d, iss::arch::FEAT_PMP>;
|
||||
#endif
|
||||
#ifdef WITH_LLVM
|
||||
#include <iss/llvm/jit_helper.h>
|
||||
#endif
|
||||
@ -47,23 +58,6 @@
|
||||
|
||||
namespace po = boost::program_options;
|
||||
|
||||
using cpu_ptr = std::unique_ptr<iss::arch_if>;
|
||||
using vm_ptr= std::unique_ptr<iss::vm_if>;
|
||||
|
||||
template<typename CORE>
|
||||
std::tuple<cpu_ptr, vm_ptr> create_cpu(std::string const& backend, unsigned gdb_port){
|
||||
CORE* lcpu = new iss::arch::riscv_hart_m_p<CORE>();
|
||||
if(backend == "interp")
|
||||
return {cpu_ptr{lcpu}, vm_ptr{iss::interp::create(lcpu, gdb_port)}};
|
||||
#ifdef WITH_LLVM
|
||||
if(backend == "llvm")
|
||||
return {cpu_ptr{lcpu}, vm_ptr{iss::llvm::create(lcpu, gdb_port)}};
|
||||
#endif
|
||||
if(backend == "tcc")
|
||||
return {cpu_ptr{lcpu}, vm_ptr{iss::tcc::create(lcpu, gdb_port)}};
|
||||
return {nullptr, nullptr};
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
/*
|
||||
* Define and parse the program options
|
||||
@ -83,7 +77,7 @@ int main(int argc, char *argv[]) {
|
||||
("elf", po::value<std::vector<std::string>>(), "ELF file(s) to load")
|
||||
("mem,m", po::value<std::string>(), "the memory input file")
|
||||
("plugin,p", po::value<std::vector<std::string>>(), "plugin to activate")
|
||||
("backend", po::value<std::string>()->default_value("tcc"), "the memory input file")
|
||||
("backend", po::value<std::string>()->default_value("interp"), "the memory input file")
|
||||
("isa", po::value<std::string>()->default_value("tgf_c"), "isa to use for simulation");
|
||||
// clang-format on
|
||||
auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
|
||||
@ -126,16 +120,26 @@ int main(int argc, char *argv[]) {
|
||||
#endif
|
||||
bool dump = clim.count("dump-ir");
|
||||
// instantiate the simulator
|
||||
vm_ptr vm{nullptr};
|
||||
cpu_ptr cpu{nullptr};
|
||||
iss::vm_ptr vm{nullptr};
|
||||
iss::cpu_ptr cpu{nullptr};
|
||||
std::string isa_opt(clim["isa"].as<std::string>());
|
||||
if (isa_opt == "tgf_c") {
|
||||
std::tie(cpu, vm) =
|
||||
iss::create_cpu<tgc_c_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
} else
|
||||
#ifdef CORE_TGC_B
|
||||
if (isa_opt == "tgf_b") {
|
||||
std::tie(cpu, vm) =
|
||||
create_cpu<iss::arch::tgf_b>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
} else if (isa_opt == "tgf_c") {
|
||||
iss::create_cpu<tgc_b_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
} else
|
||||
#endif
|
||||
#ifdef CORE_TGC_D
|
||||
if (isa_opt == "tgf_d") {
|
||||
std::tie(cpu, vm) =
|
||||
create_cpu<iss::arch::tgf_c>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
} else {
|
||||
iss::create_cpu<tgc_d_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
LOG(ERROR) << "Illegal argument value for '--isa': " << clim["isa"].as<std::string>() << std::endl;
|
||||
return 127;
|
||||
}
|
||||
@ -174,7 +178,7 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
uint64_t start_address = 0;
|
||||
if (clim.count("mem"))
|
||||
vm->get_arch()->load_file(clim["mem"].as<std::string>(), iss::arch::traits<iss::arch::tgf_b>::MEM);
|
||||
vm->get_arch()->load_file(clim["mem"].as<std::string>());
|
||||
if (clim.count("elf"))
|
||||
for (std::string input : clim["elf"].as<std::vector<std::string>>()) {
|
||||
auto start_addr = vm->get_arch()->load_file(input);
|
||||
|
@ -83,7 +83,7 @@ bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if&
|
||||
|
||||
}
|
||||
|
||||
void iss::plugin::cycle_estimate::callback(instr_info_t instr_info) {
|
||||
void iss::plugin::cycle_estimate::callback(instr_info_t instr_info, exec_info const&) {
|
||||
assert(arch_instr && "No instrumentation interface available but callback executed");
|
||||
auto entry = delays[instr_info.instr_id];
|
||||
bool taken = (arch_instr->get_next_pc()-arch_instr->get_pc()) != (entry.size/8);
|
||||
|
@ -90,6 +90,6 @@ bool iss::plugin::instruction_count::registration(const char* const version, vm_
|
||||
return true;
|
||||
}
|
||||
|
||||
void iss::plugin::instruction_count::callback(instr_info_t instr_info) {
|
||||
void iss::plugin::instruction_count::callback(instr_info_t instr_info, exec_info const&) {
|
||||
rep_counts[instr_info.instr_id]++;
|
||||
}
|
||||
|
@ -31,8 +31,21 @@
|
||||
*******************************************************************************/
|
||||
|
||||
#include "sysc/core_complex.h"
|
||||
#ifdef CORE_TGC_B
|
||||
#include "iss/arch/riscv_hart_m_p.h"
|
||||
#include "iss/arch/tgf_c.h"
|
||||
#include "iss/arch/tgc_b.h"
|
||||
using tgc_b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_b>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_C
|
||||
#include "iss/arch/riscv_hart_m_p.h"
|
||||
#include "iss/arch/tgc_c.h"
|
||||
using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>;
|
||||
#endif
|
||||
#ifdef CORE_TGC_D
|
||||
#include "iss/arch/riscv_hart_mu_p.h"
|
||||
#include "iss/arch/tgc_d.h"
|
||||
using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d, iss::arch::FEAT_PMP>;
|
||||
#endif
|
||||
#include "iss/debugger/encoderdecoder.h"
|
||||
#include "iss/debugger/gdb_session.h"
|
||||
#include "iss/debugger/server.h"
|
||||
@ -43,13 +56,17 @@
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#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
|
||||
#include <array>
|
||||
#include <scv.h>
|
||||
#endif
|
||||
|
||||
namespace sysc {
|
||||
namespace SiFive {
|
||||
namespace tgfs {
|
||||
using namespace std;
|
||||
using namespace iss;
|
||||
using namespace logging;
|
||||
@ -57,55 +74,29 @@ using namespace sc_core;
|
||||
|
||||
namespace {
|
||||
iss::debugger::encoder_decoder encdec;
|
||||
}
|
||||
|
||||
using core_type = iss::arch::tgf_c;
|
||||
|
||||
namespace {
|
||||
|
||||
std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
|
||||
|
||||
std::array<const char*, 16> trap_str = { {
|
||||
"Instruction address misaligned",
|
||||
"Instruction access fault",
|
||||
"Illegal instruction",
|
||||
"Breakpoint",
|
||||
"Load address misaligned",
|
||||
"Load access fault",
|
||||
"Store/AMO address misaligned",
|
||||
"Store/AMO access fault",
|
||||
"Environment call from U-mode",
|
||||
"Environment call from S-mode",
|
||||
"Reserved",
|
||||
"Environment call from M-mode",
|
||||
"Instruction page fault",
|
||||
"Load page fault",
|
||||
"Reserved",
|
||||
"Store/AMO page fault"
|
||||
} };
|
||||
std::array<const char*, 12> irq_str = { {
|
||||
"User software interrupt", "Supervisor software interrupt", "Reserved", "Machine software interrupt",
|
||||
"User timer interrupt", "Supervisor timer interrupt", "Reserved", "Machine timer interrupt",
|
||||
"User external interrupt", "Supervisor external interrupt", "Reserved", "Machine external interrupt" } };
|
||||
}
|
||||
|
||||
class core_wrapper : public iss::arch::riscv_hart_m_p<core_type> {
|
||||
template<typename PLAT>
|
||||
class core_wrapper_t : public PLAT {
|
||||
public:
|
||||
using base_type = arch::riscv_hart_m_p<core_type>;
|
||||
using phys_addr_t = typename arch::traits<core_type>::phys_addr_t;
|
||||
core_wrapper(core_complex *owner)
|
||||
using reg_t = typename arch::traits<typename PLAT::super>::reg_t;
|
||||
using phys_addr_t = typename arch::traits<typename PLAT::super>::phys_addr_t;
|
||||
using heart_state_t = typename PLAT::hart_state_type;
|
||||
core_wrapper_t(core_complex *owner)
|
||||
: owner(owner) { }
|
||||
|
||||
uint32_t get_mode() { return this->reg.machine_state; }
|
||||
uint32_t get_mode() { return this->reg.PRIV; }
|
||||
|
||||
inline void set_interrupt_execution(bool v) { this->interrupt_sim = v?1:0; }
|
||||
|
||||
inline bool get_interrupt_execution() { return this->interrupt_sim; }
|
||||
|
||||
base_type::hart_state<base_type::reg_t> &get_state() { return this->state; }
|
||||
heart_state_t &get_state() { return this->state; }
|
||||
|
||||
void notify_phase(exec_phase p) override {
|
||||
if (p == ISTART) owner->sync(this->reg.icount + cycle_offset);
|
||||
void notify_phase(iss::arch_if::exec_phase p) override {
|
||||
if (p == iss::arch_if::ISTART) owner->sync(this->reg.icount);
|
||||
}
|
||||
|
||||
sync_type needed_sync() const override { return PRE_SYNC; }
|
||||
@ -113,8 +104,8 @@ public:
|
||||
void disass_output(uint64_t pc, const std::string instr) override {
|
||||
if (INFO <= Log<Output2FILE<disass>>::reporting_level() && Output2FILE<disass>::stream()) {
|
||||
std::stringstream s;
|
||||
s << "[p:" << lvl[this->reg.machine_state] << ";s:0x" << std::hex << std::setfill('0')
|
||||
<< std::setw(sizeof(reg_t) * 2) << (reg_t)state.mstatus << std::dec << ";c:" << this->reg.icount << "]";
|
||||
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 << "]";
|
||||
Log<Output2FILE<disass>>().get(INFO, "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();
|
||||
@ -157,7 +148,7 @@ public:
|
||||
}
|
||||
return ret?Ok:Err;
|
||||
} else {
|
||||
return base_type::read_csr(addr, val);
|
||||
return PLAT::read_csr(addr, val);
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,11 +157,11 @@ public:
|
||||
do {
|
||||
wait(wfi_evt);
|
||||
} while (this->reg.pending_trap == 0);
|
||||
base_type::wait_until(flags);
|
||||
PLAT::wait_until(flags);
|
||||
}
|
||||
|
||||
void local_irq(short id, bool value) {
|
||||
base_type::reg_t mask = 0;
|
||||
reg_t mask = 0;
|
||||
switch (id) {
|
||||
case 16: // SW
|
||||
mask = 1 << 3;
|
||||
@ -191,6 +182,8 @@ public:
|
||||
} else
|
||||
this->csr[arch::mip] &= ~mask;
|
||||
this->check_interrupt();
|
||||
if(value)
|
||||
SCCTRACE(owner->name()) << "Triggering interrupt " << id << " Pending trap: " << this->reg.pending_trap;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -228,11 +221,76 @@ int cmd_sysc(int argc, char *argv[], debugger::out_func of, debugger::data_func
|
||||
return Err;
|
||||
}
|
||||
|
||||
using cpu_ptr = std::unique_ptr<iss::arch_if>;
|
||||
using vm_ptr= std::unique_ptr<iss::vm_if>;
|
||||
|
||||
class core_wrapper {
|
||||
public:
|
||||
core_wrapper(core_complex *owner) : owner(owner) { }
|
||||
|
||||
void reset(uint64_t addr){vm->reset(addr);}
|
||||
inline void start(){vm->start();}
|
||||
inline std::pair<uint64_t, bool> load_file(std::string const& name){ return cpu->load_file(name);};
|
||||
|
||||
std::function<unsigned(void)> get_mode;
|
||||
std::function<uint64_t(void)> get_state;
|
||||
std::function<bool(void)> get_interrupt_execution;
|
||||
std::function<void(bool)> set_interrupt_execution;
|
||||
std::function<void(short, bool)> local_irq;
|
||||
|
||||
template<typename PLAT>
|
||||
std::tuple<cpu_ptr, vm_ptr> create_core(std::string const& backend, unsigned gdb_port, uint32_t hart_id){
|
||||
auto* lcpu = new core_wrapper_t<PLAT>(owner);
|
||||
lcpu->set_mhartid(hart_id);
|
||||
get_mode = [lcpu]() { return lcpu->get_mode(); };
|
||||
get_state = [lcpu]() { return lcpu->get_state().mstatus.backing.val; };
|
||||
get_interrupt_execution = [lcpu]() { return lcpu->get_interrupt_execution(); };
|
||||
set_interrupt_execution = [lcpu](bool b) { return lcpu->set_interrupt_execution(b); };
|
||||
local_irq = [lcpu](short s, bool b) { return lcpu->local_irq(s, b); };
|
||||
if(backend == "interp")
|
||||
return {cpu_ptr{lcpu}, vm_ptr{iss::interp::create(lcpu, gdb_port)}};
|
||||
#ifdef WITH_LLVM
|
||||
if(backend == "llvm")
|
||||
return {cpu_ptr{lcpu}, vm_ptr{iss::llvm::create(lcpu, gdb_port)}};
|
||||
#endif
|
||||
#ifdef WITH_TCC
|
||||
if(backend == "tcc")
|
||||
s return {cpu_ptr{lcpu}, vm_ptr{iss::tcc::create(lcpu, gdb_port)}};
|
||||
#endif
|
||||
return {nullptr, nullptr};
|
||||
}
|
||||
|
||||
void create_cpu(std::string const& type, std::string const& backend, unsigned gdb_port, uint32_t hart_id){
|
||||
CREATE_CORE(tgc_c)
|
||||
#ifdef CORE_TGC_B
|
||||
CREATE_CORE(tgc_c)
|
||||
#endif
|
||||
#ifdef CORE_TGC_D
|
||||
CREATE_CORE(tgc_d)
|
||||
#endif
|
||||
{
|
||||
LOG(ERROR) << "Illegal argument value for core type: " << type << std::endl;
|
||||
}
|
||||
auto *srv = debugger::server<debugger::gdb_session>::get();
|
||||
if (srv) tgt_adapter = srv->get_target();
|
||||
if (tgt_adapter)
|
||||
tgt_adapter->add_custom_command(
|
||||
{"sysc", [this](int argc, char *argv[], debugger::out_func of,
|
||||
debugger::data_func df) -> int { return cmd_sysc(argc, argv, of, df, tgt_adapter); },
|
||||
"SystemC sub-commands: break <time>, print_time"});
|
||||
|
||||
}
|
||||
|
||||
core_complex * const owner;
|
||||
vm_ptr vm{nullptr};
|
||||
cpu_ptr cpu{nullptr};
|
||||
iss::debugger::target_adapter_if *tgt_adapter{nullptr};
|
||||
};
|
||||
|
||||
core_complex::core_complex(sc_module_name name)
|
||||
: sc_module(name)
|
||||
, read_lut(tlm_dmi_ext())
|
||||
, write_lut(tlm_dmi_ext())
|
||||
, tgt_adapter(nullptr)
|
||||
#ifdef WITH_SCV
|
||||
, m_db(scv_tr_db::get_default_db())
|
||||
, stream_handle(nullptr)
|
||||
@ -269,37 +327,16 @@ core_complex::~core_complex() = default;
|
||||
|
||||
void core_complex::trace(sc_trace_file *trf) const {}
|
||||
|
||||
using vm_ptr= std::unique_ptr<iss::vm_if>;
|
||||
vm_ptr create_cpu(core_wrapper* cpu, std::string const& backend, unsigned gdb_port){
|
||||
if(backend == "interp")
|
||||
return vm_ptr{iss::interp::create<core_type>(cpu, gdb_port)};
|
||||
#ifdef WITH_LLVM
|
||||
if(backend == "llvm")
|
||||
return vm_ptr{iss::llvm::create(lcpu, gdb_port)};
|
||||
#endif
|
||||
if(backend == "tcc")
|
||||
return vm_ptr{iss::tcc::create<core_type>(cpu, gdb_port)};
|
||||
return {nullptr};
|
||||
}
|
||||
|
||||
void core_complex::before_end_of_elaboration() {
|
||||
SCCDEBUG(SCMOD)<<"instantiating iss::arch::tgf with "<<backend.get_value()<<" backend";
|
||||
cpu = scc::make_unique<core_wrapper>(this);
|
||||
cpu->set_mhartid(mhartid.get_value());
|
||||
|
||||
vm = create_cpu(cpu.get(), backend.get_value(), gdb_server_port.get_value());
|
||||
cpu->create_cpu(core_type.get_value(), backend.get_value(), gdb_server_port.get_value(), mhartid.get_value());
|
||||
sc_assert(cpu->vm!=nullptr);
|
||||
#ifdef WITH_SCV
|
||||
vm->setDisassEnabled(enable_disass.get_value() || m_db != nullptr);
|
||||
cpu->vm->setDisassEnabled(enable_disass.get_value() || m_db != nullptr);
|
||||
#else
|
||||
vm->setDisassEnabled(enable_disass.get_value());
|
||||
#endif
|
||||
auto *srv = debugger::server<debugger::gdb_session>::get();
|
||||
if (srv) tgt_adapter = srv->get_target();
|
||||
if (tgt_adapter)
|
||||
tgt_adapter->add_custom_command(
|
||||
{"sysc", [this](int argc, char *argv[], debugger::out_func of,
|
||||
debugger::data_func df) -> int { return cmd_sysc(argc, argv, of, df, tgt_adapter); },
|
||||
"SystemC sub-commands: break <time>, print_time"});
|
||||
}
|
||||
|
||||
void core_complex::start_of_simulation() {
|
||||
@ -331,7 +368,7 @@ void core_complex::disass_output(uint64_t pc, const std::string instr_str) {
|
||||
tr_handle.record_attribute("PC", pc);
|
||||
tr_handle.record_attribute("INSTR", instr_str);
|
||||
tr_handle.record_attribute("MODE", lvl[cpu->get_mode()]);
|
||||
tr_handle.record_attribute("MSTATUS", cpu->get_state().mstatus.backing.val);
|
||||
tr_handle.record_attribute("MSTATUS", cpu->get_state());
|
||||
tr_handle.record_attribute("LTIME_START", quantum_keeper.get_current_time().value() / 1000);
|
||||
#endif
|
||||
}
|
||||
@ -362,7 +399,7 @@ void core_complex::run() {
|
||||
wait(clk_i.value_changed_event());
|
||||
}
|
||||
cpu->set_interrupt_execution(false);
|
||||
vm->start();
|
||||
cpu->start();
|
||||
} while (cpu->get_interrupt_execution());
|
||||
sc_stop();
|
||||
}
|
||||
@ -382,13 +419,13 @@ bool core_complex::read_mem(uint64_t addr, unsigned length, uint8_t *const data,
|
||||
gp.set_data_ptr(data);
|
||||
gp.set_data_length(length);
|
||||
gp.set_streaming_width(length);
|
||||
sc_time delay{quantum_keeper.get_local_time()};
|
||||
sc_time delay=quantum_keeper.get_local_time();
|
||||
#ifdef WITH_SCV
|
||||
if (m_db != nullptr && tr_handle.is_valid()) {
|
||||
if (is_fetch && tr_handle.is_active()) {
|
||||
tr_handle.end_transaction();
|
||||
}
|
||||
auto preExt = new scv4tlm::tlm_recording_extension(tr_handle, this);
|
||||
auto preExt = new tlm::scc::scv::tlm_recording_extension(tr_handle, this);
|
||||
gp.set_extension(preExt);
|
||||
}
|
||||
#endif
|
||||
@ -431,10 +468,10 @@ bool core_complex::write_mem(uint64_t addr, unsigned length, const uint8_t *cons
|
||||
gp.set_data_ptr(write_buf.data());
|
||||
gp.set_data_length(length);
|
||||
gp.set_streaming_width(length);
|
||||
sc_time delay{quantum_keeper.get_local_time()};
|
||||
sc_time delay=quantum_keeper.get_local_time();
|
||||
#ifdef WITH_SCV
|
||||
if (m_db != nullptr && tr_handle.is_valid()) {
|
||||
auto preExt = new scv4tlm::tlm_recording_extension(tr_handle, this);
|
||||
auto preExt = new tlm::scc::scv::tlm_recording_extension(tr_handle, this);
|
||||
gp.set_extension(preExt);
|
||||
}
|
||||
#endif
|
||||
|
1
src/vm/interp/.gitignore
vendored
Normal file
1
src/vm/interp/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/vm_tgc_*.cpp
|
3678
src/vm/interp/vm_tgc_c.cpp
Normal file
3678
src/vm/interp/vm_tgc_c.cpp
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -377,7 +377,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 2);
|
||||
gen_trap_check(tu);
|
||||
@ -424,7 +423,6 @@ private:
|
||||
new_pc_val,
|
||||
tu.l_not(tu.constant(0x1, 32U))), 32);
|
||||
tu.store(PC_val_v, traits<ARCH>::NEXT_PC);
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32U), traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 3);
|
||||
@ -466,7 +464,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 4);
|
||||
gen_trap_check(tu);
|
||||
@ -507,7 +504,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 5);
|
||||
gen_trap_check(tu);
|
||||
@ -552,7 +548,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 6);
|
||||
gen_trap_check(tu);
|
||||
@ -597,7 +592,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 7);
|
||||
gen_trap_check(tu);
|
||||
@ -638,7 +632,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 8);
|
||||
gen_trap_check(tu);
|
||||
@ -679,7 +672,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 9);
|
||||
gen_trap_check(tu);
|
||||
@ -1621,7 +1613,6 @@ private:
|
||||
tu.constant(1, 64U),
|
||||
tu.trunc(tu.constant(imm, 32U), 32));
|
||||
tu.close_scope();
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32),traits<ARCH>::LAST_BRANCH);
|
||||
gen_set_pc(tu, pc, traits<ARCH>::NEXT_PC);
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 38);
|
||||
gen_trap_check(tu);
|
||||
@ -2055,13 +2046,11 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) {
|
||||
tu(" *trap_state = {:#x};", 0x80 << 24 | (cause << 16) | trap_id);
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32),traits<ARCH>::LAST_BRANCH);
|
||||
}
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(tu_builder& tu, unsigned lvl) {
|
||||
tu("leave_trap(core_ptr, {});", lvl);
|
||||
tu.store(tu.read_mem(traits<ARCH>::CSR, (lvl << 8) + 0x41, traits<ARCH>::XLEN),traits<ARCH>::NEXT_PC);
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32),traits<ARCH>::LAST_BRANCH);
|
||||
}
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned type) {
|
||||
@ -2070,7 +2059,6 @@ template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned t
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(tu_builder& tu) {
|
||||
tu("trap_entry:");
|
||||
tu("enter_trap(core_ptr, *trap_state, *pc);");
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(),32),traits<ARCH>::LAST_BRANCH);
|
||||
tu("return *next_pc;");
|
||||
}
|
||||
|
||||
|
@ -449,7 +449,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 2);
|
||||
gen_trap_check(tu);
|
||||
@ -487,7 +486,6 @@ private:
|
||||
new_pc_val,
|
||||
tu.l_not(tu.constant(0x1, 32U))), 32);
|
||||
tu.store(PC_val_v, traits<ARCH>::NEXT_PC);
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32U), traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 3);
|
||||
gen_trap_check(tu);
|
||||
@ -528,7 +526,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 4);
|
||||
gen_trap_check(tu);
|
||||
@ -569,7 +566,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 5);
|
||||
gen_trap_check(tu);
|
||||
@ -614,7 +610,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 6);
|
||||
gen_trap_check(tu);
|
||||
@ -659,7 +654,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 7);
|
||||
gen_trap_check(tu);
|
||||
@ -700,7 +694,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 8);
|
||||
gen_trap_check(tu);
|
||||
@ -741,7 +734,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 9);
|
||||
gen_trap_check(tu);
|
||||
@ -1683,7 +1675,6 @@ private:
|
||||
tu.constant(1, 64U),
|
||||
tu.trunc(tu.constant(imm, 32U), 32));
|
||||
tu.close_scope();
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32),traits<ARCH>::LAST_BRANCH);
|
||||
gen_set_pc(tu, pc, traits<ARCH>::NEXT_PC);
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 38);
|
||||
gen_trap_check(tu);
|
||||
@ -2562,7 +2553,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 65);
|
||||
gen_trap_check(tu);
|
||||
@ -2868,7 +2858,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 76);
|
||||
gen_trap_check(tu);
|
||||
@ -2908,7 +2897,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 77);
|
||||
gen_trap_check(tu);
|
||||
@ -2948,7 +2936,6 @@ private:
|
||||
auto is_cont_v = tu.choose(
|
||||
tu.icmp(ICmpInst::ICMP_NE, tu.ext(PC_val_v, 32U, true), tu.constant(pc.val, 32U)),
|
||||
tu.constant(0U, 32), tu.constant(1U, 32));
|
||||
tu.store(is_cont_v, traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 78);
|
||||
gen_trap_check(tu);
|
||||
@ -3055,7 +3042,6 @@ private:
|
||||
tu.open_scope();
|
||||
auto PC_val_v = tu.assignment("PC_val", tu.load(rs1 + traits<ARCH>::X0, 0), 32);
|
||||
tu.store(PC_val_v, traits<ARCH>::NEXT_PC);
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32U), traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 82);
|
||||
gen_trap_check(tu);
|
||||
@ -3108,7 +3094,6 @@ private:
|
||||
tu.constant(2, 32U)), 1 + traits<ARCH>::X0);
|
||||
auto PC_val_v = tu.assignment("PC_val", tu.load(rs1 + traits<ARCH>::X0, 0), 32);
|
||||
tu.store(PC_val_v, traits<ARCH>::NEXT_PC);
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32U), traits<ARCH>::LAST_BRANCH);
|
||||
tu.close_scope();
|
||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC, 84);
|
||||
gen_trap_check(tu);
|
||||
@ -3247,13 +3232,11 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_raise_trap(tu_builder& tu, uint16_t trap_id, uint16_t cause) {
|
||||
tu(" *trap_state = {:#x};", 0x80 << 24 | (cause << 16) | trap_id);
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32),traits<ARCH>::LAST_BRANCH);
|
||||
}
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(tu_builder& tu, unsigned lvl) {
|
||||
tu("leave_trap(core_ptr, {});", lvl);
|
||||
tu.store(tu.read_mem(traits<ARCH>::CSR, (lvl << 8) + 0x41, traits<ARCH>::XLEN),traits<ARCH>::NEXT_PC);
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32),traits<ARCH>::LAST_BRANCH);
|
||||
}
|
||||
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned type) {
|
||||
@ -3262,7 +3245,6 @@ template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned t
|
||||
template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(tu_builder& tu) {
|
||||
tu("trap_entry:");
|
||||
tu("enter_trap(core_ptr, *trap_state, *pc);");
|
||||
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(),32),traits<ARCH>::LAST_BRANCH);
|
||||
tu("return *next_pc;");
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user