26 Commits

Author SHA1 Message Date
a6c7b1427e fixes missing namespaces 2023-07-09 20:15:12 +02:00
250ea3c980 extends factory to support SystemC core wrapper 2023-07-09 18:19:59 +02:00
7b31b8ca8e adds updated generated files 2023-07-09 16:58:47 +02:00
91a23a4a18 Merge branch 'develop' of https://git.minres.com/DBT-RISE/DBT-RISE-TGC into develop 2023-07-09 16:55:06 +02:00
21d3250e1a changes templates 2023-07-09 16:53:59 +02:00
2b094c3162 removes trace compass nature 2023-07-06 10:39:59 +02:00
a32c83e1be fixes CLI handling of plugin paramters in ISS 2023-07-05 08:32:05 +02:00
7e45a25218 adds a instr yaml for TGC 2023-07-05 08:28:42 +02:00
87b4082633 Merge branch 'tmp' into develop 2023-07-03 14:22:50 +02:00
4dbc7433a5 fixes cause CSR handling 2023-06-12 17:38:56 +02:00
99a9970ddd fixes sysc compile issues 2023-06-12 09:58:24 +02:00
0b5de90fb1 changes [m|u]cause rd/wr handling 2023-06-11 18:29:58 +02:00
15cd36dcd4 adds fix for compressed instructions and reads 2023-06-05 17:57:38 +02:00
2281ec4144 corrects errors and adds new backend and 2023-06-05 15:18:27 +02:00
11c481cec2 adds verbosity to error 2023-06-05 15:17:16 +02:00
60d07f2eb6 changes default loglevel to info for tgc-sim 2023-06-01 06:55:21 +02:00
a123beb301 fixes duplicate variable declaration and templates 2023-05-27 10:20:49 +02:00
ee6218279e adapts to latest code gen changes 2023-05-25 12:52:30 +02:00
ce5b2e60b9 amends template to fix branching instructions 2023-05-22 17:00:36 +02:00
c792f50427 Merge branch 'develop' of https://git.minres.com/DBT-RISE/DBT-RISE-TGC into develop 2023-05-16 21:57:32 +02:00
6ed7eafc5d adds inital version of tcc backend 2023-05-16 21:51:35 +02:00
8a5fe58d51 adds needed arch state members for TCC to tgc_c 2023-05-16 08:56:18 +02:00
16cd6d5ff5 fixes core name deduction in cmake build script 2023-05-16 08:54:08 +02:00
ee2ded931d adds remaining register offsets 2023-05-14 17:16:42 +02:00
95ba5c901a re-introduces last_branch register 2023-05-14 17:00:37 +02:00
32848ec396 fixes build system and typo in wt_cache 2023-05-13 16:57:01 +02:00
25 changed files with 2962 additions and 2539 deletions

View File

@ -23,6 +23,5 @@
<nature>org.eclipse.cdt.core.ccnature</nature> <nature>org.eclipse.cdt.core.ccnature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature> <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature> <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
<nature>org.eclipse.linuxtools.tmf.project.nature</nature>
</natures> </natures>
</projectDescription> </projectDescription>

View File

@ -40,11 +40,15 @@ set(LIB_SOURCES
if(TARGET ${CORE_NAME}_cpp) if(TARGET ${CORE_NAME}_cpp)
list(APPEND LIB_SOURCES ${${CORE_NAME}_OUTPUT_FILES}) list(APPEND LIB_SOURCES ${${CORE_NAME}_OUTPUT_FILES})
else() else()
FILE(GLOB GEN_SOURCES FILE(GLOB GEN_ISS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/iss/arch/*.cpp)
${CMAKE_CURRENT_SOURCE_DIR}/src-gen/iss/arch/*.cpp FILE(GLOB GEN_VM_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/interp/vm_*.cpp)
${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/interp/vm_*.cpp list(APPEND LIB_SOURCES ${GEN_ISS_SOURCES} ${GEN_VM_SOURCES})
) foreach(FILEPATH ${GEN_ISS_SOURCES})
list(APPEND LIB_SOURCES ${GEN_SOURCES}) get_filename_component(CORE ${FILEPATH} NAME_WE)
string(TOUPPER ${CORE} CORE)
list(APPEND LIB_DEFINES CORE_${CORE})
endforeach()
message("Defines are ${LIB_DEFINES}")
endif() endif()
if(TARGET RapidJSON OR TARGET RapidJSON::RapidJSON) if(TARGET RapidJSON OR TARGET RapidJSON::RapidJSON)
@ -131,17 +135,31 @@ project(tgc-sim)
find_package(Boost COMPONENTS program_options thread REQUIRED) find_package(Boost COMPONENTS program_options thread REQUIRED)
add_executable(${PROJECT_NAME} src/main.cpp) add_executable(${PROJECT_NAME} src/main.cpp)
FILE(GLOB TGC_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/iss/arch/*.cpp) if(TARGET ${CORE_NAME}_cpp)
list(APPEND TGC_SOURCES ${${CORE_NAME}_OUTPUT_FILES})
else()
FILE(GLOB TGC_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src-gen/iss/arch/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/interp/vm_*.cpp
)
list(APPEND TGC_SOURCES ${GEN_SOURCES})
endif()
foreach(F IN LISTS TGC_SOURCES) foreach(F IN LISTS TGC_SOURCES)
string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F}) if (${F} MATCHES ".*/arch/([^/]*)\.cpp")
string(TOUPPER ${CORE_NAME_LC} CORE_NAME) string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F})
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME}) string(TOUPPER ${CORE_NAME_LC} CORE_NAME)
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
endif()
endforeach() endforeach()
if(WITH_LLVM) if(WITH_LLVM)
target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_LLVM) target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_LLVM)
target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs}) target_link_libraries(${PROJECT_NAME} PUBLIC ${llvm_libs})
endif() endif()
if(WITH_TCC)
target_compile_definitions(${PROJECT_NAME} PRIVATE WITH_TCC)
endif()
# Links the target exe against the libraries # Links the target exe against the libraries
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc) target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc)
if(TARGET Boost::program_options) if(TARGET Boost::program_options)
@ -168,13 +186,18 @@ install(TARGETS tgc-sim
############################################################################### ###############################################################################
if(TARGET scc-sysc) if(TARGET scc-sysc)
project(dbt-rise-tgc_sc VERSION 1.0.0) project(dbt-rise-tgc_sc VERSION 1.0.0)
add_library(${PROJECT_NAME} src/sysc/core_complex.cpp) add_library(${PROJECT_NAME}
src/sysc/core_complex.cpp
src/sysc/register_tgc_c.cpp
)
target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_SYSTEMC) target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_SYSTEMC)
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME}) target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
foreach(F IN LISTS TGC_SOURCES) foreach(F IN LISTS TGC_SOURCES)
string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F}) if (${F} MATCHES ".*/arch/([^/]*)\.cpp")
string(TOUPPER ${CORE_NAME_LC} CORE_NAME) string(REGEX REPLACE ".*/([^/]*)\.cpp" "\\1" CORE_NAME_LC ${F})
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME}) string(TOUPPER ${CORE_NAME_LC} CORE_NAME)
target_compile_definitions(${PROJECT_NAME} PRIVATE CORE_${CORE_NAME})
endif()
endforeach() endforeach()
target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc scc-sysc) target_link_libraries(${PROJECT_NAME} PUBLIC dbt-rise-tgc scc-sysc)
if(WITH_LLVM) if(WITH_LLVM)

537
TGC_C_instr.yaml Normal file
View File

@ -0,0 +1,537 @@
RV32I:
- LUI:
encoding: 0b00000000000000000000000000110111
mask: 0b00000000000000000000000001111111
size: 32
branch: false
delay: 1
- AUIPC:
encoding: 0b00000000000000000000000000010111
mask: 0b00000000000000000000000001111111
size: 32
branch: false
delay: 1
- JAL:
encoding: 0b00000000000000000000000001101111
mask: 0b00000000000000000000000001111111
attributes: [[name:no_cont]]
size: 32
branch: true
delay: 1
- JALR:
encoding: 0b00000000000000000000000001100111
mask: 0b00000000000000000111000001111111
attributes: [[name:no_cont]]
size: 32
branch: true
delay: 1
- BEQ:
encoding: 0b00000000000000000000000001100011
mask: 0b00000000000000000111000001111111
attributes: [[name:no_cont], [name:cond]]
size: 32
branch: true
delay: [1,1]
- BNE:
encoding: 0b00000000000000000001000001100011
mask: 0b00000000000000000111000001111111
attributes: [[name:no_cont], [name:cond]]
size: 32
branch: true
delay: [1,1]
- BLT:
encoding: 0b00000000000000000100000001100011
mask: 0b00000000000000000111000001111111
attributes: [[name:no_cont], [name:cond]]
size: 32
branch: true
delay: [1,1]
- BGE:
encoding: 0b00000000000000000101000001100011
mask: 0b00000000000000000111000001111111
attributes: [[name:no_cont], [name:cond]]
size: 32
branch: true
delay: [1,1]
- BLTU:
encoding: 0b00000000000000000110000001100011
mask: 0b00000000000000000111000001111111
attributes: [[name:no_cont], [name:cond]]
size: 32
branch: true
delay: [1,1]
- BGEU:
encoding: 0b00000000000000000111000001100011
mask: 0b00000000000000000111000001111111
attributes: [[name:no_cont], [name:cond]]
size: 32
branch: true
delay: [1,1]
- LB:
encoding: 0b00000000000000000000000000000011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
- LH:
encoding: 0b00000000000000000001000000000011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
- LW:
encoding: 0b00000000000000000010000000000011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
- LBU:
encoding: 0b00000000000000000100000000000011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
- LHU:
encoding: 0b00000000000000000101000000000011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
- SB:
encoding: 0b00000000000000000000000000100011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
- SH:
encoding: 0b00000000000000000001000000100011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
- SW:
encoding: 0b00000000000000000010000000100011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
- ADDI:
encoding: 0b00000000000000000000000000010011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
- SLTI:
encoding: 0b00000000000000000010000000010011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
- SLTIU:
encoding: 0b00000000000000000011000000010011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
- XORI:
encoding: 0b00000000000000000100000000010011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
- ORI:
encoding: 0b00000000000000000110000000010011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
- ANDI:
encoding: 0b00000000000000000111000000010011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
- SLLI:
encoding: 0b00000000000000000001000000010011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
- SRLI:
encoding: 0b00000000000000000101000000010011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
- SRAI:
encoding: 0b01000000000000000101000000010011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
- ADD:
encoding: 0b00000000000000000000000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
- SUB:
encoding: 0b01000000000000000000000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
- SLL:
encoding: 0b00000000000000000001000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
- SLT:
encoding: 0b00000000000000000010000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
- SLTU:
encoding: 0b00000000000000000011000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
- XOR:
encoding: 0b00000000000000000100000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
- SRL:
encoding: 0b00000000000000000101000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
- SRA:
encoding: 0b01000000000000000101000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
- OR:
encoding: 0b00000000000000000110000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
- AND:
encoding: 0b00000000000000000111000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
- FENCE:
encoding: 0b00000000000000000000000000001111
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
- ECALL:
encoding: 0b00000000000000000000000001110011
mask: 0b11111111111111111111111111111111
attributes: [[name:no_cont]]
size: 32
branch: false
delay: 1
- EBREAK:
encoding: 0b00000000000100000000000001110011
mask: 0b11111111111111111111111111111111
attributes: [[name:no_cont]]
size: 32
branch: false
delay: 1
- MRET:
encoding: 0b00110000001000000000000001110011
mask: 0b11111111111111111111111111111111
attributes: [[name:no_cont]]
size: 32
branch: false
delay: 1
- WFI:
encoding: 0b00010000010100000000000001110011
mask: 0b11111111111111111111111111111111
size: 32
branch: false
delay: 1
Zicsr:
- CSRRW:
encoding: 0b00000000000000000001000001110011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
- CSRRS:
encoding: 0b00000000000000000010000001110011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
- CSRRC:
encoding: 0b00000000000000000011000001110011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
- CSRRWI:
encoding: 0b00000000000000000101000001110011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
- CSRRSI:
encoding: 0b00000000000000000110000001110011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
- CSRRCI:
encoding: 0b00000000000000000111000001110011
mask: 0b00000000000000000111000001111111
size: 32
branch: false
delay: 1
Zifencei:
- FENCE_I:
encoding: 0b00000000000000000001000000001111
mask: 0b00000000000000000111000001111111
attributes: [[name:flush]]
size: 32
branch: false
delay: 1
RV32M:
- MUL:
encoding: 0b00000010000000000000000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
- MULH:
encoding: 0b00000010000000000001000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
- MULHSU:
encoding: 0b00000010000000000010000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
- MULHU:
encoding: 0b00000010000000000011000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
- DIV:
encoding: 0b00000010000000000100000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
- DIVU:
encoding: 0b00000010000000000101000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
- REM:
encoding: 0b00000010000000000110000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
- REMU:
encoding: 0b00000010000000000111000000110011
mask: 0b11111110000000000111000001111111
size: 32
branch: false
delay: 1
RV32IC:
- CADDI4SPN:
encoding: 0b0000000000000000
mask: 0b1110000000000011
size: 16
branch: false
delay: 1
- CLW:
encoding: 0b0100000000000000
mask: 0b1110000000000011
size: 16
branch: false
delay: 1
- CSW:
encoding: 0b1100000000000000
mask: 0b1110000000000011
size: 16
branch: false
delay: 1
- CADDI:
encoding: 0b0000000000000001
mask: 0b1110000000000011
size: 16
branch: false
delay: 1
- CNOP:
encoding: 0b0000000000000001
mask: 0b1110111110000011
size: 16
branch: false
delay: 1
- CJAL:
encoding: 0b0010000000000001
mask: 0b1110000000000011
attributes: [[name:no_cont]]
size: 16
branch: true
delay: 1
- CLI:
encoding: 0b0100000000000001
mask: 0b1110000000000011
size: 16
branch: false
delay: 1
- CLUI:
encoding: 0b0110000000000001
mask: 0b1110000000000011
size: 16
branch: false
delay: 1
- CADDI16SP:
encoding: 0b0110000100000001
mask: 0b1110111110000011
size: 16
branch: false
delay: 1
- CSRLI:
encoding: 0b1000000000000001
mask: 0b1111110000000011
size: 16
branch: false
delay: 1
- CSRAI:
encoding: 0b1000010000000001
mask: 0b1111110000000011
size: 16
branch: false
delay: 1
- CANDI:
encoding: 0b1000100000000001
mask: 0b1110110000000011
size: 16
branch: false
delay: 1
- CSUB:
encoding: 0b1000110000000001
mask: 0b1111110001100011
size: 16
branch: false
delay: 1
- CXOR:
encoding: 0b1000110000100001
mask: 0b1111110001100011
size: 16
branch: false
delay: 1
- COR:
encoding: 0b1000110001000001
mask: 0b1111110001100011
size: 16
branch: false
delay: 1
- CAND:
encoding: 0b1000110001100001
mask: 0b1111110001100011
size: 16
branch: false
delay: 1
- CJ:
encoding: 0b1010000000000001
mask: 0b1110000000000011
attributes: [[name:no_cont]]
size: 16
branch: true
delay: 1
- CBEQZ:
encoding: 0b1100000000000001
mask: 0b1110000000000011
attributes: [[name:no_cont], [name:cond]]
size: 16
branch: true
delay: [1,1]
- CBNEZ:
encoding: 0b1110000000000001
mask: 0b1110000000000011
attributes: [[name:no_cont], [name:cond]]
size: 16
branch: true
delay: [1,1]
- CSLLI:
encoding: 0b0000000000000010
mask: 0b1111000000000011
size: 16
branch: false
delay: 1
- CLWSP:
encoding: 0b0100000000000010
mask: 0b1110000000000011
size: 16
branch: false
delay: 1
- CMV:
encoding: 0b1000000000000010
mask: 0b1111000000000011
size: 16
branch: false
delay: 1
- CJR:
encoding: 0b1000000000000010
mask: 0b1111000001111111
attributes: [[name:no_cont]]
size: 16
branch: true
delay: 1
- CADD:
encoding: 0b1001000000000010
mask: 0b1111000000000011
size: 16
branch: false
delay: 1
- CJALR:
encoding: 0b1001000000000010
mask: 0b1111000001111111
attributes: [[name:no_cont]]
size: 16
branch: true
delay: 1
- CEBREAK:
encoding: 0b1001000000000010
mask: 0b1111111111111111
attributes: [[name:no_cont]]
size: 16
branch: false
delay: 1
- CSWSP:
encoding: 0b1100000000000010
mask: 0b1110000000000011
size: 16
branch: false
delay: 1
- DII:
encoding: 0b0000000000000000
mask: 0b1111111111111111
attributes: [[name:no_cont]]
size: 16
branch: false
delay: 1

View File

@ -1,13 +1,13 @@
import "RV32I.core_desc" import "ISA/RV32I.core_desc"
import "RVM.core_desc" import "ISA/RVM.core_desc"
import "RVC.core_desc" import "ISA/RVC.core_desc"
Core TGC_C provides RV32I, Zicsr, Zifencei, RV32M, RV32IC { Core TGC_C provides RV32I, Zicsr, Zifencei, RV32M, RV32IC {
architectural_state { architectural_state {
XLEN=32; XLEN=32;
// definitions for the architecture wrapper // definitions for the architecture wrapper
// XL ZYXWVUTSRQPONMLKJIHGFEDCBA // XL ZYXWVUTSRQPONMLKJIHGFEDCBA
unsigned MISA_VAL = 0b01000000000000000001000100000100; unsigned int MISA_VAL = 0b01000000000000000001000100000100;
unsigned MARCHID_VAL = 0x80000003; unsigned int MARCHID_VAL = 0x80000003;
} }
} }

View File

