19 Commits

Author SHA1 Message Date
a6c7b1427e fixes missing namespaces 2023-07-09 20:15:12 +02:00
250ea3c980 extends factory to support SystemC core wrapper 2023-07-09 18:19:59 +02:00
7b31b8ca8e adds updated generated files 2023-07-09 16:58:47 +02:00
91a23a4a18 Merge branch 'develop' of https://git.minres.com/DBT-RISE/DBT-RISE-TGC into develop 2023-07-09 16:55:06 +02:00
21d3250e1a changes templates 2023-07-09 16:53:59 +02:00
2b094c3162 removes trace compass nature 2023-07-06 10:39:59 +02:00
a32c83e1be fixes CLI handling of plugin paramters in ISS 2023-07-05 08:32:05 +02:00
7e45a25218 adds a instr yaml for TGC 2023-07-05 08:28:42 +02:00
87b4082633 Merge branch 'tmp' into develop 2023-07-03 14:22:50 +02:00
4dbc7433a5 fixes cause CSR handling 2023-06-12 17:38:56 +02:00
99a9970ddd fixes sysc compile issues 2023-06-12 09:58:24 +02:00
0b5de90fb1 changes [m|u]cause rd/wr handling 2023-06-11 18:29:58 +02:00
15cd36dcd4 adds fix for compressed instructions and reads 2023-06-05 17:57:38 +02:00
2281ec4144 corrects errors and adds new backend and 2023-06-05 15:18:27 +02:00
11c481cec2 adds verbosity to error 2023-06-05 15:17:16 +02:00
60d07f2eb6 changes default loglevel to info for tgc-sim 2023-06-01 06:55:21 +02:00
a123beb301 fixes duplicate variable declaration and templates 2023-05-27 10:20:49 +02:00
ee6218279e adapts to latest code gen changes 2023-05-25 12:52:30 +02:00
ce5b2e60b9 amends template to fix branching instructions 2023-05-22 17:00:36 +02:00
24 changed files with 1688 additions and 1272 deletions

View File

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

View File

