Compare commits
19 Commits
c792f50427
...
feature/is
Author | SHA1 | Date | |
---|---|---|---|
a6c7b1427e | |||
250ea3c980 | |||
7b31b8ca8e | |||
91a23a4a18 | |||
21d3250e1a | |||
2b094c3162 | |||
a32c83e1be | |||
7e45a25218 | |||
87b4082633 | |||
4dbc7433a5 | |||
99a9970ddd | |||
0b5de90fb1 | |||
15cd36dcd4 | |||
2281ec4144 | |||
11c481cec2 | |||
60d07f2eb6 | |||
a123beb301 | |||
ee6218279e | |||
ce5b2e60b9 |
1
.project
1
.project
@ -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>
|
||||||
|
@ -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)
|
||||||
@ -182,7 +186,10 @@ 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)
|
||||||
|
537
TGC_C_instr.yaml
Normal file
537
TGC_C_instr.yaml
Normal 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
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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() {
|
||||||
|
@ -30,8 +30,6 @@
|
|||||||
*
|
*
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
<%
|
<%
|
||||||
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;
|
||||||
}
|
}
|
||||||
@ -57,9 +55,6 @@ def byteSize(int size){
|
|||||||
return 128;
|
return 128;
|
||||||
}
|
}
|
||||||
def getCString(def val){
|
def getCString(def val){
|
||||||
if(val instanceof BigIntegerWithRadix)
|
|
||||||
return ((BigIntegerWithRadix)val).toCString()
|
|
||||||
else
|
|
||||||
return val.toString()
|
return val.toString()
|
||||||
}
|
}
|
||||||
%>
|
%>
|
||||||
@ -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)
|
||||||
@ -170,12 +165,6 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
|
|||||||
uint32_t last_branch = 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;
|
||||||
|
@ -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"}<%}}%>
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -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>
|
||||||
@ -207,9 +206,11 @@ private:
|
|||||||
${it}<%}%>
|
${it}<%}%>
|
||||||
}
|
}
|
||||||
auto cur_pc_val = tu.constant(pc.val, traits::reg_bit_widths[traits::PC]);
|
auto cur_pc_val = tu.constant(pc.val, traits::reg_bit_widths[traits::PC]);
|
||||||
pc=pc+4;
|
pc=pc+ ${instr.length/8};
|
||||||
|
gen_set_pc(tu, pc, traits::NEXT_PC);
|
||||||
tu.open_scope();<%instr.behavior.eachLine{%>
|
tu.open_scope();<%instr.behavior.eachLine{%>
|
||||||
${it}<%}%>
|
${it}<%}%>
|
||||||
|
tu.close_scope();
|
||||||
vm_base<ARCH>::gen_sync(tu, POST_SYNC,${idx});
|
vm_base<ARCH>::gen_sync(tu, POST_SYNC,${idx});
|
||||||
gen_trap_check(tu);
|
gen_trap_check(tu);
|
||||||
return returnValue;
|
return returnValue;
|
||||||
@ -254,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::addr_t upper_bits = ~traits::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;
|
||||||
@ -308,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();
|
||||||
|
}
|
||||||
|
}
|
@ -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}
|
|
||||||
}<%}%>
|
|
||||||
]
|
|
||||||
}
|
|
@ -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_ */
|
|
@ -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*>(®);
|
|
||||||
}
|
|
||||||
|
|
||||||
${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
|
|
||||||
}
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
@ -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,12 +825,12 @@ 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;
|
||||||
}
|
}
|
||||||
@ -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,19 +919,19 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
|
|||||||
if(!pmp_check(access, addr, length) && (access&access_type::DEBUG) != access_type::DEBUG) {
|
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(is_fetch(access) && (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;
|
||||||
}
|
}
|
||||||
@ -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;
|
||||||
|
@ -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() {
|
||||||
|
@ -53,7 +53,7 @@ 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, PGMASK=0b111111111111, 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;
|
||||||
|
|
||||||
@ -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)
|
||||||
@ -256,12 +256,6 @@ struct tgc_c: public arch_if {
|
|||||||
uint32_t last_branch = 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;
|
||||||
|
@ -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 {
|
||||||
|
|
||||||
@ -57,6 +63,48 @@ std::tuple<cpu_ptr, vm_ptr> create_cpu(std::string const& backend, unsigned gdb_
|
|||||||
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_ */
|
||||||
|
81
src/main.cpp
81
src/main.cpp
@ -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,53 +113,24 @@ 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 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;
|
||||||
@ -172,27 +143,29 @@ int main(int argc, char *argv[]) {
|
|||||||
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){
|
||||||
|
@ -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();
|
||||||
@ -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:
|
||||||
|
33
src/sysc/register_tgc_c.cpp
Normal file
33
src/sysc/register_tgc_c.cpp
Normal 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
148
src/sysc/sc_core_adapter.h
Normal 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_ */
|
@ -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
Reference in New Issue
Block a user