@ -33,7 +33,7 @@
def getRegisterSizes(){ def getRegisterSizes(){
def regs = registers.collect{it.size} def regs = registers.collect{it.size}
regs[-1]=64 // correct for NEXT_PC regs[-1]=64 // correct for NEXT_PC
//regs+=[32, 32, 64, 64, 64, 32] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION regs+=[32,32, 64, 64, 64, 32, 32] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION, LAST_BRANCH
return regs return regs
} }
%> %>
@ -62,8 +62,8 @@ void ${coreDef.name.toLowerCase()}::reset(uint64_t address) {
reg.PC=address; reg.PC=address;
reg.NEXT_PC=reg.PC; reg.NEXT_PC=reg.PC;
reg.PRIV=0x3; reg.PRIV=0x3;
trap_state=0; reg.trap_state=0;
icount=0; reg.icount=0;
} }
uint8_t *${coreDef.name.toLowerCase()}::get_regs_base_ptr() { uint8_t *${coreDef.name.toLowerCase()}::get_regs_base_ptr() {

View File

@ -30,14 +30,12 @@
* *
*******************************************************************************/ *******************************************************************************/
<% <%
import com.minres.coredsl.util.BigIntegerWithRadix
def nativeTypeSize(int size){ def nativeTypeSize(int size){
if(size<=8) return 8; else if(size<=16) return 16; else if(size<=32) return 32; else return 64; if(size<=8) return 8; else if(size<=16) return 16; else if(size<=32) return 32; else return 64;
} }
def getRegisterSizes(){ def getRegisterSizes(){
def regs = registers.collect{nativeTypeSize(it.size)} def regs = registers.collect{nativeTypeSize(it.size)}
// regs+=[32,32, 64, 64, 64, 32] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION regs+=[32,32, 64, 64, 64, 32, 32] // append TRAP_STATE, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION, LAST_BRANCH
return regs return regs
} }
def getRegisterOffsets(){ def getRegisterOffsets(){
@ -57,10 +55,7 @@ def byteSize(int size){
return 128; return 128;
} }
def getCString(def val){ def getCString(def val){
if(val instanceof BigIntegerWithRadix) return val.toString()
return ((BigIntegerWithRadix)val).toCString()
else
return val.toString()
} }
%> %>
#ifndef _${coreDef.name.toUpperCase()}_H_ #ifndef _${coreDef.name.toUpperCase()}_H_
@ -91,7 +86,7 @@ template <> struct traits<${coreDef.name.toLowerCase()}> {
constexpr static unsigned FP_REGS_SIZE = ${constants.find {it.name=='FLEN'}?.value?:0}; constexpr static unsigned FP_REGS_SIZE = ${constants.find {it.name=='FLEN'}?.value?:0};
enum reg_e { enum reg_e {
${registers.collect{it.name}.join(', ')}, NUM_REGS ${registers.collect{it.name}.join(', ')}, NUM_REGS, TRAP_STATE=NUM_REGS, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION, LAST_BRANCH
}; };
using reg_t = uint${addrDataWidth}_t; using reg_t = uint${addrDataWidth}_t;
@ -116,7 +111,7 @@ template <> struct traits<${coreDef.name.toLowerCase()}> {
enum mem_type_e { ${spaces.collect{it.name}.join(', ')} }; enum mem_type_e { ${spaces.collect{it.name}.join(', ')} };
enum class opcode_e : unsigned short {<%instructions.eachWithIndex{instr, index -> %> enum class opcode_e {<%instructions.eachWithIndex{instr, index -> %>
${instr.instruction.name} = ${index},<%}%> ${instr.instruction.name} = ${index},<%}%>
MAX_OPCODE MAX_OPCODE
}; };
@ -136,7 +131,7 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
uint8_t* get_regs_base_ptr() override; uint8_t* get_regs_base_ptr() override;
inline uint64_t get_icount() { return icount; } inline uint64_t get_icount() { return reg.icount; }
inline bool should_stop() { return interrupt_sim; } inline bool should_stop() { return interrupt_sim; }
@ -154,7 +149,7 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
inline uint32_t get_last_branch() { return last_branch; } inline uint32_t get_last_branch() { return reg.last_branch; }
#pragma pack(push, 1) #pragma pack(push, 1)
@ -162,14 +157,14 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
registers.each { reg -> if(reg.size>0) {%> registers.each { reg -> if(reg.size>0) {%>
uint${byteSize(reg.size)}_t ${reg.name} = 0;<% uint${byteSize(reg.size)}_t ${reg.name} = 0;<%
}}%> }}%>
uint32_t trap_state = 0, pending_trap = 0;
uint64_t icount = 0;
uint64_t cycle = 0;
uint64_t instret = 0;
uint32_t instruction = 0;
uint32_t last_branch = 0;
} reg; } reg;
#pragma pack(pop) #pragma pack(pop)
uint32_t trap_state = 0, pending_trap = 0;
uint64_t icount = 0;
uint64_t cycle = 0;
uint64_t instret = 0;
uint32_t instruction = 0;
uint32_t last_branch = 0;
std::array<address_type, 4> addr_mode; std::array<address_type, 4> addr_mode;
uint64_t interrupt_sim=0; uint64_t interrupt_sim=0;

View File

@ -13,5 +13,8 @@ ${name}: <% instrList.findAll{!it.instruction.name.startsWith("__")}.each { %>
- ${it.instruction.name}: - ${it.instruction.name}:
encoding: ${it.encoding} encoding: ${it.encoding}
mask: ${it.mask}<%if(it.attributes.size) {%> mask: ${it.mask}<%if(it.attributes.size) {%>
attributes: ${it.attributes}<%}}}%> attributes: ${it.attributes}<%}%>
size: ${it.length}
branch: ${it.modifiesPC}
delay: ${it.isConditional?"[1,1]":"1"}<%}}%>

View File

@ -30,16 +30,13 @@
* *
*******************************************************************************/ *******************************************************************************/
<% <%
import com.minres.coredsl.util.BigIntegerWithRadix
def nativeTypeSize(int size){ def nativeTypeSize(int size){
if(size<=8) return 8; else if(size<=16) return 16; else if(size<=32) return 32; else return 64; if(size<=8) return 8; else if(size<=16) return 16; else if(size<=32) return 32; else return 64;
} }
%> %>
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <iss/debugger/gdb_session.h> #include <iss/debugger/gdb_session.h>
#include <iss/debugger/server.h> #include <iss/debugger/server.h>
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/iss.h> #include <iss/iss.h>
#include <iss/interp/vm_base.h> #include <iss/interp/vm_base.h>
#include <util/logging.h> #include <util/logging.h>
@ -121,7 +118,7 @@ protected:
inline void raise(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; auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id;
this->core.trap_state = trap_val; this->core.reg.trap_state = trap_val;
this->template get_reg<uint${addrDataWidth}_t>(traits::NEXT_PC) = std::numeric_limits<uint${addrDataWidth}_t>::max(); this->template get_reg<uint${addrDataWidth}_t>(traits::NEXT_PC) = std::numeric_limits<uint${addrDataWidth}_t>::max();
} }
@ -244,16 +241,16 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
auto pc=start; auto pc=start;
auto* PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]); auto* PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
auto* NEXT_PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]); auto* NEXT_PC = reinterpret_cast<uint${addrDataWidth}_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
auto& trap_state = this->core.trap_state; auto& trap_state = this->core.reg.trap_state;
auto& icount = this->core.icount; auto& icount = this->core.reg.icount;
auto& cycle = this->core.cycle; auto& cycle = this->core.reg.cycle;
auto& instret = this->core.instret; auto& instret = this->core.reg.instret;
auto& instr = this->core.instruction; auto& instr = this->core.reg.instruction;
// we fetch at max 4 byte, alignment is 2 // we fetch at max 4 byte, alignment is 2
auto *const data = reinterpret_cast<uint8_t*>(&instr); auto *const data = reinterpret_cast<uint8_t*>(&instr);
while(!this->core.should_stop() && while(!this->core.should_stop() &&
!(is_count_limit_enabled(cond) && this->core.get_icount() >= icount_limit)){ !(is_count_limit_enabled(cond) && icount >= icount_limit)){
if(fetch_ins(pc, data)!=iss::Ok){ if(fetch_ins(pc, data)!=iss::Ok){
this->do_sync(POST_SYNC, std::numeric_limits<unsigned>::max()); this->do_sync(POST_SYNC, std::numeric_limits<unsigned>::max());
pc.val = super::core.enter_trap(std::numeric_limits<uint64_t>::max(), pc.val, 0); pc.val = super::core.enter_trap(std::numeric_limits<uint64_t>::max(), pc.val, 0);
@ -262,7 +259,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
(instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0' (instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
auto inst_id = decode_inst_id(instr); auto inst_id = decode_inst_id(instr);
// pre execution stuff // pre execution stuff
this->core.last_branch = 0; this->core.reg.last_branch = 0;
if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id)); if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id));
switch(inst_id){<%instructions.eachWithIndex{instr, idx -> %> switch(inst_id){<%instructions.eachWithIndex{instr, idx -> %>
case arch::traits<ARCH>::opcode_e::${instr.name}: { case arch::traits<ARCH>::opcode_e::${instr.name}: {
@ -289,8 +286,8 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
// post execution stuff // post execution stuff
process_spawn_blocks(); process_spawn_blocks();
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, static_cast<unsigned>(inst_id)); if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, static_cast<unsigned>(inst_id));
// if(!this->core.trap_state) // update trap state if there is a pending interrupt // if(!this->core.reg.trap_state) // update trap state if there is a pending interrupt
// this->core.trap_state = this->core.pending_trap; // this->core.reg.trap_state = this->core.reg.pending_trap;
// trap check // trap check
if(trap_state!=0){ if(trap_state!=0){
super::core.enter_trap(trap_state, pc.val, instr); super::core.enter_trap(trap_state, pc.val, instr);
@ -301,7 +298,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
cycle++; cycle++;
pc.val=*NEXT_PC; pc.val=*NEXT_PC;
this->core.reg.PC = this->core.reg.NEXT_PC; this->core.reg.PC = this->core.reg.NEXT_PC;
this->core.trap_state = this->core.pending_trap; this->core.reg.trap_state = this->core.reg.pending_trap;
} }
} }
return pc; return pc;
@ -317,3 +314,30 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
} }
} // namespace interp } // namespace interp
} // namespace iss } // namespace iss
#include <iss/factory.h>
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/arch/riscv_hart_mu_p.h>
namespace iss {
namespace {
std::array<bool, 2> dummy = {
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|interp", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>();
auto vm = new interp::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
return {cpu_ptr{cpu}, vm_ptr{vm}};
}),
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|interp", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::${coreDef.name.toLowerCase()}>();
auto vm = new interp::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
return {cpu_ptr{cpu}, vm_ptr{vm}};
})
};
}
}
extern "C" {
bool* get_${coreDef.name.toLowerCase()}_interp_creators() {
return iss::dummy.data();
}
}

View File

@ -31,7 +31,6 @@
*******************************************************************************/ *******************************************************************************/
#include <iss/arch/${coreDef.name.toLowerCase()}.h> #include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/debugger/gdb_session.h> #include <iss/debugger/gdb_session.h>
#include <iss/debugger/server.h> #include <iss/debugger/server.h>
#include <iss/iss.h> #include <iss/iss.h>
@ -55,10 +54,12 @@ using namespace iss::debugger;
template <typename ARCH> class vm_impl : public iss::tcc::vm_base<ARCH> { template <typename ARCH> class vm_impl : public iss::tcc::vm_base<ARCH> {
public: public:
using traits = arch::traits<ARCH>;
using super = typename iss::tcc::vm_base<ARCH>; using super = typename iss::tcc::vm_base<ARCH>;
using virt_addr_t = typename super::virt_addr_t; using virt_addr_t = typename super::virt_addr_t;
using phys_addr_t = typename super::phys_addr_t; using phys_addr_t = typename super::phys_addr_t;
using code_word_t = typename super::code_word_t; using code_word_t = typename super::code_word_t;
using mem_type_e = typename traits::mem_type_e;
using addr_t = typename super::addr_t; using addr_t = typename super::addr_t;
using tu_builder = typename super::tu_builder; using tu_builder = typename super::tu_builder;
@ -82,7 +83,7 @@ protected:
using compile_ret_t = std::tuple<continuation_e>; using compile_ret_t = std::tuple<continuation_e>;
using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, tu_builder&); using compile_func = compile_ret_t (this_class::*)(virt_addr_t &pc, code_word_t instr, tu_builder&);
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);}
void setup_module(std::string m) override { void setup_module(std::string m) override {
super::setup_module(m); super::setup_module(m);
@ -104,10 +105,10 @@ protected:
inline void gen_set_pc(tu_builder& tu, virt_addr_t pc, unsigned reg_num) { inline void gen_set_pc(tu_builder& tu, virt_addr_t pc, unsigned reg_num) {
switch(reg_num){ switch(reg_num){
case traits<ARCH>::NEXT_PC: case traits::NEXT_PC:
tu("*next_pc = {:#x};", pc.val); tu("*next_pc = {:#x};", pc.val);
break; break;
case traits<ARCH>::PC: case traits::PC:
tu("*pc = {:#x};", pc.val); tu("*pc = {:#x};", pc.val);
break; break;
default: default:
@ -123,7 +124,7 @@ protected:
// enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 }; // enum { MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111 };
enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 }; enum { MASK16 = 0b1111111111111111, MASK32 = 0b11111111111100000111000001111111 };
enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 }; enum { EXTR_MASK16 = MASK16 >> 2, EXTR_MASK32 = MASK32 >> 2 };
enum { LUT_SIZE = 1 << util::bit_count(EXTR_MASK32), LUT_SIZE_C = 1 << util::bit_count(EXTR_MASK16) }; enum { LUT_SIZE = 1 << util::bit_count(static_cast<uint32_t>(EXTR_MASK32)), LUT_SIZE_C = 1 << util::bit_count(static_cast<uint32_t>(EXTR_MASK16)) };
std::array<compile_func, LUT_SIZE> lut; std::array<compile_func, LUT_SIZE> lut;
@ -170,6 +171,12 @@ protected:
} }
return lut_val; return lut_val;
} }
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: private:
/**************************************************************************** /****************************************************************************
@ -185,13 +192,28 @@ private:
const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{ const std::array<InstructionDesriptor, ${instructions.size}> instr_descr = {{
/* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %> /* entries are: size, valid value, valid mask, function ptr */<%instructions.each{instr -> %>
/* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */ /* instruction ${instr.instruction.name}, encoding '${instr.encoding}' */
{${instr.length}, 0b${instr.value}, 0b${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 definitions */<%instructions.eachWithIndex{instr, idx -> %>
/* instruction ${idx}: ${instr.name} */ /* instruction ${idx}: ${instr.name} */
compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, tu_builder& tu){<%instr.code.eachLine{%> compile_ret_t __${generator.functionName(instr.name)}(virt_addr_t& pc, code_word_t instr, tu_builder& tu){
tu("${instr.name}_{:#010x}:", pc.val);
vm_base<ARCH>::gen_sync(tu, PRE_SYNC,${idx});
<%instr.fields.eachLine{%>${it}
<%}%>if(this->disass_enabled){
/* generate console output when executing the command */<%instr.disass.eachLine{%>
${it}<%}%>
}
auto cur_pc_val = tu.constant(pc.val, traits::reg_bit_widths[traits::PC]);
pc=pc+ ${instr.length/8};
gen_set_pc(tu, pc, traits::NEXT_PC);
tu.open_scope();<%instr.behavior.eachLine{%>
${it}<%}%> ${it}<%}%>
tu.close_scope();
vm_base<ARCH>::gen_sync(tu, POST_SYNC,${idx});
gen_trap_check(tu);
return returnValue;
} }
<%}%> <%}%>
/**************************************************************************** /****************************************************************************
@ -233,20 +255,20 @@ vm_impl<ARCH>::gen_single_inst_behavior(virt_addr_t &pc, unsigned int &inst_cnt,
// we fetch at max 4 byte, alignment is 2 // we fetch at max 4 byte, alignment is 2
enum {TRAP_ID=1<<16}; enum {TRAP_ID=1<<16};
code_word_t insn = 0; code_word_t insn = 0;
const typename traits<ARCH>::addr_t upper_bits = ~traits<ARCH>::PGMASK; // const typename traits::addr_t upper_bits = ~traits::PGMASK;
phys_addr_t paddr(pc); phys_addr_t paddr(pc);
auto *const data = (uint8_t *)&insn; auto *const data = (uint8_t *)&insn;
paddr = this->core.v2p(pc); paddr = this->core.v2p(pc);
if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary // if ((pc.val & upper_bits) != ((pc.val + 2) & upper_bits)) { // we may cross a page boundary
auto res = this->core.read(paddr, 2, data); // auto res = this->core.read(paddr, 2, data);
if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); // if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
if ((insn & 0x3) == 0x3) { // this is a 32bit instruction // if ((insn & 0x3) == 0x3) { // this is a 32bit instruction
res = this->core.read(this->core.v2p(pc + 2), 2, data + 2); // res = this->core.read(this->core.v2p(pc + 2), 2, data + 2);
} // }
} else { // } else {
auto res = this->core.read(paddr, 4, data); auto res = this->core.read(paddr, 4, data);
if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val); if (res != iss::Ok) throw trap_access(TRAP_ID, pc.val);
} // }
if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0' if (insn == 0x0000006f || (insn&0xffff)==0xa001) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
// curr pc on stack // curr pc on stack
++inst_cnt; ++inst_cnt;
@ -260,13 +282,13 @@ 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) { 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(" *trap_state = {:#x};", 0x80 << 24 | (cause << 16) | trap_id);
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32),traits<ARCH>::LAST_BRANCH); tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(), 32));
} }
template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(tu_builder& tu, unsigned lvl) { template <typename ARCH> void vm_impl<ARCH>::gen_leave_trap(tu_builder& tu, unsigned lvl) {
tu("leave_trap(core_ptr, {});", 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(traits::NEXT_PC, tu.read_mem(traits::CSR, (lvl << 8) + 0x41, traits::XLEN));
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(), 32),traits<ARCH>::LAST_BRANCH); tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(), 32));
} }
template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned type) { template <typename ARCH> void vm_impl<ARCH>::gen_wait(tu_builder& tu, unsigned type) {
@ -274,8 +296,8 @@ 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) { template <typename ARCH> void vm_impl<ARCH>::gen_trap_behavior(tu_builder& tu) {
tu("trap_entry:"); tu("trap_entry:");
tu("enter_trap(core_ptr, *trap_state, *pc);"); tu("enter_trap(core_ptr, *trap_state, *pc, 0);");
tu.store(tu.constant(std::numeric_limits<uint32_t>::max(),32),traits<ARCH>::LAST_BRANCH); tu.store(traits::LAST_BRANCH, tu.constant(std::numeric_limits<uint32_t>::max(),32));
tu("return *next_pc;"); tu("return *next_pc;");
} }
@ -287,5 +309,32 @@ std::unique_ptr<vm_if> create<arch::${coreDef.name.toLowerCase()}>(arch::${coreD
if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port); if (port != 0) debugger::server<debugger::gdb_session>::run_server(ret, port);
return std::unique_ptr<vm_if>(ret); return std::unique_ptr<vm_if>(ret);
} }
} } // namesapce tcc
} // namespace iss } // namespace iss
#include <iss/factory.h>
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/arch/riscv_hart_mu_p.h>
namespace iss {
namespace {
std::array<bool, 2> dummy = {
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|m_p|tcc", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::${coreDef.name.toLowerCase()}>();
auto vm = new tcc::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
return {cpu_ptr{cpu}, vm_ptr{vm}};
}),
core_factory::instance().register_creator("${coreDef.name.toLowerCase()}|mu_p|tcc", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::${coreDef.name.toLowerCase()}>();
auto vm = new tcc::${coreDef.name.toLowerCase()}::vm_impl<arch::${coreDef.name.toLowerCase()}>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
return {cpu_ptr{cpu}, vm_ptr{vm}};
})
};
}
}
extern "C" {
bool* get_${coreDef.name.toLowerCase()}_tcc_creators() {
return iss::dummy.data();
}
}

View File

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

View File

@ -1,223 +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.
*
*******************************************************************************/
<%
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 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()
}
%>
#ifndef _${coreDef.name.toUpperCase()}_H_
#define _${coreDef.name.toUpperCase()}_H_
#include <array>
#include <iss/arch/traits.h>
#include <iss/arch_if.h>
#include <iss/vm_if.h>
namespace iss {
namespace arch {
struct ${coreDef.name.toLowerCase()};
template <> struct traits<${coreDef.name.toLowerCase()}> {
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*, ${getRegisterAliasNames().size}> reg_aliases{
{"${getRegisterAliasNames().join("\", \"")}"}};
enum constants {${coreDef.constants.collect{c -> c.name+"="+c.value}.join(', ')}};
constexpr static unsigned FP_REGS_SIZE = ${coreDef.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,
PENDING_TRAP,
MACHINE_STATE,
LAST_BRANCH,
ICOUNT<%
allRegs.each { reg ->
if(reg instanceof RegisterAlias){ def aliasname=getOriginalName(reg)%>,
${reg.name} = ${aliasname}<%
}
}%>
};
using reg_t = uint${regDataWidth}_t;
using addr_t = uint${addrDataWidth}_t;
using code_word_t = uint${addrDataWidth}_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, ${regSizes.size}> reg_bit_widths{
{${regSizes.join(",")}}};
static constexpr std::array<const uint32_t, ${regOffsets.size}> reg_byte_offsets{
{${regOffsets.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(', ')} };
};
struct ${coreDef.name.toLowerCase()}: public arch_if {
using virt_addr_t = typename traits<${coreDef.name.toLowerCase()}>::virt_addr_t;
using phys_addr_t = typename traits<${coreDef.name.toLowerCase()}>::phys_addr_t;
using reg_t = typename traits<${coreDef.name.toLowerCase()}>::reg_t;
using addr_t = typename traits<${coreDef.name.toLowerCase()}>::addr_t;
${coreDef.name.toLowerCase()}();
~${coreDef.name.toLowerCase()}();
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<${coreDef.name.toLowerCase()}>::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<${coreDef.name.toLowerCase()}>::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 ${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;
uint64_t icount = 0;
} reg;
std::array<address_type, 4> addr_mode;
uint64_t interrupt_sim=0;
<%
def fcsr = allRegs.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;}
<%} else { %>
uint32_t get_fcsr(){return 0;}
void set_fcsr(uint32_t val){}
<%}%>
};
}
}
#endif /* _${coreDef.name.toUpperCase()}_H_ */