@ -40,11 +40,15 @@ set(LIB_SOURCES
if(TARGET ${CORE_NAME}_cpp) if(TARGET ${CORE_NAME}_cpp)
list(APPEND LIB_SOURCES ${${CORE_NAME}_OUTPUT_FILES}) list(APPEND LIB_SOURCES ${${CORE_NAME}_OUTPUT_FILES})
else() else()
FILE(GLOB GEN_SOURCES FILE(GLOB GEN_ISS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/iss/arch/*.cpp)
${CMAKE_CURRENT_SOURCE_DIR}/src-gen/iss/arch/*.cpp FILE(GLOB GEN_VM_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/interp/vm_*.cpp)
${CMAKE_CURRENT_SOURCE_DIR}/src-gen/vm/interp/vm_*.cpp list(APPEND LIB_SOURCES ${GEN_ISS_SOURCES} ${GEN_VM_SOURCES})
) foreach(FILEPATH ${GEN_ISS_SOURCES})
list(APPEND LIB_SOURCES ${GEN_SOURCES}) get_filename_component(CORE ${FILEPATH} NAME_WE)
string(TOUPPER ${CORE} CORE)
list(APPEND LIB_DEFINES CORE_${CORE})
endforeach()
message("Defines are ${LIB_DEFINES}")
endif() endif()
if(TARGET RapidJSON OR TARGET RapidJSON::RapidJSON) if(TARGET RapidJSON OR TARGET RapidJSON::RapidJSON)
@ -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
View File

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

View File

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

View File

@ -62,8 +62,8 @@ void ${coreDef.name.toLowerCase()}::reset(uint64_t address) {
reg.PC=address; reg.PC=address;
reg.NEXT_PC=reg.PC; reg.NEXT_PC=reg.PC;
reg.PRIV=0x3; reg.PRIV=0x3;
trap_state=0; reg.trap_state=0;
icount=0; reg.icount=0;
} }
uint8_t *${coreDef.name.toLowerCase()}::get_regs_base_ptr() { uint8_t *${coreDef.name.toLowerCase()}::get_regs_base_ptr() {

View File

@ -30,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,10 +55,7 @@ def byteSize(int size){
return 128; return 128;
} }
def getCString(def val){ def getCString(def val){
if(val instanceof BigIntegerWithRadix) return val.toString()
return ((BigIntegerWithRadix)val).toCString()
else
return val.toString()
} }
%> %>
#ifndef _${coreDef.name.toUpperCase()}_H_ #ifndef _${coreDef.name.toUpperCase()}_H_
@ -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;

View File

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

View File

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

View File

@ -31,7 +31,6 @@
*******************************************************************************/ *******************************************************************************/
#include <iss/arch/${coreDef.name.toLowerCase()}.h> #include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <iss/arch/riscv_hart_m_p.h>
#include <iss/debugger/gdb_session.h> #include <iss/debugger/gdb_session.h>
#include <iss/debugger/server.h> #include <iss/debugger/server.h>
#include <iss/iss.h> #include <iss/iss.h>
@ -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();
}
}

View File

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

View File

@ -1,223 +0,0 @@
/*******************************************************************************
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/
<%
import com.minres.coredsl.coreDsl.Register
import com.minres.coredsl.coreDsl.RegisterFile
import com.minres.coredsl.coreDsl.RegisterAlias
def getTypeSize(size){
if(size > 32) 64 else if(size > 16) 32 else if(size > 8) 16 else 8
}
def getOriginalName(reg){
if( reg.original instanceof RegisterFile) {
if( reg.index != null ) {
return reg.original.name+generator.generateHostCode(reg.index)
} else {
return reg.original.name
}
} else if(reg.original instanceof Register){
return reg.original.name
}
}
def getRegisterNames(){
def regNames = []
allRegs.each { reg ->
if( reg instanceof RegisterFile) {
(reg.range.right..reg.range.left).each{
regNames+=reg.name.toLowerCase()+it
}
} else if(reg instanceof Register){
regNames+=reg.name.toLowerCase()
}
}
return regNames
}
def getRegisterAliasNames(){
def regMap = allRegs.findAll{it instanceof RegisterAlias }.collectEntries {[getOriginalName(it), it.name]}
return allRegs.findAll{it instanceof Register || it instanceof RegisterFile}.collect{reg ->
if( reg instanceof RegisterFile) {
return (reg.range.right..reg.range.left).collect{ (regMap[reg.name]?:regMap[reg.name+it]?:reg.name.toLowerCase()+it).toLowerCase() }
} else if(reg instanceof Register){
regMap[reg.name]?:reg.name.toLowerCase()
}
}.flatten()
}
%>
#ifndef _${coreDef.name.toUpperCase()}_H_
#define _${coreDef.name.toUpperCase()}_H_
#include <array>
#include <iss/arch/traits.h>
#include <iss/arch_if.h>
#include <iss/vm_if.h>
namespace iss {
namespace arch {
struct ${coreDef.name.toLowerCase()};
template <> struct traits<${coreDef.name.toLowerCase()}> {
constexpr static char const* const core_type = "${coreDef.name}";
static constexpr std::array<const char*, ${getRegisterNames().size}> reg_names{
{"${getRegisterNames().join("\", \"")}"}};
static constexpr std::array<const char*, ${getRegisterAliasNames().size}> reg_aliases{
{"${getRegisterAliasNames().join("\", \"")}"}};
enum constants {${coreDef.constants.collect{c -> c.name+"="+c.value}.join(', ')}};
constexpr static unsigned FP_REGS_SIZE = ${coreDef.constants.find {it.name=='FLEN'}?.value?:0};
enum reg_e {<%
allRegs.each { reg ->
if( reg instanceof RegisterFile) {
(reg.range.right..reg.range.left).each{%>
${reg.name}${it},<%
}
} else if(reg instanceof Register){ %>
${reg.name},<%
}
}%>
NUM_REGS,
NEXT_${pc.name}=NUM_REGS,
TRAP_STATE,
PENDING_TRAP,
MACHINE_STATE,
LAST_BRANCH,
ICOUNT<%
allRegs.each { reg ->
if(reg instanceof RegisterAlias){ def aliasname=getOriginalName(reg)%>,
${reg.name} = ${aliasname}<%
}
}%>
};
using reg_t = uint${regDataWidth}_t;
using addr_t = uint${addrDataWidth}_t;
using code_word_t = uint${addrDataWidth}_t; //TODO: check removal
using virt_addr_t = iss::typed_addr_t<iss::address_type::VIRTUAL>;
using phys_addr_t = iss::typed_addr_t<iss::address_type::PHYSICAL>;
static constexpr std::array<const uint32_t, ${regSizes.size}> reg_bit_widths{
{${regSizes.join(",")}}};
static constexpr std::array<const uint32_t, ${regOffsets.size}> reg_byte_offsets{
{${regOffsets.join(",")}}};
static const uint64_t addr_mask = (reg_t(1) << (XLEN - 1)) | ((reg_t(1) << (XLEN - 1)) - 1);
enum sreg_flag_e { FLAGS };
enum mem_type_e { ${allSpaces.collect{s -> s.name}.join(', ')} };
};
struct ${coreDef.name.toLowerCase()}: public arch_if {
using virt_addr_t = typename traits<${coreDef.name.toLowerCase()}>::virt_addr_t;
using phys_addr_t = typename traits<${coreDef.name.toLowerCase()}>::phys_addr_t;
using reg_t = typename traits<${coreDef.name.toLowerCase()}>::reg_t;
using addr_t = typename traits<${coreDef.name.toLowerCase()}>::addr_t;
${coreDef.name.toLowerCase()}();
~${coreDef.name.toLowerCase()}();
void reset(uint64_t address=0) override;
uint8_t* get_regs_base_ptr() override;
/// deprecated
void get_reg(short idx, std::vector<uint8_t>& value) override {}
void set_reg(short idx, const std::vector<uint8_t>& value) override {}
/// deprecated
bool get_flag(int flag) override {return false;}
void set_flag(int, bool value) override {};
/// deprecated
void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {};
inline uint64_t get_icount() { return reg.icount; }
inline bool should_stop() { return interrupt_sim; }
inline uint64_t stop_code() { return interrupt_sim; }
inline phys_addr_t v2p(const iss::addr_t& addr){
if (addr.space != traits<${coreDef.name.toLowerCase()}>::MEM || addr.type == iss::address_type::PHYSICAL ||
addr_mode[static_cast<uint16_t>(addr.access)&0x3]==address_type::PHYSICAL) {
return phys_addr_t(addr.access, addr.space, addr.val&traits<${coreDef.name.toLowerCase()}>::addr_mask);
} else
return virt2phys(addr);
}
virtual phys_addr_t virt2phys(const iss::addr_t& addr);
virtual iss::sync_type needed_sync() const { return iss::NO_SYNC; }
inline uint32_t get_last_branch() { return reg.last_branch; }
protected:
struct ${coreDef.name}_regs {<%
allRegs.each { reg ->
if( reg instanceof RegisterFile) {
(reg.range.right..reg.range.left).each{%>
uint${generator.getSize(reg)}_t ${reg.name}${it} = 0;<%
}
} else if(reg instanceof Register){ %>
uint${generator.getSize(reg)}_t ${reg.name} = 0;<%
}
}%>
uint${generator.getSize(pc)}_t NEXT_${pc.name} = 0;
uint32_t trap_state = 0, pending_trap = 0, machine_state = 0, last_branch = 0;
uint64_t icount = 0;
} reg;
std::array<address_type, 4> addr_mode;
uint64_t interrupt_sim=0;
<%
def fcsr = allRegs.find {it.name=='FCSR'}
if(fcsr != null) {%>
uint${generator.getSize(fcsr)}_t get_fcsr(){return reg.FCSR;}
void set_fcsr(uint${generator.getSize(fcsr)}_t val){reg.FCSR = val;}
<%} else { %>
uint32_t get_fcsr(){return 0;}
void set_fcsr(uint32_t val){}
<%}%>
};
}
}
#endif /* _${coreDef.name.toUpperCase()}_H_ */

View File

@ -1,107 +0,0 @@
/*******************************************************************************
* Copyright (C) 2017, 2018 MINRES Technologies GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*******************************************************************************/
<%
import com.minres.coredsl.coreDsl.Register
import com.minres.coredsl.coreDsl.RegisterFile
import com.minres.coredsl.coreDsl.RegisterAlias
def getOriginalName(reg){
if( reg.original instanceof RegisterFile) {
if( reg.index != null ) {
return reg.original.name+generator.generateHostCode(reg.index)
} else {
return reg.original.name
}
} else if(reg.original instanceof Register){
return reg.original.name
}
}
def getRegisterNames(){
def regNames = []
allRegs.each { reg ->
if( reg instanceof RegisterFile) {
(reg.range.right..reg.range.left).each{
regNames+=reg.name.toLowerCase()+it
}
} else if(reg instanceof Register){
regNames+=reg.name.toLowerCase()
}
}
return regNames
}
def getRegisterAliasNames(){
def regMap = allRegs.findAll{it instanceof RegisterAlias }.collectEntries {[getOriginalName(it), it.name]}
return allRegs.findAll{it instanceof Register || it instanceof RegisterFile}.collect{reg ->
if( reg instanceof RegisterFile) {
return (reg.range.right..reg.range.left).collect{ (regMap[reg.name]?:regMap[reg.name+it]?:reg.name.toLowerCase()+it).toLowerCase() }
} else if(reg instanceof Register){
regMap[reg.name]?:reg.name.toLowerCase()
}
}.flatten()
}
%>
#include "util/ities.h"
#include <util/logging.h>
#include <iss/arch/${coreDef.name.toLowerCase()}.h>
#include <cstdio>
#include <cstring>
#include <fstream>
using namespace iss::arch;
constexpr std::array<const char*, ${getRegisterNames().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_names;
constexpr std::array<const char*, ${getRegisterAliasNames().size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_aliases;
constexpr std::array<const uint32_t, ${regSizes.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_bit_widths;
constexpr std::array<const uint32_t, ${regOffsets.size}> iss::arch::traits<iss::arch::${coreDef.name.toLowerCase()}>::reg_byte_offsets;
${coreDef.name.toLowerCase()}::${coreDef.name.toLowerCase()}() {
reg.icount = 0;
}
${coreDef.name.toLowerCase()}::~${coreDef.name.toLowerCase()}() = default;
void ${coreDef.name.toLowerCase()}::reset(uint64_t address) {
for(size_t i=0; i<traits<${coreDef.name.toLowerCase()}>::NUM_REGS; ++i) set_reg(i, std::vector<uint8_t>(sizeof(traits<${coreDef.name.toLowerCase()}>::reg_t),0));
reg.PC=address;
reg.NEXT_PC=reg.PC;
reg.trap_state=0;
reg.machine_state=0x3;
reg.icount=0;
}
uint8_t *${coreDef.name.toLowerCase()}::get_regs_base_ptr() {
return reinterpret_cast<uint8_t*>(&reg);
}
${coreDef.name.toLowerCase()}::phys_addr_t ${coreDef.name.toLowerCase()}::virt2phys(const iss::addr_t &pc) {
return phys_addr_t(pc); // change logical address to physical address
}

View File

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

View File

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

View File

@ -284,6 +284,7 @@ public:
} }
riscv_hart_mu_p(feature_config cfg = feature_config{}); riscv_hart_mu_p(feature_config cfg = feature_config{});
virtual ~riscv_hart_mu_p() = default; virtual ~riscv_hart_mu_p() = default;
void reset(uint64_t address) override; void reset(uint64_t address) override;
@ -304,7 +305,7 @@ public:
void disass_output(uint64_t pc, const std::string instr) override { void disass_output(uint64_t pc, const std::string instr) override {
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]", CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]",
pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->icount + cycle_offset); pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.icount + cycle_offset);
}; };
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; } iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
@ -332,17 +333,17 @@ protected:
uint64_t get_next_pc() override { return arch.reg.NEXT_PC; }; uint64_t get_next_pc() override { return arch.reg.NEXT_PC; };
uint64_t get_instr_word() override { return arch.instruction; } uint64_t get_instr_word() override { return arch.reg.instruction; }
uint64_t get_instr_count() override { return arch.icount; } uint64_t get_instr_count() override { return arch.reg.icount; }
uint64_t get_pendig_traps() override { return arch.trap_state; } uint64_t get_pendig_traps() override { return arch.reg.trap_state; }
uint64_t get_total_cycles() override { return arch.icount + arch.cycle_offset; } uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; }; void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; };
bool is_branch_taken() override { return arch.last_branch; }; bool is_branch_taken() override { return arch.reg.last_branch; };
riscv_hart_mu_p<BASE, FEAT> &arch; riscv_hart_mu_p<BASE, FEAT> &arch;
}; };
@ -446,7 +447,7 @@ protected:
std::vector<std::function<mem_write_f>> memfn_write; std::vector<std::function<mem_write_f>> memfn_write;
void insert_mem_range(uint64_t, uint64_t, std::function<mem_read_f>, std::function<mem_write_f>); void insert_mem_range(uint64_t, uint64_t, std::function<mem_read_f>, std::function<mem_write_f>);
feature_config cfg; feature_config cfg;
unsigned mcause_max_irq{(FEAT&features_e::FEAT_CLIC)?4096:16}; uint64_t mcause_max_irq{(FEAT&features_e::FEAT_CLIC)?4096:16};
inline bool debug_mode_active() {return this->reg.PRIV&0x4;} inline bool debug_mode_active() {return this->reg.PRIV&0x4;}
std::pair<std::function<mem_read_f>, std::function<mem_write_f>> std::pair<std::function<mem_read_f>, std::function<mem_write_f>>
@ -689,9 +690,9 @@ template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m
} }
return std::make_pair(entry, true); return std::make_pair(entry, true);
} }
throw std::runtime_error("memory load file is not a valid elf file"); throw std::runtime_error(fmt::format("memory load file {} is not a valid elf file",name));
} }
throw std::runtime_error("memory load file not found"); throw std::runtime_error(fmt::format("memory load file not found, check if {} is a valid file", name));
} }
template<typename BASE, features_e FEAT> template<typename BASE, features_e FEAT>
@ -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;

View File

@ -55,8 +55,8 @@ void tgc_c::reset(uint64_t address) {
reg.PC=address; reg.PC=address;
reg.NEXT_PC=reg.PC; reg.NEXT_PC=reg.PC;
reg.PRIV=0x3; reg.PRIV=0x3;
trap_state=0; reg.trap_state=0;
icount=0; reg.icount=0;
} }
uint8_t *tgc_c::get_regs_base_ptr() { uint8_t *tgc_c::get_regs_base_ptr() {

View File

@ -53,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;

View File

@ -34,6 +34,12 @@
#define _ISS_FACTORY_H_ #define _ISS_FACTORY_H_
#include <iss/iss.h> #include <iss/iss.h>
#include <memory>
#include <unordered_map>
#include <functional>
#include <string>
#include <algorithm>
#include <vector>
namespace iss { namespace iss {
@ -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_ */

View File

@ -31,7 +31,9 @@
*******************************************************************************/ *******************************************************************************/
#include <iostream> #include <iostream>
#include "iss/factory.h" #include <vector>
#include <array>
#include <iss/factory.h>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
@ -61,7 +63,7 @@ int main(int argc, char *argv[]) {
// clang-format off // clang-format off
desc.add_options() desc.add_options()
("help,h", "Print help message") ("help,h", "Print help message")
("verbose,v", po::value<int>()->implicit_value(0), "Sets logging verbosity") ("verbose,v", po::value<int>()->default_value(4), "Sets logging verbosity")
("logfile,l", po::value<std::string>(), "Sets default log file.") ("logfile,l", po::value<std::string>(), "Sets default log file.")
("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly") ("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly")
("gdb-port,g", po::value<unsigned>()->default_value(0), "enable gdb server and specify port to use") ("gdb-port,g", po::value<unsigned>()->default_value(0), "enable gdb server and specify port to use")
@ -71,7 +73,7 @@ int main(int argc, char *argv[]) {
("elf,f", po::value<std::vector<std::string>>(), "ELF file(s) to load") ("elf,f", po::value<std::vector<std::string>>(), "ELF file(s) to load")
("mem,m", po::value<std::string>(), "the memory input file") ("mem,m", po::value<std::string>(), "the memory input file")
("plugin,p", po::value<std::vector<std::string>>(), "plugin to activate") ("plugin,p", po::value<std::vector<std::string>>(), "plugin to activate")
("backend", po::value<std::string>()->default_value("interp"), "the memory input file") ("backend", po::value<std::string>()->default_value("interp"), "the ISS backend to use, options are: interp, tcc")
("isa", po::value<std::string>()->default_value("tgc_c"), "isa to use for simulation"); ("isa", po::value<std::string>()->default_value("tgc_c"), "isa to use for simulation");
// clang-format on // clang-format on
auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run(); auto parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
@ -93,11 +95,9 @@ int main(int argc, char *argv[]) {
LOGGER(DEFAULT)::print_time() = false; LOGGER(DEFAULT)::print_time() = false;
LOGGER(connection)::print_time() = false; LOGGER(connection)::print_time() = false;
if (clim.count("verbose")) { auto l = logging::as_log_level(clim["verbose"].as<int>());
auto l = logging::as_log_level(clim["verbose"].as<int>()); LOGGER(DEFAULT)::reporting_level() = l;
LOGGER(DEFAULT)::reporting_level() = l; LOGGER(connection)::reporting_level() = l;
LOGGER(connection)::reporting_level() = l;
}
if (clim.count("logfile")) { if (clim.count("logfile")) {
// configure the connection logger // configure the connection logger
auto f = fopen(clim["logfile"].as<std::string>().c_str(), "w"); auto f = fopen(clim["logfile"].as<std::string>().c_str(), "w");
@ -113,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){

View File

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

View File

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

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

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

View File

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

File diff suppressed because it is too large Load Diff