View File

@ -1,107 +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.
*
*******************************************************************************/
<%
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()
}
%>
#include "util/ities.h"
#include <util/logging.h>
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <cstdio>
#include <cstring>
#include <fstream>
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;
${coreDef.name.toLowerCase()}::${coreDef.name.toLowerCase()}() {
reg.icount = 0;
}
${coreDef.name.toLowerCase()}::~${coreDef.name.toLowerCase()}() = default;
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.trap_state=0;
reg.machine_state=0x3;
reg.icount=0;
}
uint8_t *${coreDef.name.toLowerCase()}::get_regs_base_ptr() {
return reinterpret_cast<uint8_t*>(&reg);
}
${coreDef.name.toLowerCase()}::phys_addr_t ${coreDef.name.toLowerCase()}::virt2phys(const iss::addr_t &pc) {
return phys_addr_t(pc); // change logical address to physical address
}

View File

@ -280,7 +280,7 @@ public:
void disass_output(uint64_t pc, const std::string instr) override { void disass_output(uint64_t pc, const std::string instr) override {
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [s:0x{:x};c:{}]", CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [s:0x{:x};c:{}]",
pc, instr, (reg_t)state.mstatus, this->icount + cycle_offset); pc, instr, (reg_t)state.mstatus, this->reg.icount + cycle_offset);
}; };
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; } iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
@ -308,17 +308,17 @@ protected:
uint64_t get_next_pc() override { return arch.reg.NEXT_PC; }; uint64_t get_next_pc() override { return arch.reg.NEXT_PC; };
uint64_t get_instr_word() override { return arch.instruction; } uint64_t get_instr_word() override { return arch.reg.instruction; }
uint64_t get_instr_count() override { return arch.icount; } uint64_t get_instr_count() override { return arch.reg.icount; }
uint64_t get_pendig_traps() override { return arch.trap_state; } uint64_t get_pendig_traps() override { return arch.reg.trap_state; }
uint64_t get_total_cycles() override { return arch.icount + arch.cycle_offset; } uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; }; void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; };
bool is_branch_taken() override { return arch.last_branch; }; bool is_branch_taken() override { return arch.reg.last_branch; };
riscv_hart_m_p<BASE, FEAT> &arch; riscv_hart_m_p<BASE, FEAT> &arch;
}; };
@ -419,7 +419,7 @@ protected:
std::vector<std::function<mem_write_f>> memfn_write; std::vector<std::function<mem_write_f>> memfn_write;
void insert_mem_range(uint64_t, uint64_t, std::function<mem_read_f>, std::function<mem_write_f>); void insert_mem_range(uint64_t, uint64_t, std::function<mem_read_f>, std::function<mem_write_f>);
feature_config cfg; feature_config cfg;
unsigned mcause_max_irq{(FEAT&features_e::FEAT_CLIC)?4096:16}; uint64_t mcause_max_irq{(FEAT&features_e::FEAT_CLIC)?4096:16};
inline bool debug_mode_active() {return this->reg.PRIV&0x4;} inline bool debug_mode_active() {return this->reg.PRIV&0x4;}
std::pair<std::function<mem_read_f>, std::function<mem_write_f>> std::pair<std::function<mem_read_f>, std::function<mem_write_f>>
replace_mem_access(std::function<mem_read_f> rd, std::function<mem_write_f> wr){ replace_mem_access(std::function<mem_read_f> rd, std::function<mem_write_f> wr){
@ -619,9 +619,9 @@ template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m
} }
return std::make_pair(entry, true); return std::make_pair(entry, true);
} }
throw std::runtime_error("memory load file is not a valid elf file"); throw std::runtime_error(fmt::format("memory load file {} is not a valid elf file",name));
} }
throw std::runtime_error("memory load file not found"); throw std::runtime_error(fmt::format("memory load file not found, check if {} is a valid file", name));
} }
template<typename BASE, features_e FEAT> template<typename BASE, features_e FEAT>
@ -657,12 +657,12 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
if (unlikely(is_fetch(access) && (addr&(alignment-1)))) { if (unlikely(is_fetch(access) && (addr&(alignment-1)))) {
fault_data = addr; fault_data = addr;
if (is_debug(access)) throw trap_access(0, addr); if (is_debug(access)) throw trap_access(0, addr);
this->trap_state = (1UL << 31); // issue trap 0 this->reg.trap_state = (1UL << 31); // issue trap 0
return iss::Err; return iss::Err;
} }
try { try {
if(!is_debug(access) && (addr&(alignment-1))){ if(!is_debug(access) && (addr&(alignment-1))){
this->trap_state = (1UL << 31) | 4<<16; this->reg.trap_state = (1UL << 31) | 4<<16;
fault_data=addr; fault_data=addr;
return iss::Err; return iss::Err;
} }
@ -681,12 +681,12 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
res = hart_mem_rd_delegate( phys_addr, length, data); res = hart_mem_rd_delegate( phys_addr, length, data);
} }
if (unlikely(res != iss::Ok)){ if (unlikely(res != iss::Ok)){
this->trap_state = (1UL << 31) | (5 << 16); // issue trap 5 (load access fault this->reg.trap_state = (1UL << 31) | (5 << 16); // issue trap 5 (load access fault
fault_data=addr; fault_data=addr;
} }
return res; return res;
} catch (trap_access &ta) { } catch (trap_access &ta) {
this->trap_state = (1UL << 31) | ta.id; this->reg.trap_state = (1UL << 31) | ta.id;
fault_data=ta.addr; fault_data=ta.addr;
return iss::Err; return iss::Err;
} }
@ -712,7 +712,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
} }
return iss::Ok; return iss::Ok;
} catch (trap_access &ta) { } catch (trap_access &ta) {
this->trap_state = (1UL << 31) | ta.id; this->reg.trap_state = (1UL << 31) | ta.id;
fault_data=ta.addr; fault_data=ta.addr;
return iss::Err; return iss::Err;
} }
@ -750,12 +750,12 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
if (unlikely((access && iss::access_type::FETCH) && (addr & 0x1) == 1)) { if (unlikely((access && iss::access_type::FETCH) && (addr & 0x1) == 1)) {
fault_data = addr; fault_data = addr;
if (access && iss::access_type::DEBUG) throw trap_access(0, addr); if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
this->trap_state = (1UL << 31); // issue trap 0 this->reg.trap_state = (1UL << 31); // issue trap 0
return iss::Err; return iss::Err;
} }
try { try {
if(length>1 && (addr&(length-1)) && (access&access_type::DEBUG) != access_type::DEBUG){ if(length>1 && (addr&(length-1)) && (access&access_type::DEBUG) != access_type::DEBUG){
this->trap_state = (1UL << 31) | 6<<16; this->reg.trap_state = (1UL << 31) | 6<<16;
fault_data=addr; fault_data=addr;
return iss::Err; return iss::Err;
} }
@ -774,12 +774,12 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
res = write_mem( phys_addr, length, data); res = write_mem( phys_addr, length, data);
} }
if (unlikely(res != iss::Ok)) { if (unlikely(res != iss::Ok)) {
this->trap_state = (1UL << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault) this->reg.trap_state = (1UL << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
fault_data=addr; fault_data=addr;
} }
return res; return res;
} catch (trap_access &ta) { } catch (trap_access &ta) {
this->trap_state = (1UL << 31) | ta.id; this->reg.trap_state = (1UL << 31) | ta.id;
fault_data=ta.addr; fault_data=ta.addr;
return iss::Err; return iss::Err;
} }
@ -839,7 +839,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write(const address_type type, const acc
} }
return iss::Ok; return iss::Ok;
} catch (trap_access &ta) { } catch (trap_access &ta) {
this->trap_state = (1UL << 31) | ta.id; this->reg.trap_state = (1UL << 31) | ta.id;
fault_data=ta.addr; fault_data=ta.addr;
return iss::Err; return iss::Err;
} }
@ -885,7 +885,7 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
} }
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_cycle(unsigned addr, reg_t &val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_cycle(unsigned addr, reg_t &val) {
auto cycle_val = this->icount + cycle_offset; auto cycle_val = this->reg.icount + cycle_offset;
if (addr == mcycle) { if (addr == mcycle) {
val = static_cast<reg_t>(cycle_val); val = static_cast<reg_t>(cycle_val);
} else if (addr == mcycleh) { } else if (addr == mcycleh) {
@ -904,35 +904,35 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
mcycle_csr = (static_cast<uint64_t>(val)<<32) + (mcycle_csr & 0xffffffff); mcycle_csr = (static_cast<uint64_t>(val)<<32) + (mcycle_csr & 0xffffffff);
} }
} }
cycle_offset = mcycle_csr-this->icount; // TODO: relying on wrap-around cycle_offset = mcycle_csr-this->reg.icount; // TODO: relying on wrap-around
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_instret(unsigned addr, reg_t &val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_instret(unsigned addr, reg_t &val) {
if ((addr&0xff) == (minstret&0xff)) { if ((addr&0xff) == (minstret&0xff)) {
val = static_cast<reg_t>(this->instret); val = static_cast<reg_t>(this->reg.instret);
} else if ((addr&0xff) == (minstreth&0xff)) { } else if ((addr&0xff) == (minstreth&0xff)) {
val = static_cast<reg_t>(this->instret >> 32); val = static_cast<reg_t>(this->reg.instret >> 32);
} }
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_instret(unsigned addr, reg_t val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_instret(unsigned addr, reg_t val) {
if (sizeof(typename traits<BASE>::reg_t) != 4) { if (sizeof(typename traits<BASE>::reg_t) != 4) {
this->instret = static_cast<uint64_t>(val); this->reg.instret = static_cast<uint64_t>(val);
} else { } else {
if ((addr&0xff) == (minstret&0xff)) { if ((addr&0xff) == (minstret&0xff)) {
this->instret = (this->instret & 0xffffffff00000000) + val; this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val;
} else { } else {
this->instret = (static_cast<uint64_t>(val)<<32) + (this->instret & 0xffffffff); this->reg.instret = (static_cast<uint64_t>(val)<<32) + (this->reg.instret & 0xffffffff);
} }
} }
this->instret--; this->reg.instret--;
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_time(unsigned addr, reg_t &val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_time(unsigned addr, reg_t &val) {
uint64_t time_val = this->icount / (100000000 / 32768 - 1); //-> ~3052; uint64_t time_val = this->reg.icount / (100000000 / 32768 - 1); //-> ~3052;
if (addr == time) { if (addr == time) {
val = static_cast<reg_t>(time_val); val = static_cast<reg_t>(time_val);
} else if (addr == timeh) { } else if (addr == timeh) {
@ -959,7 +959,6 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
} }
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_cause(unsigned addr, reg_t &val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::read_cause(unsigned addr, reg_t &val) {
auto res = csr[addr];
if((FEAT & features_e::FEAT_CLIC) && (csr[mtvec]&0x3)==3) { if((FEAT & features_e::FEAT_CLIC) && (csr[mtvec]&0x3)==3) {
val = csr[addr] & ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1) | (0xfUL<<16)); val = csr[addr] & ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1) | (0xfUL<<16));
val |= clic_mprev_lvl<<16; val |= clic_mprev_lvl<<16;
@ -971,7 +970,6 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>
} }
template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_cause(unsigned addr, reg_t val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_m_p<BASE, FEAT>::write_cause(unsigned addr, reg_t val) {
csr[addr] = val & ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1));
if((FEAT & features_e::FEAT_CLIC) && (csr[mtvec]&0x3)==3) { if((FEAT & features_e::FEAT_CLIC) && (csr[mtvec]&0x3)==3) {
auto mask = ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1) | (0xfUL<<16)); auto mask = ((1UL<<(traits<BASE>::XLEN-1)) | (mcause_max_irq-1) | (0xfUL<<16));
csr[addr] = (val & mask) | (csr[addr] & ~mask); csr[addr] = (val & mask) | (csr[addr] & ~mask);
@ -1074,18 +1072,6 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write_xtvt(unsigned addr, reg_t val) {
template <typename BASE, features_e FEAT> template <typename BASE, features_e FEAT>
iss::status riscv_hart_m_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) { iss::status riscv_hart_m_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
switch (paddr.val) { 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->icount > 30000) data[3] |= 0x80;
} break;
default: { default: {
for(auto offs=0U; offs<length; ++offs) { for(auto offs=0U; offs<length; ++offs) {
*(data + offs)=mem[(paddr.val+offs)%mem.size()]; *(data + offs)=mem[(paddr.val+offs)%mem.size()];
@ -1098,29 +1084,13 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned len
template <typename BASE, features_e FEAT> template <typename BASE, features_e FEAT>
iss::status riscv_hart_m_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) { iss::status riscv_hart_m_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) {
switch (paddr.val) { switch (paddr.val) {
case 0x10013000: // UART0 base, TXFIFO reg case 0xFFFF0000: // UART0 base, TXFIFO reg
case 0x10023000: // UART1 base, TXFIFO reg
uart_buf << (char)data[0];
if (((char)data[0]) == '\n' || data[0] == 0) { if (((char)data[0]) == '\n' || data[0] == 0) {
LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send '"<<uart_buf.str()<<"'"; LOG(INFO)<<"UART"<<((paddr.val>>12)&0x3)<<" send '"<<uart_buf.str()<<"'";
std::cout << uart_buf.str();
uart_buf.str(""); uart_buf.str("");
} } else if(((char)data[0]) != '\r')
uart_buf << (char)data[0];
break; 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: { default: {
mem_type::page_type &p = mem(paddr.val / mem.page_size); mem_type::page_type &p = mem(paddr.val / mem.page_size);
std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask)); std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask));
@ -1142,7 +1112,7 @@ iss::status riscv_hart_m_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned le
LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
<< "), stopping simulation"; << "), stopping simulation";
} }
this->trap_state=std::numeric_limits<uint32_t>::max(); this->reg.trap_state=std::numeric_limits<uint32_t>::max();
this->interrupt_sim=hostvar; this->interrupt_sim=hostvar;
break; break;
//throw(iss::simulation_stopped(hostvar)); //throw(iss::simulation_stopped(hostvar));
@ -1227,7 +1197,7 @@ template <typename BASE, features_e FEAT> void riscv_hart_m_p<BASE, FEAT>::check
enabled_interrupts >>= 1; enabled_interrupts >>= 1;
res++; res++;
} }
this->pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id this->reg.pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
} }
} }
@ -1275,7 +1245,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::e
fault_data = 0; fault_data = 0;
} else { } else {
csr[mepc] = this->reg.NEXT_PC & get_pc_mask(); // store next address if interrupt csr[mepc] = this->reg.NEXT_PC & get_pc_mask(); // store next address if interrupt
this->pending_trap = 0; this->reg.pending_trap = 0;
} }
csr[mcause] = (trap_id << (traits<BASE>::XLEN-1)) + cause; csr[mcause] = (trap_id << (traits<BASE>::XLEN-1)) + cause;
// update mstatus // update mstatus
@ -1305,7 +1275,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::e
} }
// reset trap state // reset trap state
this->reg.PRIV = new_priv; this->reg.PRIV = new_priv;
this->trap_state = 0; this->reg.trap_state = 0;
std::array<char, 32> buffer; std::array<char, 32> buffer;
#if defined(_MSC_VER) #if defined(_MSC_VER)
sprintf(buffer.data(), "0x%016llx", addr); sprintf(buffer.data(), "0x%016llx", addr);
@ -1326,7 +1296,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_m_p<BASE, FEAT>::l
this->reg.NEXT_PC = csr[mepc] & get_pc_mask(); this->reg.NEXT_PC = csr[mepc] & get_pc_mask();
CLOG(INFO, disass) << "Executing xRET"; CLOG(INFO, disass) << "Executing xRET";
check_interrupt(); check_interrupt();
this->trap_state = this->pending_trap; this->reg.trap_state = this->reg.pending_trap;
return this->reg.NEXT_PC; return this->reg.NEXT_PC;
} }

View File

@ -307,7 +307,7 @@ public:
void disass_output(uint64_t pc, const std::string instr) override { void disass_output(uint64_t pc, const std::string instr) override {
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]", CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]",
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->icount + cycle_offset); pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.icount + cycle_offset);
}; };
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; } iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
@ -316,6 +316,9 @@ public:
csr[addr & csr.page_addr_mask] = val; csr[addr & csr.page_addr_mask] = val;
} }
void set_irq_num(unsigned i) {
mcause_max_irq=1<<util::ilog2(i);
}
protected: protected:
struct riscv_instrumentation_if : public iss::instrumentation_if { struct riscv_instrumentation_if : public iss::instrumentation_if {
@ -328,21 +331,21 @@ protected:
*/ */
const std::string core_type_name() const override { return traits<BASE>::core_type; } const std::string core_type_name() const override { return traits<BASE>::core_type; }
virtual uint64_t get_pc() { return arch.get_pc(); }; uint64_t get_pc() override { return arch.reg.PC; };
virtual uint64_t get_next_pc() { return arch.get_next_pc(); }; uint64_t get_next_pc() override { return arch.reg.NEXT_PC; };
uint64_t get_instr_word() override { return arch.instruction; } uint64_t get_instr_word() override { return arch.reg.instruction; }
uint64_t get_instr_count() { return arch.icount; } uint64_t get_instr_count() override { return arch.reg.icount; }
uint64_t get_pendig_traps() override { return arch.trap_state; } uint64_t get_pendig_traps() override { return arch.reg.trap_state; }
uint64_t get_total_cycles() override { return arch.icount + arch.cycle_offset; } uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; }; void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; };
bool is_branch_taken() override { return arch.last_branch; }; bool is_branch_taken() override { return arch.reg.last_branch; };
riscv_hart_msu_vp<BASE> &arch; riscv_hart_msu_vp<BASE> &arch;
}; };
@ -381,16 +384,17 @@ protected:
std::unordered_map<unsigned, rd_csr_f> csr_rd_cb; std::unordered_map<unsigned, rd_csr_f> csr_rd_cb;
std::unordered_map<unsigned, wr_csr_f> csr_wr_cb; std::unordered_map<unsigned, wr_csr_f> csr_wr_cb;
private: std::vector<uint8_t> tcm;
iss::status read_reg(unsigned addr, reg_t &val);
iss::status write_reg(unsigned addr, reg_t val); iss::status read_csr_reg(unsigned addr, reg_t &val);
iss::status write_csr_reg(unsigned addr, reg_t val);
iss::status read_null(unsigned addr, reg_t &val); iss::status read_null(unsigned addr, reg_t &val);
iss::status write_null(unsigned addr, reg_t val){return iss::status::Ok;} iss::status write_null(unsigned addr, reg_t val){return iss::status::Ok;}
iss::status read_cycle(unsigned addr, reg_t &val); iss::status read_cycle(unsigned addr, reg_t &val);
iss::status write_cycle(unsigned addr, reg_t val); iss::status write_cycle(unsigned addr, reg_t val);
iss::status read_instret(unsigned addr, reg_t &val); iss::status read_instret(unsigned addr, reg_t &val);
iss::status write_instret(unsigned addr, reg_t val); iss::status write_instret(unsigned addr, reg_t val);
iss::status read_mtvec(unsigned addr, reg_t &val); iss::status read_tvec(unsigned addr, reg_t &val);
iss::status read_time(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 read_status(unsigned addr, reg_t &val);
iss::status write_status(unsigned addr, reg_t val); iss::status write_status(unsigned addr, reg_t val);
@ -398,6 +402,8 @@ private:
iss::status read_ie(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 write_ie(unsigned addr, reg_t val);
iss::status read_ip(unsigned addr, reg_t &val); iss::status read_ip(unsigned addr, reg_t &val);
iss::status write_ideleg(unsigned addr, reg_t val);
iss::status write_edeleg(unsigned addr, reg_t val);
iss::status read_hartid(unsigned addr, reg_t &val); iss::status read_hartid(unsigned addr, reg_t &val);
iss::status write_epc(unsigned addr, reg_t val); iss::status write_epc(unsigned addr, reg_t val);
iss::status read_satp(unsigned addr, reg_t &val); iss::status read_satp(unsigned addr, reg_t &val);
@ -417,7 +423,6 @@ private:
reg_t mhartid_reg{0x0}; reg_t mhartid_reg{0x0};
protected:
void check_interrupt(); void check_interrupt();
}; };
@ -434,22 +439,22 @@ riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp()
uart_buf.str(""); uart_buf.str("");
for (unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr){ for (unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr){
csr_rd_cb[addr] = &this_class::read_null; csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg; csr_wr_cb[addr] = &this_class::write_csr_reg;
} }
for (unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr){ for (unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr){
csr_rd_cb[addr] = &this_class::read_null; csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg; csr_wr_cb[addr] = &this_class::write_csr_reg;
} }
for (unsigned addr = mhpmevent3; addr <= mhpmevent31; ++addr){ for (unsigned addr = mhpmevent3; addr <= mhpmevent31; ++addr){
csr_rd_cb[addr] = &this_class::read_null; csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg; csr_wr_cb[addr] = &this_class::write_csr_reg;
} }
for (unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr){ for (unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr){
csr_rd_cb[addr] = &this_class::read_null; csr_rd_cb[addr] = &this_class::read_null;
} }
for (unsigned addr = cycleh; addr <= hpmcounter31h; ++addr){ for (unsigned addr = cycleh; addr <= hpmcounter31h; ++addr){
csr_rd_cb[addr] = &this_class::read_null; csr_rd_cb[addr] = &this_class::read_null;
//csr_wr_cb[addr] = &this_class::write_reg; //csr_wr_cb[addr] = &this_class::write_csr_reg;
} }
// common regs // common regs
const std::array<unsigned, 22> addrs{{ const std::array<unsigned, 22> addrs{{
@ -459,25 +464,25 @@ riscv_hart_msu_vp<BASE>::riscv_hart_msu_vp()
uepc, utvec, uscratch, ucause, utval, uscratch uepc, utvec, uscratch, ucause, utval, uscratch
}}; }};
for(auto addr: addrs) { for(auto addr: addrs) {
csr_rd_cb[addr] = &this_class::read_reg; csr_rd_cb[addr] = &this_class::read_csr_reg;
csr_wr_cb[addr] = &this_class::write_reg; csr_wr_cb[addr] = &this_class::write_csr_reg;
} }
// special handling & overrides // special handling & overrides
csr_rd_cb[time] = &this_class::read_time; csr_rd_cb[time] = &this_class::read_time;
csr_rd_cb[timeh] = &this_class::read_time; if(traits<BASE>::XLEN==32) csr_rd_cb[timeh] = &this_class::read_time;
csr_rd_cb[cycle] = &this_class::read_cycle; csr_rd_cb[cycle] = &this_class::read_cycle;
csr_rd_cb[cycleh] = &this_class::read_cycle; if(traits<BASE>::XLEN==32) csr_rd_cb[cycleh] = &this_class::read_cycle;
csr_rd_cb[instret] = &this_class::read_instret; csr_rd_cb[instret] = &this_class::read_instret;
csr_rd_cb[instreth] = &this_class::read_instret; if(traits<BASE>::XLEN==32) csr_rd_cb[instreth] = &this_class::read_instret;
csr_rd_cb[mcycle] = &this_class::read_cycle; csr_rd_cb[mcycle] = &this_class::read_cycle;
csr_wr_cb[mcycle] = &this_class::write_cycle; csr_wr_cb[mcycle] = &this_class::write_cycle;
csr_rd_cb[mcycleh] = &this_class::read_cycle; if(traits<BASE>::XLEN==32) csr_rd_cb[mcycleh] = &this_class::read_cycle;
csr_wr_cb[mcycleh] = &this_class::write_cycle; if(traits<BASE>::XLEN==32) csr_wr_cb[mcycleh] = &this_class::write_cycle;
csr_rd_cb[minstret] = &this_class::read_instret; csr_rd_cb[minstret] = &this_class::read_instret;
csr_wr_cb[minstret] = &this_class::write_instret; csr_wr_cb[minstret] = &this_class::write_instret;
csr_rd_cb[minstreth] = &this_class::read_instret; if(traits<BASE>::XLEN==32) csr_rd_cb[minstreth] = &this_class::read_instret;
csr_wr_cb[minstreth] = &this_class::write_instret; if(traits<BASE>::XLEN==32) csr_wr_cb[minstreth] = &this_class::write_instret;
csr_rd_cb[mstatus] = &this_class::read_status; csr_rd_cb[mstatus] = &this_class::read_status;
csr_wr_cb[mstatus] = &this_class::write_status; csr_wr_cb[mstatus] = &this_class::write_status;
csr_wr_cb[mcause] = &this_class::write_cause; csr_wr_cb[mcause] = &this_class::write_cause;
@ -527,10 +532,10 @@ template <typename BASE> std::pair<uint64_t, bool> riscv_hart_msu_vp<BASE>::load
if (fp) { if (fp) {
std::array<char, 5> buf; std::array<char, 5> buf;
auto n = fread(buf.data(), 1, 4, fp); auto n = fread(buf.data(), 1, 4, fp);
fclose(fp);
if (n != 4) throw std::runtime_error("input file has insufficient size"); if (n != 4) throw std::runtime_error("input file has insufficient size");
buf[4] = 0; buf[4] = 0;
if (strcmp(buf.data() + 1, "ELF") == 0) { if (strcmp(buf.data() + 1, "ELF") == 0) {
fclose(fp);
// Create elfio reader // Create elfio reader
ELFIO::elfio reader; ELFIO::elfio reader;
// Load ELF data // Load ELF data
@ -549,7 +554,7 @@ template <typename BASE> std::pair<uint64_t, bool> riscv_hart_msu_vp<BASE>::load
traits<BASE>::MEM, pseg->get_physical_address(), traits<BASE>::MEM, pseg->get_physical_address(),
fsize, reinterpret_cast<const uint8_t *const>(seg_data)); fsize, reinterpret_cast<const uint8_t *const>(seg_data));
if (res != iss::Ok) if (res != iss::Ok)
LOG(ERROR) << "problem writing " << fsize << "bytes to 0x" << std::hex LOG(ERR) << "problem writing " << fsize << "bytes to 0x" << std::hex
<< pseg->get_physical_address(); << pseg->get_physical_address();
} }
} }
@ -583,9 +588,9 @@ template <typename BASE> std::pair<uint64_t, bool> riscv_hart_msu_vp<BASE>::load
} }
return std::make_pair(entry, true); return std::make_pair(entry, true);
} }
throw std::runtime_error("memory load file is not a valid elf file"); throw std::runtime_error(fmt::format("memory load file {} is not a valid elf file",name));
} }
throw std::runtime_error("memory load file not found"); throw std::runtime_error(fmt::format("memory load file not found, check if {} is a valid file", name));
} }
template <typename BASE> template <typename BASE>
@ -607,12 +612,12 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
if (unlikely(is_fetch(access) && (addr&(alignment-1)))) { if (unlikely(is_fetch(access) && (addr&(alignment-1)))) {
fault_data = addr; fault_data = addr;
if (access && iss::access_type::DEBUG) throw trap_access(0, addr); if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
this->trap_state = (1 << 31); // issue trap 0 this->reg.trap_state = (1 << 31); // issue trap 0
return iss::Err; return iss::Err;
} }
try { try {
if(!is_debug(access) && (addr&(alignment-1))){ if(!is_debug(access) && (addr&(alignment-1))){
this->trap_state = 1<<31 | 4<<16; this->reg.trap_state = 1<<31 | 4<<16;
fault_data=addr; fault_data=addr;
return iss::Err; return iss::Err;
} }
@ -631,12 +636,12 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
read_mem( BASE::v2p(phys_addr_t{access, space, addr}), length, data): read_mem( BASE::v2p(phys_addr_t{access, space, addr}), length, data):
read_mem( BASE::v2p(iss::addr_t{access, type, space, addr}), length, data); read_mem( BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
if (unlikely(res != iss::Ok)){ if (unlikely(res != iss::Ok)){
this->trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
fault_data=addr; fault_data=addr;
} }
return res; return res;
} catch (trap_access &ta) { } catch (trap_access &ta) {
this->trap_state = (1 << 31) | ta.id; this->reg.trap_state = (1 << 31) | ta.id;
fault_data=ta.addr; fault_data=ta.addr;
return iss::Err; return iss::Err;
} }
@ -652,7 +657,7 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
case 3: { // SFENCE:VMA upper case 3: { // SFENCE:VMA upper
auto tvm = state.mstatus.TVM; auto tvm = state.mstatus.TVM;
if (this->reg.PRIV == PRIV_S & tvm != 0) { if (this->reg.PRIV == PRIV_S & tvm != 0) {
this->trap_state = (1 << 31) | (2 << 16); this->reg.trap_state = (1 << 31) | (2 << 16);
this->fault_data = this->reg.PC; this->fault_data = this->reg.PC;
return iss::Err; return iss::Err;
} }
@ -673,7 +678,7 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
} }
return iss::Ok; return iss::Ok;
} catch (trap_access &ta) { } catch (trap_access &ta) {
this->trap_state = (1 << 31) | ta.id; this->reg.trap_state = (1UL << 31) | ta.id;
fault_data=ta.addr; fault_data=ta.addr;
return iss::Err; return iss::Err;
} }
@ -711,7 +716,7 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
if (unlikely((access && iss::access_type::FETCH) && (addr & 0x1) == 1)) { if (unlikely((access && iss::access_type::FETCH) && (addr & 0x1) == 1)) {
fault_data = addr; fault_data = addr;
if (access && iss::access_type::DEBUG) throw trap_access(0, addr); if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
this->trap_state = (1 << 31); // issue trap 0 this->reg.trap_state = (1 << 31); // issue trap 0
return iss::Err; return iss::Err;
} }
try { try {
@ -730,12 +735,12 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
write_mem(phys_addr_t{access, space, addr}, length, data): write_mem(phys_addr_t{access, space, addr}, length, data):
write_mem(BASE::v2p(iss::addr_t{access, type, space, addr}), length, data); write_mem(BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
if (unlikely(res != iss::Ok)) { if (unlikely(res != iss::Ok)) {
this->trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault) this->reg.trap_state = (1UL << 31) | (7UL << 16); // issue trap 7 (Store/AMO access fault)
fault_data=addr; fault_data=addr;
} }
return res; return res;
} catch (trap_access &ta) { } catch (trap_access &ta) {
this->trap_state = (1 << 31) | ta.id; this->reg.trap_state = (1UL << 31) | ta.id;
fault_data=ta.addr; fault_data=ta.addr;
return iss::Err; return iss::Err;
} }
@ -784,7 +789,7 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
ptw.clear(); ptw.clear();
auto tvm = state.mstatus.TVM; auto tvm = state.mstatus.TVM;
if (this->reg.PRIV == PRIV_S & tvm != 0) { if (this->reg.PRIV == PRIV_S & tvm != 0) {
this->trap_state = (1 << 31) | (2 << 16); this->reg.trap_state = (1 << 31) | (2 << 16);
this->fault_data = this->reg.PC; this->fault_data = this->reg.PC;
return iss::Err; return iss::Err;
} }
@ -800,7 +805,7 @@ iss::status riscv_hart_msu_vp<BASE>::write(const address_type type, const access
} }
return iss::Ok; return iss::Ok;
} catch (trap_access &ta) { } catch (trap_access &ta) {
this->trap_state = (1 << 31) | ta.id; this->reg.trap_state = (1UL << 31) | ta.id;
fault_data=ta.addr; fault_data=ta.addr;
return iss::Err; return iss::Err;
} }
@ -846,7 +851,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_reg(unsigned
} }
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_cycle(unsigned addr, reg_t &val) { template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_cycle(unsigned addr, reg_t &val) {
auto cycle_val = this->icount + cycle_offset; auto cycle_val = this->reg.icount + cycle_offset;
if (addr == mcycle) { if (addr == mcycle) {
val = static_cast<reg_t>(cycle_val); val = static_cast<reg_t>(cycle_val);
} else if (addr == mcycleh) { } else if (addr == mcycleh) {
@ -858,8 +863,6 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_cycle(unsigne
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_cycle(unsigned addr, reg_t val) { template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_cycle(unsigned addr, reg_t val) {
if (sizeof(typename traits<BASE>::reg_t) != 4) { if (sizeof(typename traits<BASE>::reg_t) != 4) {
if (addr == mcycleh)
return iss::Err;
mcycle_csr = static_cast<uint64_t>(val); mcycle_csr = static_cast<uint64_t>(val);
} else { } else {
if (addr == mcycle) { if (addr == mcycle) {
@ -868,7 +871,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_cycle(unsign
mcycle_csr = (static_cast<uint64_t>(val)<<32) + (mcycle_csr & 0xffffffff); mcycle_csr = (static_cast<uint64_t>(val)<<32) + (mcycle_csr & 0xffffffff);
} }
} }
cycle_offset = mcycle_csr-this->icount; // TODO: relying on wrap-around cycle_offset = mcycle_csr-this->reg.icount; // TODO: relying on wrap-around
return iss::Ok; return iss::Ok;
} }
@ -876,7 +879,6 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_instret(unsig
if ((addr&0xff) == (minstret&0xff)) { if ((addr&0xff) == (minstret&0xff)) {
val = static_cast<reg_t>(this->reg.instret); val = static_cast<reg_t>(this->reg.instret);
} else if ((addr&0xff) == (minstreth&0xff)) { } else if ((addr&0xff) == (minstreth&0xff)) {
if (sizeof(typename traits<BASE>::reg_t) != 4) return iss::Err;
val = static_cast<reg_t>(this->reg.instret >> 32); val = static_cast<reg_t>(this->reg.instret >> 32);
} }
return iss::Ok; return iss::Ok;
@ -884,8 +886,6 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_instret(unsig
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_instret(unsigned addr, reg_t val) { template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_instret(unsigned addr, reg_t val) {
if (sizeof(typename traits<BASE>::reg_t) != 4) { if (sizeof(typename traits<BASE>::reg_t) != 4) {
if ((addr&0xff) == (minstreth&0xff))
return iss::Err;
this->reg.instret = static_cast<uint64_t>(val); this->reg.instret = static_cast<uint64_t>(val);
} else { } else {
if ((addr&0xff) == (minstret&0xff)) { if ((addr&0xff) == (minstret&0xff)) {
@ -899,7 +899,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_instret(unsi
} }
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_time(unsigned addr, reg_t &val) { template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_time(unsigned addr, reg_t &val) {
uint64_t time_val = this->icount / (100000000 / 32768 - 1); //-> ~3052; uint64_t time_val = this->reg.icount / (100000000 / 32768 - 1); //-> ~3052;
if (addr == time) { if (addr == time) {
val = static_cast<reg_t>(time_val); val = static_cast<reg_t>(time_val);
} else if (addr == timeh) { } else if (addr == timeh) {
@ -968,7 +968,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_epc(unsigned
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_satp(unsigned addr, reg_t &val) { template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_satp(unsigned addr, reg_t &val) {
reg_t tvm = state.mstatus.TVM; reg_t tvm = state.mstatus.TVM;
if (this->reg.PRIV == PRIV_S & tvm != 0) { if (this->reg.PRIV == PRIV_S & tvm != 0) {
this->trap_state = (1 << 31) | (2 << 16); this->reg.trap_state = (1 << 31) | (2 << 16);
this->fault_data = this->reg.PC; this->fault_data = this->reg.PC;
return iss::Err; return iss::Err;
} }
@ -979,7 +979,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_satp(unsigned
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_satp(unsigned addr, reg_t val) { template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_satp(unsigned addr, reg_t val) {
reg_t tvm = state.mstatus.TVM; reg_t tvm = state.mstatus.TVM;
if (this->reg.PRIV == PRIV_S & tvm != 0) { if (this->reg.PRIV == PRIV_S & tvm != 0) {
this->trap_state = (1 << 31) | (2 << 16); this->reg.trap_state = (1 << 31) | (2 << 16);
this->fault_data = this->reg.PC; this->fault_data = this->reg.PC;
return iss::Err; return iss::Err;
} }
@ -1024,18 +1024,6 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_fcsr(unsigne
template <typename BASE> template <typename BASE>
iss::status riscv_hart_msu_vp<BASE>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) { iss::status riscv_hart_msu_vp<BASE>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
switch (paddr.val) { 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->icount > 30000) data[3] |= 0x80;
} break;
default: { default: {
for(auto offs=0U; offs<length; ++offs) { for(auto offs=0U; offs<length; ++offs) {
*(data + offs)=mem[(paddr.val+offs)%mem.size()]; *(data + offs)=mem[(paddr.val+offs)%mem.size()];
@ -1048,30 +1036,13 @@ iss::status riscv_hart_msu_vp<BASE>::read_mem(phys_addr_t paddr, unsigned length
template <typename BASE> template <typename BASE>
iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) { iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) {
switch (paddr.val) { switch (paddr.val) {
case 0x10013000: // UART0 base, TXFIFO reg case 0xFFFF0000: // UART0 base, TXFIFO reg
case 0x10023000: // UART1 base, TXFIFO reg
uart_buf << (char)data[0];
if (((char)data[0]) == '\n' || data[0] == 0) { if (((char)data[0]) == '\n' || data[0] == 0) {
// LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send LOG(INFO)<<"UART"<<((paddr.val>>12)&0x3)<<" send '"<<uart_buf.str()<<"'";
// '"<<uart_buf.str()<<"'";
std::cout << uart_buf.str();
uart_buf.str(""); uart_buf.str("");
} } else if(((char)data[0]) != '\r')
uart_buf << (char)data[0];
break; 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: { default: {
mem_type::page_type &p = mem(paddr.val / mem.page_size); mem_type::page_type &p = mem(paddr.val / mem.page_size);
std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask)); std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask));
@ -1093,7 +1064,7 @@ iss::status riscv_hart_msu_vp<BASE>::write_mem(phys_addr_t paddr, unsigned lengt
LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
<< "), stopping simulation"; << "), stopping simulation";
} }
this->trap_state=std::numeric_limits<uint32_t>::max(); this->reg.trap_state=std::numeric_limits<uint32_t>::max();
this->interrupt_sim=hostvar; this->interrupt_sim=hostvar;
break; break;
//throw(iss::simulation_stopped(hostvar)); //throw(iss::simulation_stopped(hostvar));
@ -1162,7 +1133,7 @@ template <typename BASE> void riscv_hart_msu_vp<BASE>::check_interrupt() {
if (enabled_interrupts != 0) { if (enabled_interrupts != 0) {
int res = 0; int res = 0;
while ((enabled_interrupts & 1) == 0) enabled_interrupts >>= 1, res++; while ((enabled_interrupts & 1) == 0) enabled_interrupts >>= 1, res++;
this->pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id this->reg.pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
} }
} }
@ -1263,6 +1234,7 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f
auto cur_priv = this->reg.PRIV; auto cur_priv = this->reg.PRIV;
// flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0] // flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0]
// calculate and write mcause val // calculate and write mcause val
if(flags==std::numeric_limits<uint64_t>::max()) flags=this->reg.trap_state;
auto trap_id = bit_sub<0, 16>(flags); auto trap_id = bit_sub<0, 16>(flags);
auto cause = bit_sub<16, 15>(flags); auto cause = bit_sub<16, 15>(flags);
if (trap_id == 0 && cause == 11) cause = 0x8 + cur_priv; // adjust environment call cause if (trap_id == 0 && cause == 11) cause = 0x8 + cur_priv; // adjust environment call cause
@ -1306,7 +1278,7 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f
if (cur_priv != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0) if (cur_priv != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0)
new_priv = (csr[sideleg] >> cause) & 0x1 ? PRIV_U : PRIV_S; new_priv = (csr[sideleg] >> cause) & 0x1 ? PRIV_U : PRIV_S;
csr[uepc | (new_priv << 8)] = this->reg.NEXT_PC; // store next address if interrupt csr[uepc | (new_priv << 8)] = this->reg.NEXT_PC; // store next address if interrupt
this->pending_trap = 0; this->reg.pending_trap = 0;
} }
size_t adr = ucause | (new_priv << 8); size_t adr = ucause | (new_priv << 8);
csr[adr] = (trap_id << 31) + cause; csr[adr] = (trap_id << 31) + cause;
@ -1351,7 +1323,7 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::enter_trap(uint64_t f
<< lvl[cur_priv] << " to " << lvl[new_priv]; << lvl[cur_priv] << " to " << lvl[new_priv];
// reset trap state // reset trap state
this->reg.PRIV = new_priv; this->reg.PRIV = new_priv;
this->trap_state = 0; this->reg.trap_state = 0;
update_vm_info(); update_vm_info();
return this->reg.NEXT_PC; return this->reg.NEXT_PC;
} }
@ -1363,7 +1335,7 @@ template <typename BASE> uint64_t riscv_hart_msu_vp<BASE>::leave_trap(uint64_t f
auto tsr = state.mstatus.TSR; auto tsr = state.mstatus.TSR;
if (cur_priv == PRIV_S && inst_priv == PRIV_S && tsr != 0) { if (cur_priv == PRIV_S && inst_priv == PRIV_S && tsr != 0) {
this->trap_state = (1 << 31) | (2 << 16); this->reg.trap_state = (1 << 31) | (2 << 16);
this->fault_data = this->reg.PC; this->fault_data = this->reg.PC;
return this->reg.PC; return this->reg.PC;
} }
@ -1402,7 +1374,7 @@ template <typename BASE> void riscv_hart_msu_vp<BASE>::wait_until(uint64_t flags
auto status = state.mstatus; auto status = state.mstatus;
auto tw = status.TW; auto tw = status.TW;
if (this->reg.PRIV == PRIV_S && tw != 0) { if (this->reg.PRIV == PRIV_S && tw != 0) {
this->trap_state = (1 << 31) | (2 << 16); this->reg.trap_state = (1 << 31) | (2 << 16);
this->fault_data = this->reg.PC; this->fault_data = this->reg.PC;
} }
} }

View File

@ -284,6 +284,7 @@ public:
} }
riscv_hart_mu_p(feature_config cfg = feature_config{}); riscv_hart_mu_p(feature_config cfg = feature_config{});
virtual ~riscv_hart_mu_p() = default; virtual ~riscv_hart_mu_p() = default;
void reset(uint64_t address) override; void reset(uint64_t address) override;
@ -304,7 +305,7 @@ public:
void disass_output(uint64_t pc, const std::string instr) override { void disass_output(uint64_t pc, const std::string instr) override {
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]", CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]",
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->icount + cycle_offset); pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.icount + cycle_offset);
}; };
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; } iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
@ -332,17 +333,17 @@ protected:
uint64_t get_next_pc() override { return arch.reg.NEXT_PC; }; uint64_t get_next_pc() override { return arch.reg.NEXT_PC; };
uint64_t get_instr_word() override { return arch.instruction; } uint64_t get_instr_word() override { return arch.reg.instruction; }
uint64_t get_instr_count() override { return arch.icount; } uint64_t get_instr_count() override { return arch.reg.icount; }
uint64_t get_pendig_traps() override { return arch.trap_state; } uint64_t get_pendig_traps() override { return arch.reg.trap_state; }
uint64_t get_total_cycles() override { return arch.icount + arch.cycle_offset; } uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; }; void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; };
bool is_branch_taken() override { return arch.last_branch; }; bool is_branch_taken() override { return arch.reg.last_branch; };
riscv_hart_mu_p<BASE, FEAT> &arch; riscv_hart_mu_p<BASE, FEAT> &arch;
}; };
@ -446,7 +447,7 @@ protected:
std::vector<std::function<mem_write_f>> memfn_write; std::vector<std::function<mem_write_f>> memfn_write;
void insert_mem_range(uint64_t, uint64_t, std::function<mem_read_f>, std::function<mem_write_f>); void insert_mem_range(uint64_t, uint64_t, std::function<mem_read_f>, std::function<mem_write_f>);
feature_config cfg; feature_config cfg;
unsigned mcause_max_irq{(FEAT&features_e::FEAT_CLIC)?4096:16}; uint64_t mcause_max_irq{(FEAT&features_e::FEAT_CLIC)?4096:16};
inline bool debug_mode_active() {return this->reg.PRIV&0x4;} inline bool debug_mode_active() {return this->reg.PRIV&0x4;}
std::pair<std::function<mem_read_f>, std::function<mem_write_f>> std::pair<std::function<mem_read_f>, std::function<mem_write_f>>
@ -689,9 +690,9 @@ template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m
} }
return std::make_pair(entry, true); return std::make_pair(entry, true);
} }
throw std::runtime_error("memory load file is not a valid elf file"); throw std::runtime_error(fmt::format("memory load file {} is not a valid elf file",name));
} }
throw std::runtime_error("memory load file not found"); throw std::runtime_error(fmt::format("memory load file not found, check if {} is a valid file", name));
} }
template<typename BASE, features_e FEAT> template<typename BASE, features_e FEAT>
@ -803,7 +804,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
#ifndef NDEBUG #ifndef NDEBUG
if (access && iss::access_type::DEBUG) { if (access && iss::access_type::DEBUG) {
LOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr; LOG(TRACEALL) << "debug read of " << length << " bytes @addr 0x" << std::hex << addr;
} else if(access && iss::access_type::FETCH){ } else if(is_fetch(access)){
LOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr; LOG(TRACEALL) << "fetch of " << length << " bytes @addr 0x" << std::hex << addr;
} else { } else {
LOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr; LOG(TRACE) << "read of " << length << " bytes @addr 0x" << std::hex << addr;
@ -816,7 +817,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
if(!pmp_check(access, addr, length) && !is_debug(access)) { if(!pmp_check(access, addr, length) && !is_debug(access)) {
fault_data = addr; fault_data = addr;
if (is_debug(access)) throw trap_access(0, addr); if (is_debug(access)) throw trap_access(0, addr);
this->trap_state = (1UL << 31) | ((access==access_type::FETCH?1:5) << 16); // issue trap 1 this->reg.trap_state = (1UL << 31) | ((access==access_type::FETCH?1:5) << 16); // issue trap 1
return iss::Err; return iss::Err;
} }
} }
@ -824,18 +825,18 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
if (unlikely(is_fetch(access) && (addr&(alignment-1)))) { if (unlikely(is_fetch(access) && (addr&(alignment-1)))) {
fault_data = addr; fault_data = addr;
if (is_debug(access)) throw trap_access(0, addr); if (is_debug(access)) throw trap_access(0, addr);
this->trap_state = (1UL << 31); // issue trap 0 this->reg.trap_state = (1UL << 31); // issue trap 0
return iss::Err; return iss::Err;
} }
try { try {
if(!is_debug(access) && (addr&(alignment-1))){ if(!is_debug(access) && (addr&(alignment-1))){
this->trap_state = (1UL << 31) | 4<<16; this->reg.trap_state = (1UL << 31) | 4<<16;
fault_data=addr; fault_data=addr;
return iss::Err; return iss::Err;
} }
auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr}); auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
auto res = iss::Err; auto res = iss::Err;
if(access != access_type::FETCH && memfn_range.size()){ if(!is_fetch(access) && memfn_range.size()){
auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){ auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){
return std::get<0>(a)<=phys_addr.val && (std::get<0>(a)+std::get<1>(a))>phys_addr.val; return std::get<0>(a)<=phys_addr.val && (std::get<0>(a)+std::get<1>(a))>phys_addr.val;
}); });
@ -848,12 +849,12 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
res = hart_mem_rd_delegate( phys_addr, length, data); res = hart_mem_rd_delegate( phys_addr, length, data);
} }
if (unlikely(res != iss::Ok)){ if (unlikely(res != iss::Ok)){
this->trap_state = (1UL << 31) | (5 << 16); // issue trap 5 (load access fault this->reg.trap_state = (1UL << 31) | (5 << 16); // issue trap 5 (load access fault
fault_data=addr; fault_data=addr;
} }
return res; return res;
} catch (trap_access &ta) { } catch (trap_access &ta) {
this->trap_state = (1UL << 31) | ta.id; this->reg.trap_state = (1UL << 31) | ta.id;
fault_data=ta.addr; fault_data=ta.addr;
return iss::Err; return iss::Err;
} }
@ -879,7 +880,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
} }
return iss::Ok; return iss::Ok;
} catch (trap_access &ta) { } catch (trap_access &ta) {
this->trap_state = (1UL << 31) | ta.id; this->reg.trap_state = (1UL << 31) | ta.id;
fault_data=ta.addr; fault_data=ta.addr;
return iss::Err; return iss::Err;
} }
@ -918,25 +919,25 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
if(!pmp_check(access, addr, length) && (access&access_type::DEBUG) != access_type::DEBUG) { if(!pmp_check(access, addr, length) && (access&access_type::DEBUG) != access_type::DEBUG) {
fault_data = addr; fault_data = addr;
if (access && iss::access_type::DEBUG) throw trap_access(0, addr); if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
this->trap_state = (1UL << 31) | (7 << 16); // issue trap 1 this->reg.trap_state = (1UL << 31) | (7 << 16); // issue trap 1
return iss::Err; return iss::Err;
} }
} }
if (unlikely((access && iss::access_type::FETCH) && (addr & 0x1) == 1)) { if (unlikely(is_fetch(access) && (addr & 0x1) == 1)) {
fault_data = addr; fault_data = addr;
if (access && iss::access_type::DEBUG) throw trap_access(0, addr); if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
this->trap_state = (1UL << 31); // issue trap 0 this->reg.trap_state = (1UL << 31); // issue trap 0
return iss::Err; return iss::Err;
} }
try { try {
if(length>1 && (addr&(length-1)) && (access&access_type::DEBUG) != access_type::DEBUG){ if(length>1 && (addr&(length-1)) && (access&access_type::DEBUG) != access_type::DEBUG){
this->trap_state = (1UL << 31) | 6<<16; this->reg.trap_state = (1UL << 31) | 6<<16;
fault_data=addr; fault_data=addr;
return iss::Err; return iss::Err;
} }
auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr}); auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
auto res = iss::Err; auto res = iss::Err;
if(access != access_type::FETCH && memfn_range.size()){ if(!is_fetch(access) && memfn_range.size()){
auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){ auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){
return std::get<0>(a)<=phys_addr.val && (std::get<0>(a)+std::get<1>(a))>phys_addr.val; return std::get<0>(a)<=phys_addr.val && (std::get<0>(a)+std::get<1>(a))>phys_addr.val;
}); });
@ -949,12 +950,12 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
res = hart_mem_wr_delegate( phys_addr, length, data); res = hart_mem_wr_delegate( phys_addr, length, data);
} }
if (unlikely(res != iss::Ok)) { if (unlikely(res != iss::Ok)) {
this->trap_state = (1UL << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault) this->reg.trap_state = (1UL << 31) | (7UL << 16); // issue trap 7 (Store/AMO access fault)
fault_data=addr; fault_data=addr;
} }
return res; return res;
} catch (trap_access &ta) { } catch (trap_access &ta) {
this->trap_state = (1UL << 31) | ta.id; this->reg.trap_state = (1UL << 31) | ta.id;
fault_data=ta.addr; fault_data=ta.addr;
return iss::Err; return iss::Err;
} }
@ -1014,7 +1015,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
} }
return iss::Ok; return iss::Ok;
} catch (trap_access &ta) { } catch (trap_access &ta) {
this->trap_state = (1UL << 31) | ta.id; this->reg.trap_state = (1UL << 31) | ta.id;
fault_data=ta.addr; fault_data=ta.addr;
return iss::Err; return iss::Err;
} }
@ -1060,7 +1061,7 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
} }
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_cycle(unsigned addr, reg_t &val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_cycle(unsigned addr, reg_t &val) {
auto cycle_val = this->icount + cycle_offset; auto cycle_val = this->reg.icount + cycle_offset;
if (addr == mcycle) { if (addr == mcycle) {
val = static_cast<reg_t>(cycle_val); val = static_cast<reg_t>(cycle_val);
} else if (addr == mcycleh) { } else if (addr == mcycleh) {
@ -1079,35 +1080,35 @@ template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT
mcycle_csr = (static_cast<uint64_t>(val)<<32) + (mcycle_csr & 0xffffffff); mcycle_csr = (static_cast<uint64_t>(val)<<32) + (mcycle_csr & 0xffffffff);
} }
} }
cycle_offset = mcycle_csr-this->icount; // TODO: relying on wrap-around cycle_offset = mcycle_csr-this->reg.icount; // TODO: relying on wrap-around
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_instret(unsigned addr, reg_t &val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_instret(unsigned addr, reg_t &val) {
if ((addr&0xff) == (minstret&0xff)) { if ((addr&0xff) == (minstret&0xff)) {
val = static_cast<reg_t>(this->instret); val = static_cast<reg_t>(this->reg.instret);
} else if ((addr&0xff) == (minstreth&0xff)) { } else if ((addr&0xff) == (minstreth&0xff)) {
val = static_cast<reg_t>(this->instret >> 32); val = static_cast<reg_t>(this->reg.instret >> 32);
} }
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_instret(unsigned addr, reg_t val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_instret(unsigned addr, reg_t val) {
if (sizeof(typename traits<BASE>::reg_t) != 4) { if (sizeof(typename traits<BASE>::reg_t) != 4) {
this->instret = static_cast<uint64_t>(val); this->reg.instret = static_cast<uint64_t>(val);
} else { } else {
if ((addr&0xff) == (minstret&0xff)) { if ((addr&0xff) == (minstret&0xff)) {
this->instret = (this->instret & 0xffffffff00000000) + val; this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val;
} else { } else {
this->instret = (static_cast<uint64_t>(val)<<32) + (this->instret & 0xffffffff); this->reg.instret = (static_cast<uint64_t>(val)<<32) + (this->reg.instret & 0xffffffff);
} }
} }
this->instret--; this->reg.instret--;
return iss::Ok; return iss::Ok;
} }
template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_time(unsigned addr, reg_t &val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_time(unsigned addr, reg_t &val) {
uint64_t time_val = this->icount / (100000000 / 32768 - 1); //-> ~3052; uint64_t time_val = this->reg.icount / (100000000 / 32768 - 1); //-> ~3052;
if (addr == time) { if (addr == time) {
val = static_cast<reg_t>(time_val); val = static_cast<reg_t>(time_val);
} else if (addr == timeh) { } else if (addr == timeh) {
@ -1283,18 +1284,6 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write_xtvt(unsigned addr, reg_t val) {
template <typename BASE, features_e FEAT> 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) { iss::status riscv_hart_mu_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
switch (paddr.val) { 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->icount > 30000) data[3] |= 0x80;
} break;
default: { default: {
for(auto offs=0U; offs<length; ++offs) { for(auto offs=0U; offs<length; ++offs) {
*(data + offs)=mem[(paddr.val+offs)%mem.size()]; *(data + offs)=mem[(paddr.val+offs)%mem.size()];
@ -1307,29 +1296,13 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned le
template <typename BASE, features_e FEAT> 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) { iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) {
switch (paddr.val) { switch (paddr.val) {
case 0x10013000: // UART0 base, TXFIFO reg case 0xFFFF0000: // UART0 base, TXFIFO reg
case 0x10023000: // UART1 base, TXFIFO reg
uart_buf << (char)data[0];
if (((char)data[0]) == '\n' || data[0] == 0) { if (((char)data[0]) == '\n' || data[0] == 0) {
LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send '"<<uart_buf.str()<<"'"; LOG(INFO)<<"UART"<<((paddr.val>>12)&0x3)<<" send '"<<uart_buf.str()<<"'";
std::cout << uart_buf.str();
uart_buf.str(""); uart_buf.str("");
} } else if(((char)data[0]) != '\r')
uart_buf << (char)data[0];
break; 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: { default: {
mem_type::page_type &p = mem(paddr.val / mem.page_size); mem_type::page_type &p = mem(paddr.val / mem.page_size);
std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask)); std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask));
@ -1351,7 +1324,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned l
LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar LOG(INFO) << "tohost value is 0x" << std::hex << hostvar << std::dec << " (" << hostvar
<< "), stopping simulation"; << "), stopping simulation";
} }
this->trap_state=std::numeric_limits<uint32_t>::max(); this->reg.trap_state=std::numeric_limits<uint32_t>::max();
this->interrupt_sim=hostvar; this->interrupt_sim=hostvar;
break; break;
//throw(iss::simulation_stopped(hostvar)); //throw(iss::simulation_stopped(hostvar));
@ -1436,14 +1409,14 @@ template <typename BASE, features_e FEAT> void riscv_hart_mu_p<BASE, FEAT>::chec
enabled_interrupts >>= 1; enabled_interrupts >>= 1;
res++; res++;
} }
this->pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id this->reg.pending_trap = res << 16 | 1; // 0x80 << 24 | (cause << 16) | trap_id
} }
} }
template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) { template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) {
// flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0] // flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0]
// calculate and write mcause val // calculate and write mcause val
if(flags==std::numeric_limits<uint64_t>::max()) flags=this->trap_state; if(flags==std::numeric_limits<uint64_t>::max()) flags=this->reg.trap_state;
auto trap_id = bit_sub<0, 16>(flags); auto trap_id = bit_sub<0, 16>(flags);
auto cause = bit_sub<16, 15>(flags); auto cause = bit_sub<16, 15>(flags);
if (trap_id == 0 && cause == 11) cause = 0x8 + this->reg.PRIV; // adjust environment call cause if (trap_id == 0 && cause == 11) cause = 0x8 + this->reg.PRIV; // adjust environment call cause
@ -1490,7 +1463,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
if (this->reg.PRIV != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0) if (this->reg.PRIV != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0)
new_priv = PRIV_U; new_priv = PRIV_U;
csr[uepc | (new_priv << 8)] = this->reg.NEXT_PC; // store next address if interrupt csr[uepc | (new_priv << 8)] = this->reg.NEXT_PC; // store next address if interrupt
this->pending_trap = 0; this->reg.pending_trap = 0;
} }
size_t adr = ucause | (new_priv << 8); size_t adr = ucause | (new_priv << 8);
csr[adr] = (trap_id << (traits<BASE>::XLEN-1)) + cause; csr[adr] = (trap_id << (traits<BASE>::XLEN-1)) + cause;
@ -1543,7 +1516,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
<< lvl[this->reg.PRIV] << " to " << lvl[new_priv]; << lvl[this->reg.PRIV] << " to " << lvl[new_priv];
// reset trap state // reset trap state
this->reg.PRIV = new_priv; this->reg.PRIV = new_priv;
this->trap_state = 0; this->reg.trap_state = 0;
return this->reg.NEXT_PC; return this->reg.NEXT_PC;
} }
@ -1552,7 +1525,7 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
auto inst_priv = (flags & 0x3)? 3:0; auto inst_priv = (flags & 0x3)? 3:0;
if(inst_priv>cur_priv){ if(inst_priv>cur_priv){
auto trap_val = 0x80ULL << 24 | (2 << 16); // illegal instruction auto trap_val = 0x80ULL << 24 | (2 << 16); // illegal instruction
this->trap_state = trap_val; this->reg.trap_state = trap_val;
this->reg.NEXT_PC = std::numeric_limits<uint32_t>::max(); this->reg.NEXT_PC = std::numeric_limits<uint32_t>::max();
} else { } else {
auto status = state.mstatus; auto status = state.mstatus;

View File

@ -41,8 +41,8 @@ using namespace iss::arch;
constexpr std::array<const char*, 36> iss::arch::traits<iss::arch::tgc_c>::reg_names; constexpr std::array<const char*, 36> iss::arch::traits<iss::arch::tgc_c>::reg_names;
constexpr std::array<const char*, 36> iss::arch::traits<iss::arch::tgc_c>::reg_aliases; constexpr std::array<const char*, 36> iss::arch::traits<iss::arch::tgc_c>::reg_aliases;
constexpr std::array<const uint32_t, 36> iss::arch::traits<iss::arch::tgc_c>::reg_bit_widths; constexpr std::array<const uint32_t, 43> iss::arch::traits<iss::arch::tgc_c>::reg_bit_widths;
constexpr std::array<const uint32_t, 36> iss::arch::traits<iss::arch::tgc_c>::reg_byte_offsets; constexpr std::array<const uint32_t, 43> iss::arch::traits<iss::arch::tgc_c>::reg_byte_offsets;
tgc_c::tgc_c() = default; tgc_c::tgc_c() = default;
@ -55,8 +55,8 @@ void tgc_c::reset(uint64_t address) {
reg.PC=address; reg.PC=address;
reg.NEXT_PC=reg.PC; reg.NEXT_PC=reg.PC;
reg.PRIV=0x3; reg.PRIV=0x3;
trap_state=0; reg.trap_state=0;
icount=0; reg.icount=0;
} }
uint8_t *tgc_c::get_regs_base_ptr() { uint8_t *tgc_c::get_regs_base_ptr() {

View File

@ -53,12 +53,12 @@ template <> struct traits<tgc_c> {
static constexpr std::array<const char*, 36> reg_aliases{ static constexpr std::array<const char*, 36> reg_aliases{
{"ZERO", "RA", "SP", "GP", "TP", "T0", "T1", "T2", "S0", "S1", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "S10", "S11", "T3", "T4", "T5", "T6", "PC", "NEXT_PC", "PRIV", "DPC"}}; {"ZERO", "RA", "SP", "GP", "TP", "T0", "T1", "T2", "S0", "S1", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "S10", "S11", "T3", "T4", "T5", "T6", "PC", "NEXT_PC", "PRIV", "DPC"}};
enum constants {MISA_VAL=0b01000000000000000001000100000100, MARCHID_VAL=0x80000003, XLEN=32, INSTR_ALIGNMENT=2, RFS=32, fence=0, fencei=1, fencevmal=2, fencevmau=3, CSR_SIZE=4096, MUL_LEN=64}; enum constants {MISA_VAL=1073746180, MARCHID_VAL=2147483651, XLEN=32, INSTR_ALIGNMENT=2, RFS=32, fence=0, fencei=1, fencevmal=2, fencevmau=3, CSR_SIZE=4096, MUL_LEN=64};
constexpr static unsigned FP_REGS_SIZE = 0; constexpr static unsigned FP_REGS_SIZE = 0;
enum reg_e { enum reg_e {
X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, X30, X31, PC, NEXT_PC, PRIV, DPC, NUM_REGS X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, X30, X31, PC, NEXT_PC, PRIV, DPC, NUM_REGS, TRAP_STATE=NUM_REGS, PENDING_TRAP, ICOUNT, CYCLE, INSTRET, INSTRUCTION, LAST_BRANCH
}; };
using reg_t = uint32_t; using reg_t = uint32_t;
@ -71,11 +71,11 @@ template <> struct traits<tgc_c> {
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>; using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
static constexpr std::array<const uint32_t, 36> reg_bit_widths{ static constexpr std::array<const uint32_t, 43> reg_bit_widths{
{32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,8,32}}; {32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,8,32,32,32,64,64,64,32,32}};
static constexpr std::array<const uint32_t, 36> reg_byte_offsets{ static constexpr std::array<const uint32_t, 43> 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}}; {0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,137,141,145,149,157,165,173,177}};
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1); static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
@ -83,7 +83,7 @@ template <> struct traits<tgc_c> {
enum mem_type_e { MEM, FENCE, RES, CSR }; enum mem_type_e { MEM, FENCE, RES, CSR };
enum class opcode_e : unsigned short { enum class opcode_e {
LUI = 0, LUI = 0,
AUIPC = 1, AUIPC = 1,
JAL = 2, JAL = 2,
@ -189,7 +189,7 @@ struct tgc_c: public arch_if {
uint8_t* get_regs_base_ptr() override; uint8_t* get_regs_base_ptr() override;
inline uint64_t get_icount() { return icount; } inline uint64_t get_icount() { return reg.icount; }
inline bool should_stop() { return interrupt_sim; } inline bool should_stop() { return interrupt_sim; }
@ -207,7 +207,7 @@ struct tgc_c: public arch_if {
virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; } virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
inline uint32_t get_last_branch() { return last_branch; } inline uint32_t get_last_branch() { return reg.last_branch; }
#pragma pack(push, 1) #pragma pack(push, 1)
@ -248,14 +248,14 @@ struct tgc_c: public arch_if {
uint32_t NEXT_PC = 0; uint32_t NEXT_PC = 0;
uint8_t PRIV = 0; uint8_t PRIV = 0;
uint32_t DPC = 0; uint32_t DPC = 0;
uint32_t trap_state = 0, pending_trap = 0;
uint64_t icount = 0;
uint64_t cycle = 0;
uint64_t instret = 0;
uint32_t instruction = 0;
uint32_t last_branch = 0;
} reg; } reg;
#pragma pack(pop) #pragma pack(pop)
uint32_t trap_state = 0, pending_trap = 0;
uint64_t icount = 0;
uint64_t cycle = 0;
uint64_t instret = 0;
uint32_t instruction = 0;
uint32_t last_branch = 0;
std::array<address_type, 4> addr_mode; std::array<address_type, 4> addr_mode;
uint64_t interrupt_sim=0; uint64_t interrupt_sim=0;

View File

@ -120,7 +120,7 @@ iss::status iss::arch::wt_cache<BASE>::read_cache(phys_addr_t a, unsigned l, uin
if((a.val&io_addr_mask) != io_address) { if((a.val&io_addr_mask) != io_address) {
auto set_addr=(a.val&(size-1))>>util::ilog2(line_sz*ways); auto set_addr=(a.val&(size-1))>>util::ilog2(line_sz*ways);
auto tag_addr=a.val>>util::ilog2(line_sz); auto tag_addr=a.val>>util::ilog2(line_sz);
auto& set = (a.access==access_type::FETCH?icache_ptr:dcache_ptr)->sets[set_addr]; auto& set = (is_fetch(a.access)?icache_ptr:dcache_ptr)->sets[set_addr];
for(auto& cl: set.ways) { for(auto& cl: set.ways) {
if(cl.st==cache::state::VALID && cl.tag_addr==tag_addr) { if(cl.st==cache::state::VALID && cl.tag_addr==tag_addr) {
auto start_addr = a.val&(line_sz-1); auto start_addr = a.val&(line_sz-1);
@ -156,7 +156,7 @@ iss::status iss::arch::wt_cache<BASE>::write_cache(phys_addr_t a, unsigned l, co
if(cl.st==cache::state::VALID && cl.tag_addr==tag_addr) { if(cl.st==cache::state::VALID && cl.tag_addr==tag_addr) {
auto start_addr = a.val&(line_sz-1); auto start_addr = a.val&(line_sz-1);
for(auto i = 0U; i<l; ++i) for(auto i = 0U; i<l; ++i)
cl.data[start_addr+1] = d[i]; cl.data[start_addr+i] = d[i];
break; break;
} }
} }

View File

@ -34,6 +34,12 @@
#define _ISS_FACTORY_H_ #define _ISS_FACTORY_H_
#include <iss/iss.h> #include <iss/iss.h>
#include <memory>
#include <unordered_map>
#include <functional>
#include <string>
#include <algorithm>
#include <vector>
namespace iss { namespace iss {
@ -50,13 +56,55 @@ std::tuple<cpu_ptr, vm_ptr> create_cpu(std::string const& backend, unsigned gdb_
if(backend == "llvm") if(backend == "llvm")
return {cpu_ptr{lcpu}, vm_ptr{iss::llvm::create(lcpu, gdb_port)}}; return {cpu_ptr{lcpu}, vm_ptr{iss::llvm::create(lcpu, gdb_port)}};
#endif #endif
#ifdef WITH_LLVM #ifdef WITH_TCC
if(backend == "tcc") if(backend == "tcc")
return {cpu_ptr{lcpu}, vm_ptr{iss::tcc::create(lcpu, gdb_port)}}; return {cpu_ptr{lcpu}, vm_ptr{iss::tcc::create(lcpu, gdb_port)}};
#endif #endif
return {nullptr, nullptr}; return {nullptr, nullptr};
} }
class core_factory {
using cpu_ptr = std::unique_ptr<iss::arch_if>;
using vm_ptr= std::unique_ptr<iss::vm_if>;
using base_t = std::tuple<cpu_ptr, vm_ptr>;
using create_fn = std::function<base_t(unsigned, void*) >;
using registry_t = std::unordered_map<std::string, create_fn> ;
registry_t registry;
core_factory() = default;
core_factory(const core_factory &) = delete;
core_factory & operator=(const core_factory &) = delete;
public:
static core_factory & instance() { static core_factory bf; return bf; }
bool register_creator(const std::string &, create_fn const&);
base_t create(const std::string &, unsigned gdb_port=0, void* init_data=nullptr) const;
std::vector<std::string> get_names() {
std::vector<std::string> keys{registry.size()};
std::transform(std::begin(registry), std::end(registry), std::begin(keys), [](std::pair<std::string, create_fn> const& p){
return p.first;
});
return keys;
}
};
inline bool core_factory::register_creator(const std::string & className, create_fn const& fn) {
registry[className] = fn;
return true;
}
inline core_factory::base_t core_factory::create(const std::string &className, unsigned gdb_port, void* data) const {
registry_t::const_iterator regEntry = registry.find(className);
if (regEntry != registry.end())
return regEntry->second(gdb_port, data);
return {nullptr, nullptr};
}
} }
#endif /* _ISS_FACTORY_H_ */ #endif /* _ISS_FACTORY_H_ */

View File

@ -31,7 +31,9 @@
*******************************************************************************/ *******************************************************************************/
#include <iostream> #include <iostream>
#include "iss/factory.h" #include <vector>
#include <array>
#include <iss/factory.h>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
@ -61,7 +63,7 @@ int main(int argc, char *argv[]) {
// clang-format off // clang-format off
desc.add_options() desc.add_options()
("help,h", "Print help message") ("help,h", "Print help message")
("verbose,v", po::value<int>()->implicit_value(0), "Sets logging verbosity") ("verbose,v", po::value<int>()->default_value(4), "Sets logging verbosity")
("logfile,l", po::value<std::string>(), "Sets default log file.") ("logfile,l", po::value<std::string>(), "Sets default log file.")
("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly") ("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly")
("gdb-port,g", po::value<unsigned>()->default_value(0), "enable gdb server and specify port to use") ("gdb-port,g", po::value<unsigned>()->default_value(0), "enable gdb server and specify port to use")
@ -71,7 +73,7 @@ int main(int argc, char *argv[]) {
("elf,f", po::value<std::vector<std::string>>(), "ELF file(s) to load") ("elf,f", po::value<std::vector<std::string>>(), "ELF file(s) to load")
("mem,m", po::value<std::string>(), "the memory input file") ("mem,m", po::value<std::string>(), "the memory input file")
("plugin,p", po::value<std::vector<std::string>>(), "plugin to activate") ("plugin,p", po::value<std::vector<std::string>>(), "plugin to activate")
("backend", po::value<std::string>()->default_value("interp"), "the memory input file") ("backend", po::value<std::string>()->default_value("interp"), "the ISS backend to use, options are: interp, tcc")
("isa", po::value<std::string>()->default_value("tgc_c"), "isa to use for simulation"); ("isa", po::value<std::string>()->default_value("tgc_c"), "isa to use for simulation");
// clang-format on // clang-format on
auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run(); auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
@ -93,11 +95,9 @@ int main(int argc, char *argv[]) {
LOGGER(DEFAULT)::print_time() = false; LOGGER(DEFAULT)::print_time() = false;
LOGGER(connection)::print_time() = false; LOGGER(connection)::print_time() = false;
if (clim.count("verbose")) { auto l = logging::as_log_level(clim["verbose"].as<int>());
auto l = logging::as_log_level(clim["verbose"].as<int>()); LOGGER(DEFAULT)::reporting_level() = l;
LOGGER(DEFAULT)::reporting_level() = l; LOGGER(connection)::reporting_level() = l;
LOGGER(connection)::reporting_level() = l;
}
if (clim.count("logfile")) { if (clim.count("logfile")) {
// configure the connection logger // configure the connection logger
auto f = fopen(clim["logfile"].as<std::string>().c_str(), "w"); auto f = fopen(clim["logfile"].as<std::string>().c_str(), "w");
@ -113,86 +113,59 @@ int main(int argc, char *argv[]) {
iss::init_jit_debug(argc, argv); iss::init_jit_debug(argc, argv);
#endif #endif
bool dump = clim.count("dump-ir"); bool dump = clim.count("dump-ir");
auto & f = iss::core_factory::instance();
// instantiate the simulator // instantiate the simulator
iss::vm_ptr vm{nullptr}; iss::vm_ptr vm{nullptr};
iss::cpu_ptr cpu{nullptr}; iss::cpu_ptr cpu{nullptr};
std::string isa_opt(clim["isa"].as<std::string>()); std::string isa_opt(clim["isa"].as<std::string>());
if (isa_opt == "tgc_c") { if(isa_opt.size()==0 || isa_opt == "?") {
std::tie(cpu, vm) = std::cout<<"Available cores: "<<util::join(f.get_names(), ", ")<<std::endl;
iss::create_cpu<tgc_c_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>()); return 0;
} else } else if (isa_opt.find('|') != std::string::npos) {
#ifdef CORE_TGC_B std::tie(cpu, vm) = f.create(isa_opt+"|"+clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
if (isa_opt == "tgc_b") { } else {
std::tie(cpu, vm) = auto base_isa = isa_opt.substr(0, 5);
iss::create_cpu<tgc_b_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>()); if(base_isa=="tgc_d" || base_isa=="tgc_e") {
} else isa_opt += "|mu_p_clic_pmp|"+clim["backend"].as<std::string>();
#endif } else {
#ifdef CORE_TGC_C_XRB_NN isa_opt += "|m_p|"+clim["backend"].as<std::string>();
if (isa_opt == "tgc_c_xrb_nn") { }
std::tie(cpu, vm) = std::tie(cpu, vm) = f.create(isa_opt, clim["gdb-port"].as<unsigned>());
iss::create_cpu<tgc_c_xrb_nn_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
} else
#endif
#ifdef CORE_TGC_D
if (isa_opt == "tgc_d") {
std::tie(cpu, vm) =
iss::create_cpu<tgc_d_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
} else
#endif
#ifdef CORE_TGC_D_XRB_MAC
if (isa_opt == "tgc_d_xrb_mac") {
std::tie(cpu, vm) =
iss::create_cpu<tgc_d_xrb_mac_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
} else
#endif
#ifdef CORE_TGC_D_XRB_NN
if (isa_opt == "tgc_d_xrb_nn") {
std::tie(cpu, vm) =
iss::create_cpu<tgc_d_xrb_nn_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
} else
#endif
#ifdef CORE_TGC_E
if (isa_opt == "tgc_e") {
std::tie(cpu, vm) =
iss::create_cpu<tgc_e_plat_type>(clim["backend"].as<std::string>(), clim["gdb-port"].as<unsigned>());
} else
#endif
{
LOG(ERR) << "Illegal argument value for '--isa': " << isa_opt << std::endl;
return 127;
} }
if(!cpu ){ if(!cpu ){
LOG(ERR) << "Could not create cpu fore for isa " << isa_opt << " and backend " <<clim["backend"].as<std::string>()<< std::endl; LOG(ERR) << "Could not create cpu for isa " << isa_opt << " and backend " <<clim["backend"].as<std::string>()<< std::endl;
return 127; return 127;
} }
if(!vm ){ if(!vm ){
LOG(ERR) << "Could not create vm fore for isa " << isa_opt << " and backend " <<clim["backend"].as<std::string>()<< std::endl; LOG(ERR) << "Could not create vm for isa " << isa_opt << " and backend " <<clim["backend"].as<std::string>()<< std::endl;
return 127; return 127;
} }
if (clim.count("plugin")) { if (clim.count("plugin")) {
for (std::string const& opt_val : clim["plugin"].as<std::vector<std::string>>()) { for (std::string const& opt_val : clim["plugin"].as<std::vector<std::string>>()) {
std::string plugin_name=opt_val; std::string plugin_name=opt_val;
std::string filename{"cycles.txt"}; std::string arg{""};
std::size_t found = opt_val.find('='); std::size_t found = opt_val.find('=');
if (found != std::string::npos) { if (found != std::string::npos) {
plugin_name = opt_val.substr(0, found); plugin_name = opt_val.substr(0, found);
filename = opt_val.substr(found + 1, opt_val.size()); arg = opt_val.substr(found + 1, opt_val.size());
} }
if (plugin_name == "ic") { if (plugin_name == "ic") {
auto *ic_plugin = new iss::plugin::instruction_count(filename); auto *ic_plugin = new iss::plugin::instruction_count(arg);
vm->register_plugin(*ic_plugin); vm->register_plugin(*ic_plugin);
plugin_list.push_back(ic_plugin); plugin_list.push_back(ic_plugin);
} else if (plugin_name == "ce") { } else if (plugin_name == "ce") {
auto *ce_plugin = new iss::plugin::cycle_estimate(filename); auto *ce_plugin = new iss::plugin::cycle_estimate(arg);
vm->register_plugin(*ce_plugin); vm->register_plugin(*ce_plugin);
plugin_list.push_back(ce_plugin); plugin_list.push_back(ce_plugin);
} else if (plugin_name == "pctrace") { } else if (plugin_name == "pctrace") {
auto *plugin = new iss::plugin::pctrace(filename); auto *plugin = new iss::plugin::pctrace(arg);
vm->register_plugin(*plugin); vm->register_plugin(*plugin);
plugin_list.push_back(plugin); plugin_list.push_back(plugin);
} else { } else {
#ifndef WIN32 #ifndef WIN32
std::array<char const*, 1> a{{filename.c_str()}}; std::vector<char const*> a{};
if(arg.length())
a.push_back({arg.c_str()});
iss::plugin::loader l(plugin_name, {{"initPlugin"}}); iss::plugin::loader l(plugin_name, {{"initPlugin"}});
auto* plugin = l.call_function<iss::vm_plugin*>("initPlugin", a.size(), a.data()); auto* plugin = l.call_function<iss::vm_plugin*>("initPlugin", a.size(), a.data());
if(plugin){ if(plugin){

View File

@ -118,7 +118,7 @@ public:
std::stringstream s; std::stringstream s;
s << "[p:" << lvl[this->reg.PRIV] << ";s:0x" << std::hex << std::setfill('0') 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:" << std::setw(sizeof(reg_t) * 2) << (reg_t)this->state.mstatus << std::dec << ";c:"
<< this->icount + this->cycle_offset << "]"; << this->reg.icount + this->cycle_offset << "]";
SCCDEBUG(owner->name())<<"disass: " SCCDEBUG(owner->name())<<"disass: "
<< "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t" << std::setw(40) << "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t" << std::setw(40)
<< std::setfill(' ') << std::left << instr << s.str(); << std::setfill(' ') << std::left << instr << s.str();
@ -129,7 +129,7 @@ public:
if (addr.access && access_type::DEBUG) if (addr.access && access_type::DEBUG)
return owner->read_mem_dbg(addr.val, length, data) ? Ok : Err; return owner->read_mem_dbg(addr.val, length, data) ? Ok : Err;
else { else {
return owner->read_mem(addr.val, length, data, addr.access && access_type::FETCH) ? Ok : Err; return owner->read_mem(addr.val, length, data, is_fetch(addr.access)) ? Ok : Err;
} }
} }
@ -178,7 +178,7 @@ public:
void wait_until(uint64_t flags) override { void wait_until(uint64_t flags) override {
SCCDEBUG(owner->name()) << "Sleeping until interrupt"; SCCDEBUG(owner->name()) << "Sleeping until interrupt";
while(this->pending_trap == 0 && (this->csr[arch::mip] & this->csr[arch::mie]) == 0) { while(this->reg.pending_trap == 0 && (this->csr[arch::mip] & this->csr[arch::mie]) == 0) {
sc_core::wait(wfi_evt); sc_core::wait(wfi_evt);
} }
PLAT::wait_until(flags); PLAT::wait_until(flags);
@ -207,7 +207,7 @@ public:
this->csr[arch::mip] &= ~mask; this->csr[arch::mip] &= ~mask;
this->check_interrupt(); this->check_interrupt();
if(value) if(value)
SCCTRACE(owner->name()) << "Triggering interrupt " << id << " Pending trap: " << this->pending_trap; SCCTRACE(owner->name()) << "Triggering interrupt " << id << " Pending trap: " << this->reg.pending_trap;
} }
private: private:

View File

@ -0,0 +1,33 @@
/*
* register_tgc_c.cpp
*
* Created on: Jul 5, 2023
* Author: eyck
*/
#include <iss/factory.h>
#include <iss/arch/tgc_c.h>
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/arch/riscv_hart_mu_p.h>
#include "sc_core_adapter.h"
#include "core_complex.h"
namespace iss {
namespace {
volatile std::array<bool, 2> dummy = {
core_factory::instance().register_creator("tgc_c|m_p|interp", [](unsigned gdb_port, void* data) -> std::tuple<cpu_ptr, vm_ptr>{
auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
arch::tgc_c* lcpu = new sc_core_adapter<arch::riscv_hart_m_p<arch::tgc_c>>(cc);
return {cpu_ptr{lcpu}, vm_ptr{interp::create(lcpu, gdb_port)}};
}),
core_factory::instance().register_creator("tgc_c|mu_p|interp", [](unsigned gdb_port, void* data) -> std::tuple<cpu_ptr, vm_ptr>{
auto cc = reinterpret_cast<sysc::tgfs::core_complex*>(data);
arch::tgc_c* lcpu = new sc_core_adapter<arch::riscv_hart_mu_p<arch::tgc_c>>(cc);
return {cpu_ptr{lcpu}, vm_ptr{interp::create(lcpu, gdb_port)}};
})
};
}
}

148
src/sysc/sc_core_adapter.h Normal file
View File

@ -0,0 +1,148 @@
/*
* sc_core_adapter.h
*
* Created on: Jul 5, 2023
* Author: eyck
*/
#ifndef _SYSC_SC_CORE_ADAPTER_H_
#define _SYSC_SC_CORE_ADAPTER_H_
#include <scc/report.h>
#include <util/ities.h>
#include "core_complex.h"
#include <iss/iss.h>
#include <iss/vm_types.h>
#include <iostream>
template<typename PLAT>
class sc_core_adapter : public PLAT {
public:
using reg_t = typename iss::arch::traits<typename PLAT::core>::reg_t;
using phys_addr_t = typename iss::arch::traits<typename PLAT::core>::phys_addr_t;
using heart_state_t = typename PLAT::hart_state_type;
sc_core_adapter(sysc::tgfs::core_complex *owner)
: owner(owner) { }
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; }
heart_state_t &get_state() { return this->state; }
void notify_phase(iss::arch_if::exec_phase p) override {
if (p == iss::arch_if::ISTART)
owner->sync(this->instr_if.get_total_cycles());
}
iss::sync_type needed_sync() const override { return iss::PRE_SYNC; }
void disass_output(uint64_t pc, const std::string instr) override {
static constexpr std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
if (!owner->disass_output(pc, instr)) {
std::stringstream s;
s << "[p:" << lvl[this->reg.PRIV] << ";s:0x" << std::hex << std::setfill('0')
<< std::setw(sizeof(reg_t) * 2) << (reg_t)this->state.mstatus << std::dec << ";c:"
<< this->reg.icount + this->cycle_offset << "]";
SCCDEBUG(owner->name())<<"disass: "
<< "0x" << std::setw(16) << std::right << std::setfill('0') << std::hex << pc << "\t\t" << std::setw(40)
<< std::setfill(' ') << std::left << instr << s.str();
}
};
iss::status read_mem(phys_addr_t addr, unsigned length, uint8_t *const data) override {
if (addr.access && iss::access_type::DEBUG)
return owner->read_mem_dbg(addr.val, length, data) ? iss::Ok : iss::Err;
else {
return owner->read_mem(addr.val, length, data, is_fetch(addr.access)) ? iss::Ok : iss::Err;
}
}
iss::status write_mem(phys_addr_t addr, unsigned length, const uint8_t *const data) override {
if (addr.access && iss::access_type::DEBUG)
return owner->write_mem_dbg(addr.val, length, data) ? iss::Ok : iss::Err;
else {
auto res = owner->write_mem(addr.val, length, data) ? iss::Ok : iss::Err;
// clear MTIP on mtimecmp write
if (addr.val == 0x2004000) {
reg_t val;
this->read_csr(iss::arch::mip, val);
if (val & (1ULL << 7)) this->write_csr(iss::arch::mip, val & ~(1ULL << 7));
}
return res;
}
}
iss::status read_csr(unsigned addr, reg_t &val) override {
#ifndef CWR_SYSTEMC
if((addr==iss::arch::time || addr==iss::arch::timeh) && owner->mtime_o.get_interface(0)){
uint64_t time_val;
bool ret = owner->mtime_o->nb_peek(time_val);
if (addr == iss::arch::time) {
val = static_cast<reg_t>(time_val);
} else if (addr == iss::arch::timeh) {
if (sizeof(reg_t) != 4) return iss::Err;
val = static_cast<reg_t>(time_val >> 32);
}
return ret?iss::Ok:iss::Err;
#else
if((addr==iss::arch::time || addr==iss::arch::timeh)){
uint64_t time_val = owner->mtime_i.read();
if (addr == iss::arch::time) {
val = static_cast<reg_t>(time_val);
} else if (addr == iss::arch::timeh) {
if (sizeof(reg_t) != 4) return iss::Err;
val = static_cast<reg_t>(time_val >> 32);
}
return iss::Ok;
#endif
} else {
return PLAT::read_csr(addr, val);
}
}
void wait_until(uint64_t flags) override {
SCCDEBUG(owner->name()) << "Sleeping until interrupt";
while(this->reg.pending_trap == 0 && (this->csr[iss::arch::mip] & this->csr[iss::arch::mie]) == 0) {
sc_core::wait(wfi_evt);
}
PLAT::wait_until(flags);
}
void local_irq(short id, bool value) {
reg_t mask = 0;
switch (id) {
case 3: // SW
mask = 1 << 3;
break;
case 7: // timer
mask = 1 << 7;
break;
case 11: // external
mask = 1 << 11;
break;
default:
if(id>15) mask = 1 << id;
break;
}
if (value) {
this->csr[iss::arch::mip] |= mask;
wfi_evt.notify();
} else
this->csr[iss::arch::mip] &= ~mask;
this->check_interrupt();
if(value)
SCCTRACE(owner->name()) << "Triggering interrupt " << id << " Pending trap: " << this->reg.pending_trap;
}
private:
sysc::tgfs::core_complex *const owner;
sc_core::sc_event wfi_evt;
};
#endif /* _SYSC_SC_CORE_ADAPTER_H_ */

View File

@ -30,10 +30,9 @@
* *
*******************************************************************************/ *******************************************************************************/
#include <iss/arch/tgc_c.h>
#include <iss/debugger/gdb_session.h> #include <iss/debugger/gdb_session.h>
#include <iss/debugger/server.h> #include <iss/debugger/server.h>
#include <iss/arch/tgc_c.h>
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/iss.h> #include <iss/iss.h>
#include <iss/interp/vm_base.h> #include <iss/interp/vm_base.h>
#include <util/logging.h> #include <util/logging.h>
@ -115,7 +114,7 @@ protected:
inline void raise(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; auto trap_val = 0x80ULL << 24 | (cause << 16) | trap_id;
this->core.trap_state = trap_val; this->core.reg.trap_state = trap_val;
this->template get_reg<uint32_t>(traits::NEXT_PC) = std::numeric_limits<uint32_t>::max(); this->template get_reg<uint32_t>(traits::NEXT_PC) = std::numeric_limits<uint32_t>::max();
} }
@ -322,16 +321,16 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
auto pc=start; auto pc=start;
auto* PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]); auto* PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::PC]);
auto* NEXT_PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]); auto* NEXT_PC = reinterpret_cast<uint32_t*>(this->regs_base_ptr+arch::traits<ARCH>::reg_byte_offsets[arch::traits<ARCH>::NEXT_PC]);
auto& trap_state = this->core.trap_state; auto& trap_state = this->core.reg.trap_state;
auto& icount = this->core.icount; auto& icount = this->core.reg.icount;
auto& cycle = this->core.cycle; auto& cycle = this->core.reg.cycle;
auto& instret = this->core.instret; auto& instret = this->core.reg.instret;
auto& instr = this->core.instruction; auto& instr = this->core.reg.instruction;
// we fetch at max 4 byte, alignment is 2 // we fetch at max 4 byte, alignment is 2
auto *const data = reinterpret_cast<uint8_t*>(&instr); auto *const data = reinterpret_cast<uint8_t*>(&instr);
while(!this->core.should_stop() && while(!this->core.should_stop() &&
!(is_count_limit_enabled(cond) && this->core.get_icount() >= icount_limit)){ !(is_count_limit_enabled(cond) && icount >= icount_limit)){
if(fetch_ins(pc, data)!=iss::Ok){ if(fetch_ins(pc, data)!=iss::Ok){
this->do_sync(POST_SYNC, std::numeric_limits<unsigned>::max()); this->do_sync(POST_SYNC, std::numeric_limits<unsigned>::max());
pc.val = super::core.enter_trap(std::numeric_limits<uint64_t>::max(), pc.val, 0); pc.val = super::core.enter_trap(std::numeric_limits<uint64_t>::max(), pc.val, 0);
@ -340,7 +339,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
(instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0' (instr == 0x0000006f || (instr&0xffff)==0xa001)) throw simulation_stopped(0); // 'J 0' or 'C.J 0'
auto inst_id = decode_inst_id(instr); auto inst_id = decode_inst_id(instr);
// pre execution stuff // pre execution stuff
this->core.last_branch = 0; this->core.reg.last_branch = 0;
if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id)); if(this->sync_exec && PRE_SYNC) this->do_sync(PRE_SYNC, static_cast<unsigned>(inst_id));
switch(inst_id){ switch(inst_id){
case arch::traits<ARCH>::opcode_e::LUI: { case arch::traits<ARCH>::opcode_e::LUI: {
@ -389,7 +388,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = *PC + (int32_t)imm; *(X+rd) = (uint32_t)(*PC + (int32_t)imm);
} }
} }
} }
@ -419,10 +418,10 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = *PC + 4; *(X+rd) = (uint32_t)(*PC + 4);
} }
*NEXT_PC = *PC + (int32_t)sext<21>(imm); *NEXT_PC = (uint32_t)(*PC + (int32_t)sext<21>(imm));
this->core.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
} }
@ -448,16 +447,16 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
uint32_t new_pc = (*(X+rs1) + (int16_t)sext<12>(imm)) & ~ 0x1; uint32_t new_pc = (uint32_t)((*(X+rs1) + (int16_t)sext<12>(imm)) & ~ 0x1);
if(new_pc % traits::INSTR_ALIGNMENT) { if(new_pc % traits::INSTR_ALIGNMENT) {
raise(0, 0); raise(0, 0);
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = *PC + 4; *(X+rd) = (uint32_t)(*PC + 4);
} }
*NEXT_PC = new_pc & ~ 0x1; *NEXT_PC = new_pc & ~ 0x1;
this->core.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
} }
@ -488,8 +487,8 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 0); raise(0, 0);
} }
else { else {
*NEXT_PC = *PC + (int16_t)sext<13>(imm); *NEXT_PC = (uint32_t)(*PC + (int16_t)sext<13>(imm));
this->core.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
} }
@ -521,8 +520,8 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 0); raise(0, 0);
} }
else { else {
*NEXT_PC = *PC + (int16_t)sext<13>(imm); *NEXT_PC = (uint32_t)(*PC + (int16_t)sext<13>(imm));
this->core.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
} }
@ -554,8 +553,8 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 0); raise(0, 0);
} }
else { else {
*NEXT_PC = *PC + (int16_t)sext<13>(imm); *NEXT_PC = (uint32_t)(*PC + (int16_t)sext<13>(imm));
this->core.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
} }
@ -587,8 +586,8 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 0); raise(0, 0);
} }
else { else {
*NEXT_PC = *PC + (int16_t)sext<13>(imm); *NEXT_PC = (uint32_t)(*PC + (int16_t)sext<13>(imm));
this->core.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
} }
@ -620,8 +619,8 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 0); raise(0, 0);
} }
else { else {
*NEXT_PC = *PC + (int16_t)sext<13>(imm); *NEXT_PC = (uint32_t)(*PC + (int16_t)sext<13>(imm));
this->core.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
} }
@ -653,8 +652,8 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 0); raise(0, 0);
} }
else { else {
*NEXT_PC = *PC + (int16_t)sext<13>(imm); *NEXT_PC = (uint32_t)(*PC + (int16_t)sext<13>(imm));
this->core.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
} }
@ -681,9 +680,9 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
uint32_t load_address = *(X+rs1) + (int16_t)sext<12>(imm); uint32_t load_address = (uint32_t)(*(X+rs1) + (int16_t)sext<12>(imm));
int8_t read_res = super::template read_mem<int8_t>(traits::MEM, load_address); int8_t read_res = super::template read_mem<int8_t>(traits::MEM, load_address);
if(this->core.trap_state>=0x80000000UL) goto TRAP_LB; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_LB;
int8_t res = (int8_t)read_res; int8_t res = (int8_t)read_res;
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)res; *(X+rd) = (uint32_t)res;
@ -712,9 +711,9 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
uint32_t load_address = *(X+rs1) + (int16_t)sext<12>(imm); uint32_t load_address = (uint32_t)(*(X+rs1) + (int16_t)sext<12>(imm));
int16_t read_res = super::template read_mem<int16_t>(traits::MEM, load_address); int16_t read_res = super::template read_mem<int16_t>(traits::MEM, load_address);
if(this->core.trap_state>=0x80000000UL) goto TRAP_LH; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_LH;
int16_t res = (int16_t)read_res; int16_t res = (int16_t)read_res;
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)res; *(X+rd) = (uint32_t)res;
@ -743,9 +742,9 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
uint32_t load_address = *(X+rs1) + (int16_t)sext<12>(imm); uint32_t load_address = (uint32_t)(*(X+rs1) + (int16_t)sext<12>(imm));
int32_t read_res = super::template read_mem<int32_t>(traits::MEM, load_address); int32_t read_res = super::template read_mem<int32_t>(traits::MEM, load_address);
if(this->core.trap_state>=0x80000000UL) goto TRAP_LW; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_LW;
int32_t res = (int32_t)read_res; int32_t res = (int32_t)read_res;
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)res; *(X+rd) = (uint32_t)res;
@ -774,10 +773,10 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
uint32_t load_address = *(X+rs1) + (int16_t)sext<12>(imm); uint32_t load_address = (uint32_t)(*(X+rs1) + (int16_t)sext<12>(imm));
uint8_t read_res = super::template read_mem<uint8_t>(traits::MEM, load_address); uint8_t read_res = super::template read_mem<uint8_t>(traits::MEM, load_address);
if(this->core.trap_state>=0x80000000UL) goto TRAP_LBU; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_LBU;
uint8_t res = (uint8_t)read_res; uint8_t res = read_res;
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)res; *(X+rd) = (uint32_t)res;
} }
@ -805,10 +804,10 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
uint32_t load_address = *(X+rs1) + (int16_t)sext<12>(imm); uint32_t load_address = (uint32_t)(*(X+rs1) + (int16_t)sext<12>(imm));
uint16_t read_res = super::template read_mem<uint16_t>(traits::MEM, load_address); uint16_t read_res = super::template read_mem<uint16_t>(traits::MEM, load_address);
if(this->core.trap_state>=0x80000000UL) goto TRAP_LHU; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_LHU;
uint16_t res = (uint16_t)read_res; uint16_t res = read_res;
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)res; *(X+rd) = (uint32_t)res;
} }
@ -836,9 +835,9 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
uint32_t store_address = *(X+rs1) + (int16_t)sext<12>(imm); uint32_t store_address = (uint32_t)(*(X+rs1) + (int16_t)sext<12>(imm));
super::template write_mem<uint8_t>(traits::MEM, store_address, (int8_t)*(X+rs2)); super::template write_mem<uint8_t>(traits::MEM, store_address, (uint8_t)*(X+rs2));
if(this->core.trap_state>=0x80000000UL) goto TRAP_SB; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_SB;
} }
} }
TRAP_SB:break; TRAP_SB:break;
@ -863,9 +862,9 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
uint32_t store_address = *(X+rs1) + (int16_t)sext<12>(imm); uint32_t store_address = (uint32_t)(*(X+rs1) + (int16_t)sext<12>(imm));
super::template write_mem<uint16_t>(traits::MEM, store_address, (int16_t)*(X+rs2)); super::template write_mem<uint16_t>(traits::MEM, store_address, (uint16_t)*(X+rs2));
if(this->core.trap_state>=0x80000000UL) goto TRAP_SH; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_SH;
} }
} }
TRAP_SH:break; TRAP_SH:break;
@ -890,9 +889,9 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
uint32_t store_address = *(X+rs1) + (int16_t)sext<12>(imm); uint32_t store_address = (uint32_t)(*(X+rs1) + (int16_t)sext<12>(imm));
super::template write_mem<uint32_t>(traits::MEM, store_address, (int32_t)*(X+rs2)); super::template write_mem<uint32_t>(traits::MEM, store_address, (uint32_t)*(X+rs2));
if(this->core.trap_state>=0x80000000UL) goto TRAP_SW; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_SW;
} }
} }
TRAP_SW:break; TRAP_SW:break;
@ -918,7 +917,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = *(X+rs1) + (int16_t)sext<12>(imm); *(X+rd) = (uint32_t)(*(X+rs1) + (int16_t)sext<12>(imm));
} }
} }
} }
@ -1134,7 +1133,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = (int32_t)*(X+rs1) >> shamt; *(X+rd) = (uint32_t)((int32_t)*(X+rs1) >> shamt);
} }
} }
} }
@ -1161,7 +1160,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = *(X+rs1) + *(X+rs2); *(X+rd) = (uint32_t)(*(X+rs1) + *(X+rs2));
} }
} }
} }
@ -1188,7 +1187,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = *(X+rs1) - *(X+rs2); *(X+rd) = (uint32_t)(*(X+rs1) - *(X+rs2));
} }
} }
} }
@ -1350,7 +1349,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = (int32_t)*(X+rs1) >> (*(X+rs2) & (traits::XLEN - 1)); *(X+rd) = (uint32_t)((int32_t)*(X+rs1) >> (*(X+rs2) & (traits::XLEN - 1)));
} }
} }
} }
@ -1427,8 +1426,8 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
*NEXT_PC = *PC + 4; *NEXT_PC = *PC + 4;
// execute instruction // execute instruction
{ {
super::template write_mem<uint8_t>(traits::FENCE, traits::fence, pred << 4 | succ); super::template write_mem<uint32_t>(traits::FENCE, traits::fence, (uint8_t)pred << 4 | succ);
if(this->core.trap_state>=0x80000000UL) goto TRAP_FENCE; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_FENCE;
} }
TRAP_FENCE:break; TRAP_FENCE:break;
}// @suppress("No break at end of case") }// @suppress("No break at end of case")
@ -1507,15 +1506,15 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
uint32_t xrs1 = *(X+rs1); uint32_t xrs1 = *(X+rs1);
if(rd != 0) { if(rd != 0) {
uint32_t read_res = super::template read_mem<uint32_t>(traits::CSR, csr); uint32_t read_res = super::template read_mem<uint32_t>(traits::CSR, csr);
if(this->core.trap_state>=0x80000000UL) goto TRAP_CSRRW; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_CSRRW;
uint32_t xrd = read_res; uint32_t xrd = read_res;
super::template write_mem<uint32_t>(traits::CSR, csr, xrs1); super::template write_mem<uint32_t>(traits::CSR, csr, xrs1);
if(this->core.trap_state>=0x80000000UL) goto TRAP_CSRRW; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_CSRRW;
*(X+rd) = xrd; *(X+rd) = xrd;
} }
else { else {
super::template write_mem<uint32_t>(traits::CSR, csr, xrs1); super::template write_mem<uint32_t>(traits::CSR, csr, xrs1);
if(this->core.trap_state>=0x80000000UL) goto TRAP_CSRRW; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_CSRRW;
} }
} }
} }
@ -1542,12 +1541,12 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
uint32_t read_res = super::template read_mem<uint32_t>(traits::CSR, csr); uint32_t read_res = super::template read_mem<uint32_t>(traits::CSR, csr);
if(this->core.trap_state>=0x80000000UL) goto TRAP_CSRRS; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_CSRRS;
uint32_t xrd = read_res; uint32_t xrd = read_res;
uint32_t xrs1 = *(X+rs1); uint32_t xrs1 = *(X+rs1);
if(rs1 != 0) { if(rs1 != 0) {
super::template write_mem<uint32_t>(traits::CSR, csr, xrd | xrs1); super::template write_mem<uint32_t>(traits::CSR, csr, xrd | xrs1);
if(this->core.trap_state>=0x80000000UL) goto TRAP_CSRRS; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_CSRRS;
} }
if(rd != 0) { if(rd != 0) {
*(X+rd) = xrd; *(X+rd) = xrd;
@ -1577,12 +1576,12 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
uint32_t read_res = super::template read_mem<uint32_t>(traits::CSR, csr); uint32_t read_res = super::template read_mem<uint32_t>(traits::CSR, csr);
if(this->core.trap_state>=0x80000000UL) goto TRAP_CSRRC; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_CSRRC;
uint32_t xrd = read_res; uint32_t xrd = read_res;
uint32_t xrs1 = *(X+rs1); uint32_t xrs1 = *(X+rs1);
if(rs1 != 0) { if(rs1 != 0) {
super::template write_mem<uint32_t>(traits::CSR, csr, xrd & ~ xrs1); super::template write_mem<uint32_t>(traits::CSR, csr, xrd & ~ xrs1);
if(this->core.trap_state>=0x80000000UL) goto TRAP_CSRRC; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_CSRRC;
} }
if(rd != 0) { if(rd != 0) {
*(X+rd) = xrd; *(X+rd) = xrd;
@ -1612,10 +1611,10 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
uint32_t read_res = super::template read_mem<uint32_t>(traits::CSR, csr); uint32_t read_res = super::template read_mem<uint32_t>(traits::CSR, csr);
if(this->core.trap_state>=0x80000000UL) goto TRAP_CSRRWI; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_CSRRWI;
uint32_t xrd = read_res; uint32_t xrd = read_res;
super::template write_mem<uint32_t>(traits::CSR, csr, (uint32_t)zimm); super::template write_mem<uint32_t>(traits::CSR, csr, (uint32_t)zimm);
if(this->core.trap_state>=0x80000000UL) goto TRAP_CSRRWI; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_CSRRWI;
if(rd != 0) { if(rd != 0) {
*(X+rd) = xrd; *(X+rd) = xrd;
} }
@ -1644,11 +1643,11 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
uint32_t read_res = super::template read_mem<uint32_t>(traits::CSR, csr); uint32_t read_res = super::template read_mem<uint32_t>(traits::CSR, csr);
if(this->core.trap_state>=0x80000000UL) goto TRAP_CSRRSI; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_CSRRSI;
uint32_t xrd = read_res; uint32_t xrd = read_res;
if(zimm != 0) { if(zimm != 0) {
super::template write_mem<uint32_t>(traits::CSR, csr, xrd | (uint32_t)zimm); super::template write_mem<uint32_t>(traits::CSR, csr, xrd | (uint32_t)zimm);
if(this->core.trap_state>=0x80000000UL) goto TRAP_CSRRSI; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_CSRRSI;
} }
if(rd != 0) { if(rd != 0) {
*(X+rd) = xrd; *(X+rd) = xrd;
@ -1678,11 +1677,11 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
uint32_t read_res = super::template read_mem<uint32_t>(traits::CSR, csr); uint32_t read_res = super::template read_mem<uint32_t>(traits::CSR, csr);
if(this->core.trap_state>=0x80000000UL) goto TRAP_CSRRCI; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_CSRRCI;
uint32_t xrd = read_res; uint32_t xrd = read_res;
if(zimm != 0) { if(zimm != 0) {
super::template write_mem<uint32_t>(traits::CSR, csr, xrd & ~ ((uint32_t)zimm)); super::template write_mem<uint32_t>(traits::CSR, csr, xrd & ~ ((uint32_t)zimm));
if(this->core.trap_state>=0x80000000UL) goto TRAP_CSRRCI; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_CSRRCI;
} }
if(rd != 0) { if(rd != 0) {
*(X+rd) = xrd; *(X+rd) = xrd;
@ -1706,8 +1705,8 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
*NEXT_PC = *PC + 4; *NEXT_PC = *PC + 4;
// execute instruction // execute instruction
{ {
super::template write_mem<uint16_t>(traits::FENCE, traits::fencei, imm); super::template write_mem<uint32_t>(traits::FENCE, traits::fencei, imm);
if(this->core.trap_state>=0x80000000UL) goto TRAP_FENCE_I; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_FENCE_I;
} }
TRAP_FENCE_I:break; TRAP_FENCE_I:break;
}// @suppress("No break at end of case") }// @suppress("No break at end of case")
@ -1731,7 +1730,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
int64_t res = (int64_t)(int32_t)*(X+rs1) * (int64_t)(int32_t)*(X+rs2); int64_t res = (int64_t)((int64_t)(int32_t)*(X+rs1) * (int64_t)(int32_t)*(X+rs2));
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)res; *(X+rd) = (uint32_t)res;
} }
@ -1759,7 +1758,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
int64_t res = (int64_t)(int32_t)*(X+rs1) * (int64_t)(int32_t)*(X+rs2); int64_t res = (int64_t)((int64_t)(int32_t)*(X+rs1) * (int64_t)(int32_t)*(X+rs2));
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)(res >> traits::XLEN); *(X+rd) = (uint32_t)(res >> traits::XLEN);
} }
@ -1787,7 +1786,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
int64_t res = (int64_t)(int32_t)*(X+rs1) * (uint64_t)*(X+rs2); int64_t res = (int64_t)((int64_t)(int32_t)*(X+rs1) * (uint64_t)*(X+rs2));
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)(res >> traits::XLEN); *(X+rd) = (uint32_t)(res >> traits::XLEN);
} }
@ -1815,7 +1814,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
uint64_t res = (uint64_t)*(X+rs1) * (uint64_t)*(X+rs2); uint64_t res = (uint64_t)((uint64_t)*(X+rs1) * (uint64_t)*(X+rs2));
if(rd != 0) { if(rd != 0) {
*(X+rd) = (uint32_t)(res >> traits::XLEN); *(X+rd) = (uint32_t)(res >> traits::XLEN);
} }
@ -1852,11 +1851,11 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
*(X+rd) = MMIN; *(X+rd) = MMIN;
} }
else { else {
*(X+rd) = dividend / divisor; *(X+rd) = (uint32_t)(dividend / divisor);
} }
} }
else { else {
*(X+rd) = (int32_t)- 1; *(X+rd) = (uint32_t)- 1;
} }
} }
} }
@ -1885,12 +1884,12 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
else { else {
if(*(X+rs2) != 0) { if(*(X+rs2) != 0) {
if(rd != 0) { if(rd != 0) {
*(X+rd) = *(X+rs1) / *(X+rs2); *(X+rd) = (uint32_t)(*(X+rs1) / *(X+rs2));
} }
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = (int32_t)- 1; *(X+rd) = (uint32_t)- 1;
} }
} }
} }
@ -1926,7 +1925,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = (int32_t)*(X+rs1) % (int32_t)*(X+rs2); *(X+rd) = (uint32_t)((int32_t)*(X+rs1) % (int32_t)*(X+rs2));
} }
} }
} }
@ -1980,7 +1979,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
/* generate console output when executing the command */ /* generate console output when executing the command */
auto mnemonic = fmt::format( auto mnemonic = fmt::format(
"{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "caddi4spn"), "{mnemonic:10} {rd}, {imm:#05x}", fmt::arg("mnemonic", "caddi4spn"),
fmt::arg("rd", name(rd)), fmt::arg("imm", imm)); fmt::arg("rd", name(8+rd)), fmt::arg("imm", imm));
this->core.disass_output(pc.val, mnemonic); this->core.disass_output(pc.val, mnemonic);
} }
// used registers // used registers
@ -1989,7 +1988,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
// execute instruction // execute instruction
{ {
if(imm) { if(imm) {
*(X+rd + 8) = *(X+2) + imm; *(X+rd + 8) = (uint32_t)(*(X+2) + imm);
} }
else { else {
raise(0, 2); raise(0, 2);
@ -2013,10 +2012,10 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
*NEXT_PC = *PC + 2; *NEXT_PC = *PC + 2;
// execute instruction // execute instruction
{ {
uint32_t load_address = *(X+rs1 + 8) + uimm; uint32_t offs = (uint32_t)(*(X+rs1 + 8) + uimm);
int32_t read_res = super::template read_mem<int32_t>(traits::MEM, load_address); int32_t read_res = super::template read_mem<int32_t>(traits::MEM, offs);
if(this->core.trap_state>=0x80000000UL) goto TRAP_CLW; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_CLW;
*(X+rd + 8) = (int32_t)read_res; *(X+rd + 8) = (uint32_t)(int32_t)read_res;
} }
TRAP_CLW:break; TRAP_CLW:break;
}// @suppress("No break at end of case") }// @suppress("No break at end of case")
@ -2036,9 +2035,9 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
*NEXT_PC = *PC + 2; *NEXT_PC = *PC + 2;
// execute instruction // execute instruction
{ {
uint32_t load_address = *(X+rs1 + 8) + uimm; uint32_t offs = (uint32_t)(*(X+rs1 + 8) + uimm);
super::template write_mem<uint32_t>(traits::MEM, load_address, (int32_t)*(X+rs2 + 8)); super::template write_mem<uint32_t>(traits::MEM, offs, (uint32_t)*(X+rs2 + 8));
if(this->core.trap_state>=0x80000000UL) goto TRAP_CSW; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_CSW;
} }
TRAP_CSW:break; TRAP_CSW:break;
}// @suppress("No break at end of case") }// @suppress("No break at end of case")
@ -2062,7 +2061,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(rs1 != 0) { if(rs1 != 0) {
*(X+rs1) = *(X+rs1) + (int8_t)sext<6>(imm); *(X+rs1) = (uint32_t)(*(X+rs1) + (int8_t)sext<6>(imm));
} }
} }
} }
@ -2095,9 +2094,9 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
*NEXT_PC = *PC + 2; *NEXT_PC = *PC + 2;
// execute instruction // execute instruction
{ {
*(X+1) = *PC + 2; *(X+1) = (uint32_t)(*PC + 2);
*NEXT_PC = *PC + (int16_t)sext<12>(imm); *NEXT_PC = (uint32_t)(*PC + (int16_t)sext<12>(imm));
this->core.last_branch = 1; this->core.reg.last_branch = 1;
} }
TRAP_CJAL:break; TRAP_CJAL:break;
}// @suppress("No break at end of case") }// @suppress("No break at end of case")
@ -2121,7 +2120,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = (int8_t)sext<6>(imm); *(X+rd) = (uint32_t)((int8_t)sext<6>(imm));
} }
} }
} }
@ -2146,7 +2145,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
if(rd != 0) { if(rd != 0) {
*(X+rd) = (int32_t)sext<18>(imm); *(X+rd) = (uint32_t)((int32_t)sext<18>(imm));
} }
} }
TRAP_CLUI:break; TRAP_CLUI:break;
@ -2166,7 +2165,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
// execute instruction // execute instruction
{ {
if(nzimm) { if(nzimm) {
*(X+2) = *(X+2) + (int16_t)sext<10>(nzimm); *(X+2) = (uint32_t)(*(X+2) + (int16_t)sext<10>(nzimm));
} }
else { else {
raise(0, 2); raise(0, 2);
@ -2223,11 +2222,11 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
// execute instruction // execute instruction
{ {
if(shamt) { if(shamt) {
*(X+rs1 + 8) = ((int32_t)*(X+rs1 + 8)) >> shamt; *(X+rs1 + 8) = (uint32_t)(((int32_t)*(X+rs1 + 8)) >> shamt);
} }
else { else {
if(traits::XLEN == 128) { if(traits::XLEN == 128) {
*(X+rs1 + 8) = ((int32_t)*(X+rs1 + 8)) >> 64; *(X+rs1 + 8) = (uint32_t)(((int32_t)*(X+rs1 + 8)) >> 64);
} }
} }
} }
@ -2248,7 +2247,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
*NEXT_PC = *PC + 2; *NEXT_PC = *PC + 2;
// execute instruction // execute instruction
{ {
*(X+rs1 + 8) = *(X+rs1 + 8) & (int8_t)sext<6>(imm); *(X+rs1 + 8) = (uint32_t)(*(X+rs1 + 8) & (int8_t)sext<6>(imm));
} }
TRAP_CANDI:break; TRAP_CANDI:break;
}// @suppress("No break at end of case") }// @suppress("No break at end of case")
@ -2267,7 +2266,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
*NEXT_PC = *PC + 2; *NEXT_PC = *PC + 2;
// execute instruction // execute instruction
{ {
*(X+rd + 8) = *(X+rd + 8) - *(X+rs2 + 8); *(X+rd + 8) = (uint32_t)(*(X+rd + 8) - *(X+rs2 + 8));
} }
TRAP_CSUB:break; TRAP_CSUB:break;
}// @suppress("No break at end of case") }// @suppress("No break at end of case")
@ -2341,8 +2340,8 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
*NEXT_PC = *PC + 2; *NEXT_PC = *PC + 2;
// execute instruction // execute instruction
{ {
*NEXT_PC = *PC + (int16_t)sext<12>(imm); *NEXT_PC = (uint32_t)(*PC + (int16_t)sext<12>(imm));
this->core.last_branch = 1; this->core.reg.last_branch = 1;
} }
TRAP_CJ:break; TRAP_CJ:break;
}// @suppress("No break at end of case") }// @suppress("No break at end of case")
@ -2362,8 +2361,8 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
// execute instruction // execute instruction
{ {
if(*(X+rs1 + 8) == 0) { if(*(X+rs1 + 8) == 0) {
*NEXT_PC = *PC + (int16_t)sext<9>(imm); *NEXT_PC = (uint32_t)(*PC + (int16_t)sext<9>(imm));
this->core.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
TRAP_CBEQZ:break; TRAP_CBEQZ:break;
@ -2384,8 +2383,8 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
// execute instruction // execute instruction
{ {
if(*(X+rs1 + 8) != 0) { if(*(X+rs1 + 8) != 0) {
*NEXT_PC = *PC + (int16_t)sext<9>(imm); *NEXT_PC = (uint32_t)(*PC + (int16_t)sext<9>(imm));
this->core.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
TRAP_CBNEZ:break; TRAP_CBNEZ:break;
@ -2435,10 +2434,10 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
int32_t read_res = super::template read_mem<int32_t>(traits::MEM, *(X+2) + uimm); uint32_t offs = (uint32_t)(*(X+2) + uimm);
if(this->core.trap_state>=0x80000000UL) goto TRAP_CLWSP; int32_t read_res = super::template read_mem<int32_t>(traits::MEM, offs);
int32_t res = read_res; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_CLWSP;
*(X+rd) = (int32_t)res; *(X+rd) = (uint32_t)(int32_t)read_res;
} }
} }
TRAP_CLWSP:break; TRAP_CLWSP:break;
@ -2485,7 +2484,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
{ {
if(rs1 && rs1 < traits::RFS) { if(rs1 && rs1 < traits::RFS) {
*NEXT_PC = *(X+rs1 % traits::RFS) & ~ 0x1; *NEXT_PC = *(X+rs1 % traits::RFS) & ~ 0x1;
this->core.last_branch = 1; this->core.reg.last_branch = 1;
} }
else { else {
raise(0, 2); raise(0, 2);
@ -2526,7 +2525,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
if(rd != 0) { if(rd != 0) {
*(X+rd) = *(X+rd) + *(X+rs2); *(X+rd) = (uint32_t)(*(X+rd) + *(X+rs2));
} }
} }
} }
@ -2551,9 +2550,9 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
} }
else { else {
uint32_t new_pc = *(X+rs1); uint32_t new_pc = *(X+rs1);
*(X+1) = *PC + 2; *(X+1) = (uint32_t)(*PC + 2);
*NEXT_PC = new_pc & ~ 0x1; *NEXT_PC = new_pc & ~ 0x1;
this->core.last_branch = 1; this->core.reg.last_branch = 1;
} }
} }
TRAP_CJALR:break; TRAP_CJALR:break;
@ -2590,9 +2589,9 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
raise(0, 2); raise(0, 2);
} }
else { else {
uint32_t offs = *(X+2) + uimm; uint32_t offs = (uint32_t)(*(X+2) + uimm);
super::template write_mem<uint32_t>(traits::MEM, offs, (uint32_t)*(X+rs2)); super::template write_mem<uint32_t>(traits::MEM, offs, (uint32_t)*(X+rs2));
if(this->core.trap_state>=0x80000000UL) goto TRAP_CSWSP; if(this->core.reg.trap_state>=0x80000000UL) goto TRAP_CSWSP;
} }
} }
TRAP_CSWSP:break; TRAP_CSWSP:break;
@ -2618,8 +2617,8 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
// post execution stuff // post execution stuff
process_spawn_blocks(); process_spawn_blocks();
if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, static_cast<unsigned>(inst_id)); if(this->sync_exec && POST_SYNC) this->do_sync(POST_SYNC, static_cast<unsigned>(inst_id));
// if(!this->core.trap_state) // update trap state if there is a pending interrupt // if(!this->core.reg.trap_state) // update trap state if there is a pending interrupt
// this->core.trap_state = this->core.pending_trap; // this->core.reg.trap_state = this->core.reg.pending_trap;
// trap check // trap check
if(trap_state!=0){ if(trap_state!=0){
super::core.enter_trap(trap_state, pc.val, instr); super::core.enter_trap(trap_state, pc.val, instr);
@ -2630,7 +2629,7 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
cycle++; cycle++;
pc.val=*NEXT_PC; pc.val=*NEXT_PC;
this->core.reg.PC = this->core.reg.NEXT_PC; this->core.reg.PC = this->core.reg.NEXT_PC;
this->core.trap_state = this->core.pending_trap; this->core.reg.trap_state = this->core.reg.pending_trap;
} }
} }
return pc; return pc;
@ -2646,3 +2645,30 @@ std::unique_ptr<vm_if> create<arch::tgc_c>(arch::tgc_c *core, unsigned short por
} }
} // namespace interp } // namespace interp
} // namespace iss } // namespace iss
#include <iss/factory.h>
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/arch/riscv_hart_mu_p.h>
namespace iss {
namespace {
std::array<bool, 2> dummy = {
core_factory::instance().register_creator("tgc_c|m_p|interp", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
auto* cpu = new iss::arch::riscv_hart_m_p<iss::arch::tgc_c>();
auto vm = new interp::tgc_c::vm_impl<arch::tgc_c>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
return {cpu_ptr{cpu}, vm_ptr{vm}};
}),
core_factory::instance().register_creator("tgc_c|mu_p|interp", [](unsigned port, void*) -> std::tuple<cpu_ptr, vm_ptr>{
auto* cpu = new iss::arch::riscv_hart_mu_p<iss::arch::tgc_c>();
auto vm = new interp::tgc_c::vm_impl<arch::tgc_c>(*cpu, false);
if (port != 0) debugger::server<debugger::gdb_session>::run_server(vm, port);
return {cpu_ptr{cpu}, vm_ptr{vm}};
})
};
}
}
extern "C" {
bool* get_tgc_c_interp_creators() {
return iss::dummy.data();
}
}

File diff suppressed because it is too large Load Diff