diff --git a/.cproject b/.cproject
index 5c92890..2021fe9 100644
--- a/.cproject
+++ b/.cproject
@@ -151,11 +151,8 @@
-
-
-
-
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3b83bf8..cecbbeb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -31,3 +31,4 @@ add_subdirectory(external)
add_subdirectory(dbt-core)
add_subdirectory(sc-components)
add_subdirectory(riscv)
+add_subdirectory(riscv.sc)
diff --git a/dbt-core b/dbt-core
index df6f6eb..1091afc 160000
--- a/dbt-core
+++ b/dbt-core
@@ -1 +1 @@
-Subproject commit df6f6eb713c3c0a2dc10ba29e80d586a9f66a25f
+Subproject commit 1091afcc3045c1bea5508a6be785eed757632452
diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt
index a27d214..8972513 100644
--- a/external/CMakeLists.txt
+++ b/external/CMakeLists.txt
@@ -8,18 +8,16 @@ project("external")
include(Common)
-include_directories( ${PROJECT_SOURCE_DIR}/external/libGIS ${PROJECT_SOURCE_DIR}/external/easyloggingpp/src )
+include_directories( ${PROJECT_SOURCE_DIR}/external/libGIS )
FILE(GLOB ElfioHeaders elfio *.hpp)
FILE(GLOB GISHeaders libGis *.h)
-FILE(GLOB LogHeaders easyloggingpp/src *.h)
-set(LIB_HEADERS ${ElfioHeaders} ${GISHeaders} ${LogHeaders})
+set(LIB_HEADERS ${ElfioHeaders} ${GISHeaders})
set(LIB_SOURCES
libGIS/atmel_generic.c
libGIS/ihex.c
libGIS/srecord.c
- easyloggingpp/src/easylogging++.cc
)
# Define two variables in order not to repeat ourselves.
diff --git a/riscv.sc/CMakeLists.txt b/riscv.sc/CMakeLists.txt
new file mode 100644
index 0000000..1e7d2f3
--- /dev/null
+++ b/riscv.sc/CMakeLists.txt
@@ -0,0 +1,95 @@
+cmake_minimum_required(VERSION 2.8)
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) # main (top) cmake dir
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) # project specific cmake dir
+set(CMAKE_CXX_STANDARD 14) # tODO move up to a general cmake config for all sub projects ?
+
+# CMake useful variables
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
+
+# Set the name of your project here
+project("riscv.sc")
+
+# Set the version number of your project here (format is MAJOR.MINOR.PATCHLEVEL - e.g. 1.0.0)
+set(VERSION_MAJOR "0")
+set(VERSION_MINOR "0")
+set(VERSION_PATCH "1")
+set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
+
+include(Common)
+
+## Git (and its revision)
+find_package(Git QUIET) # if we don't find git or FindGit.cmake is not on the system we ignore it.
+## The Git module will trigger a reconfiguration for each pull that will bring a new revision on the local repository
+set (VCS_REVISION "-1")
+if(GIT_FOUND)
+ include(GetGitRevisionDescription)
+ get_git_head_revision(GIT_REFSPEC GIT_SHA1)
+ message(STATUS "GIT branch ${GIT_REFSPEC}")
+ message(STATUS "GIT revision ${GIT_SHA1}")
+ set (VCS_REVISION ${GIT_SHA1})
+endif()
+
+# This line finds the boost lib and headers.
+set(Boost_NO_BOOST_CMAKE ON) # Don't do a find_package in config mode before searching for a regular boost install.
+find_package(Boost COMPONENTS program_options system thread REQUIRED)
+
+find_package(LLVM REQUIRED CONFIG)
+message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
+message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
+llvm_map_components_to_libnames(llvm_libs support core mcjit x86codegen x86asmparser)
+
+find_package(SystemC)
+if(SystemC_FOUND)
+ add_definitions(-DWITH_SYSTEMC)
+ include_directories(${SystemC_INCLUDE_DIRS})
+ link_directories(${SystemC_LIBRARY_DIRS})
+else(SystemC_FOUND)
+ message( FATAL_ERROR "SystemC library not found." )
+endif(SystemC_FOUND)
+
+if(SCV_FOUND)
+ add_definitions(-DWITH_SCV)
+ link_directories(${SCV_LIBRARY_DIRS})
+endif(SCV_FOUND)
+
+# This sets the include directory for the reference project. This is the -I flag in gcc.
+include_directories(
+ ${PROJECT_SOURCE_DIR}/incl
+ ${LLVM_INCLUDE_DIRS}
+)
+
+add_dependent_subproject(dbt-core)
+add_dependent_subproject(sc-components)
+add_dependent_header(util)
+
+include_directories(
+ ${PROJECT_SOURCE_DIR}/incl
+ ${PROJECT_SOURCE_DIR}/../external/elfio
+ ${PROJECT_SOURCE_DIR}/../external/libGIS
+ ${PROJECT_SOURCE_DIR}/../riscv
+ ${Boost_INCLUDE_DIRS}
+)
+
+
+# Mac needed variables (adapt for your needs - http://www.cmake.org/Wiki/CMake_RPATH_handling#Mac_OS_X_and_the_RPATH)
+set(CMAKE_MACOSX_RPATH ON)
+set(CMAKE_SKIP_BUILD_RPATH FALSE)
+set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
+set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
+set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
+
+add_subdirectory(src)
+
+#
+# SYSTEM PACKAGING (RPM, TGZ, ...)
+# _____________________________________________________________________________
+
+#include(CPackConfig)
+
+#
+# CMAKE PACKAGING (for other CMake projects to use this one easily)
+# _____________________________________________________________________________
+
+#include(PackageConfigurator)
\ No newline at end of file
diff --git a/riscv/fe310.rdl b/riscv.sc/gen_input/fe310.rdl
similarity index 100%
rename from riscv/fe310.rdl
rename to riscv.sc/gen_input/fe310.rdl
diff --git a/riscv/gpio.rdl b/riscv.sc/gen_input/gpio.rdl
similarity index 100%
rename from riscv/gpio.rdl
rename to riscv.sc/gen_input/gpio.rdl
diff --git a/riscv/plic.rdl b/riscv.sc/gen_input/plic.rdl
similarity index 91%
rename from riscv/plic.rdl
rename to riscv.sc/gen_input/plic.rdl
index 67c05ea..ee7b004 100644
--- a/riscv/plic.rdl
+++ b/riscv.sc/gen_input/plic.rdl
@@ -26,12 +26,12 @@ regfile plic_regs {
field {
name = "threshold";
} \threshold[2:0];
- } \threshold @0x0C200000;
+ } \threshold @0x200000;
reg {
name="claim/complete";
desc="interrupt handling completed";
field {
name = "interrupt_claimed";
} interrupt_claimed[31:0];
- } claim_complete @0x0C200004;
+ } claim_complete @0x200004;
};
\ No newline at end of file
diff --git a/riscv.sc/gen_input/spi.rdl b/riscv.sc/gen_input/spi.rdl
new file mode 100644
index 0000000..8c142f4
--- /dev/null
+++ b/riscv.sc/gen_input/spi.rdl
@@ -0,0 +1,174 @@
+regfile spi_regs {
+ lsb0;
+ reg {
+ name="sckdiv";
+ desc="Serial clock divisor";
+ field {
+ name ="div";
+ } div[12];
+ } sckdiv @0x000;
+ reg {
+ name="sckmode";
+ desc="Serial clock mode";
+ field {
+ name="pha";
+ } pha[1];
+ field {
+ name="pol";
+ } pol[1];
+ } sckmode @0x004;
+ reg {
+ name="csid";
+ desc="Chip select ID";
+ field {
+ name="csid";
+ } csid[32];
+ } csid @0x010;
+ reg {
+ name="csdef";
+ desc="Chip select default";
+ field {
+ name="csdef";
+ } csdef[32];
+ } csdef @0x014;
+ reg {
+ name="csmode";
+ desc="Chip select mode";
+ field {
+ name="mode";
+ } mode[2];
+ } csmode @0x018;
+ reg {
+ name="delay0";
+ desc="Delay control 0";
+ field {
+ name="cssck";
+ } cssck[7:0];
+ field {
+ name ="sckcs";
+ } sckcs[23:16];
+ } delay0 @0x028;
+ reg {
+ name="delay1";
+ desc="Delay control 1";
+ field {
+ name="intercs";
+ }intercs[15:0];
+ field {
+ name="interxfr";
+ } interxfr[23:16];
+ } delay1 @0x02C;
+ reg {
+ name="fmt";
+ desc="Frame format";
+ field{
+ name ="proto";
+ }proto[2];
+ field {
+ name="endian";
+ } endian[1];
+ field {
+ name="dir";
+ } dir[1];
+ field {
+ name="len";
+ } len[19:16];
+ } fmt @0x040;
+ reg {
+ name="txdata";
+ desc="Tx FIFO data";
+ field {
+ name="data";
+ } data[8];
+ field {
+ name="full";
+ } full[31:31];
+ } txdata @0x048;
+ reg {
+ name="rxdata";
+ desc="Rx FIFO data";
+ field{
+ name="data";
+ } data[8];
+ field{
+ name="empty";
+ } empty[31:31];
+ } rxdata @0x04C;
+ reg {
+ name="txmark";
+ desc="Tx FIFO watermark";
+ field {
+ name="txmark";
+ } txmark[3];
+ } txmark @0x050;
+ reg {
+ name="rxmark";
+ desc="Rx FIFO watermark";
+ field {
+ name="rxmark";
+ } rxmark[3];
+ } rxmark @0x054;
+ reg {
+ name="fctrl";
+ desc="SPI flash interface control";
+ field {
+ name="en";
+ } en[1];
+ } fctrl @0x060;
+ reg {
+ name="ffmt";
+ desc="SPI flash instruction format";
+ field {
+ name="cmd_en";
+ reset=0x1;
+ } cmd_en[1];
+ field {
+ name="addr_len";
+ reset=0x3;
+ } addr_len[2];
+ field {
+ name="pad_cnt";
+ reset=0x0;
+ } pad_cnt[4];
+ field {
+ name="cmd_proto";
+ reset=0x0;
+ } cmd_proto[2];
+ field {
+ name="addr_proto";
+ reset=0x0;
+ } addr_proto[2];
+ field {
+ name="data_proto";
+ reset=0x0;
+ } data_proto[2];
+ field {
+ name="cmd_code";
+ reset=0x3;
+ } cmd_code[23:16];
+ field {
+ name="pad_code";
+ reset=0x0;
+ } pad_code[8];
+ } ffmt @0x064;
+ reg {
+ name="ie";
+ desc="SPI interrupt enable";
+ field{
+ name="txwm";
+ } txwm[1];
+ field{
+ name="rxwm";
+ } rxwm[1];
+ } ie @0x070;
+ reg {
+ name="ip";
+ desc="SPI interrupt pending";
+ field{
+ name="txwm";
+ } txwm[1];
+ field{
+ name="rxwm";
+ } rxwm[1];
+ } ip @0x074;
+};
diff --git a/riscv.sc/gen_input/uart.rdl b/riscv.sc/gen_input/uart.rdl
new file mode 100644
index 0000000..a7aef85
--- /dev/null
+++ b/riscv.sc/gen_input/uart.rdl
@@ -0,0 +1,81 @@
+regfile uart_regs {
+ lsb0;
+ reg {
+ name="txdata";
+ desc="Transmit data register";
+ field {
+ name ="data";
+ } data[7:0];
+ field {
+ name ="full";
+ } full[31:31];
+ } txdata @0x00;
+ reg {
+ name="rxdata";
+ desc="Receive data register";
+ field {
+ name ="data";
+ } data[7:0];
+ field {
+ name ="empty";
+ } empty[31:31];
+ }rxdata @0x04;
+ reg {
+ name="txctrl";
+ desc="Transmit control register";
+ field {
+ name ="txen";
+ } txen[1];
+ field {
+ name ="nstop";
+ } nstop[1];
+ field {
+ name ="reserved";
+ } reserved[14];
+ field {
+ name ="txcnt";
+ } txcnt[3];
+ }txctrl @0x08;
+ reg {
+ name="rxctrl";
+ desc="Receive control register";
+ field {
+ name ="rxen";
+ } rxen[1];
+ field {
+ name ="reserved";
+ } reserved[15];
+ field {
+ name ="rxcnt";
+ } rxcnt[3];
+ }rxctrl @0x0C;
+ reg {
+ name="ie";
+ desc="UART interrupt enable";
+ field{
+ name ="txwm";
+ } txwm[1];
+ field{
+ name ="rxwm";
+ } rxwm[1];
+ }ie @0x10;
+ reg {
+ name="ip";
+ desc="UART Interrupt pending";
+ field{
+ name ="txwm";
+ } txwm[1];
+ field{
+ name ="rxwm";
+ } rxwm[1];
+ } ip @0x14;
+ reg {
+ name="div";
+ desc="Baud rate divisor";
+ field{
+ name ="div";
+ } div[16];
+ } div @0x18;
+};
+
+
\ No newline at end of file
diff --git a/riscv.sc/incl/cli_options.h b/riscv.sc/incl/cli_options.h
new file mode 100644
index 0000000..9e02585
--- /dev/null
+++ b/riscv.sc/incl/cli_options.h
@@ -0,0 +1,171 @@
+/*******************************************************************************
+ * Copyright (C) 2017, MINRES Technologies GmbH
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Contributors:
+ * eyck@minres.com - initial API and implementation
+ ******************************************************************************/
+
+#ifndef _CLI_OPTIONS_H_
+#define _CLI_OPTIONS_H_
+#include
+#include
+#include
+#include
+
+namespace {
+const size_t ERROR_IN_COMMAND_LINE = 1;
+const size_t SUCCESS = 0;
+const size_t ERROR_UNHANDLED_EXCEPTION = 2;
+
+
+inline void enable_log_level(int level){
+ switch(level){
+ case 0:
+ logging::Logger::reporting_level()= logging::FATAL;
+ /* no break */
+ case 1:
+ logging::Logger::reporting_level()= logging::ERROR;
+ /* no break */
+ case 2:
+ logging::Logger::reporting_level()= logging::WARNING;
+ /* no break */
+ case 3:
+ logging::Logger::reporting_level()= logging::INFO;
+ /* no break */
+ case 4:
+ logging::Logger::reporting_level()= logging::DEBUG;
+ /* no break */
+ case 5:
+ logging::Logger::reporting_level()= logging::TRACE;
+ /* no break */
+ }
+}
+
+inline void configure_default_logger(boost::program_options::variables_map& vm){
+// el::Configurations defaultConf;
+// defaultConf.setToDefault();
+// defaultConf.set(el::Level::Error, el::ConfigurationType::Format, "%datetime{%H:%m:%s.%g} %level %msg");
+// defaultConf.set(el::Level::Warning, el::ConfigurationType::Format, "%datetime{%H:%m:%s.%g} %level %msg");
+// defaultConf.set(el::Level::Info, el::ConfigurationType::Format, "%datetime{%H:%m:%s.%g} %level %msg");
+// defaultConf.set(el::Level::Debug, el::ConfigurationType::Format, "%datetime{%H:%m:%s.%g} %level %msg");
+// defaultConf.set(el::Level::Trace, el::ConfigurationType::Format, "%datetime{%H:%m:%s.%g} %level %msg");
+ if(vm.count("verbose"))
+ enable_log_level(vm["verbose"].as());
+ if(vm.count("log-file"))
+ logging::Output2FILE::stream() = fopen(vm["log-file"].as().c_str(), "w");
+ // default logger uses default configurations
+// el::Loggers::reconfigureLogger("default", defaultConf);
+}
+
+inline void configure_debugger_logger() {
+ // configure the connection logger
+// el::Logger* gdbServerLogger = el::Loggers::getLogger("connection");
+// el::Configurations gdbServerConf;
+// gdbServerConf.setToDefault();
+// gdbServerConf.set(el::Level::Error, el::ConfigurationType::Format,
+// "%datetime{%H:%m:%s.%g} %level [%logger] %msg");
+// gdbServerConf.set(el::Level::Warning, el::ConfigurationType::Format,
+// "%datetime{%H:%m:%s.%g} %level [%logger] %msg");
+// gdbServerConf.set(el::Level::Info, el::ConfigurationType::Format,
+// "%datetime{%H:%m:%s.%g} %level [%logger] %msg");
+// gdbServerConf.set(el::Level::Debug, el::ConfigurationType::Format,
+// "%datetime{%H:%m:%s.%g} %level [%logger] %msg");
+// gdbServerConf.set(el::Level::Trace, el::ConfigurationType::Format,
+// "%datetime{%H:%m:%s.%g} %level [%logger] %msg");
+// enable_log_level(gdbServerConf, 5);
+// gdbServerLogger->configure(gdbServerConf);
+}
+
+inline void configure_disass_logger(boost::program_options::variables_map& vm) {
+// el::Logger* disassLogger = el::Loggers::getLogger("disass");
+// el::Configurations disassConf;
+// if(vm.count("disass")){
+// auto file_name=vm["disass"].as();
+// disassConf.setToDefault();
+// if (file_name.length() > 0) {
+// disassConf.set(el::Level::Global, el::ConfigurationType::ToFile,
+// std::string("true"));
+// disassConf.set(el::Level::Global,
+// el::ConfigurationType::ToStandardOutput, std::string("false"));
+// disassConf.set(el::Level::Global, el::ConfigurationType::Format,
+// std::string("%msg"));
+// disassConf.set(el::Level::Global, el::ConfigurationType::Filename,
+// file_name);
+// std::ofstream str(file_name); // just to clear the file
+// } else {
+// disassConf.set(el::Level::Global, el::ConfigurationType::Format,
+// "%datetime{%H:%m:%s.%g} [%logger] %msg");
+// }
+// } else {
+// enable_log_level(disassConf, 0);
+// }
+// disassLogger->configure(disassConf);
+}
+
+} // namespace
+
+inline int parse_cli_options(boost::program_options::variables_map& vm, int argc, char *argv[]){
+ namespace po = boost::program_options;
+ po::options_description desc("Options");
+ desc.add_options()
+ ("help,h", "Print help message")
+ ("verbose,v", po::value()->implicit_value(0), "Sets logging verbosity")
+ ("vmodule", po::value(),"Defines the module(s) to be logged")
+ ("logging-flags", po::value(),"Sets logging flag(s).")
+ ("log-file", po::value(),"Sets default log file.")
+ ("disass,d", po::value()->implicit_value(""),"Enables disassembly")
+ ("elf,l", po::value< std::vector >(), "ELF file(s) to load")
+ ("gdb-port,g", po::value(), "enable gdb server and specify port to use")
+ ("input,i", po::value(), "the elf file to load (instead of hex files)")
+ ("dump-ir", "dump the intermediate representation")
+ ("cycles,c", po::value()->default_value(-1), "number of cycles to run")
+ ("systemc,s", "Run as SystemC simulation")
+ ("time", po::value(), "SystemC siimulation time in ms")
+ ("reset,r", po::value(), "reset address")
+ ("trace", po::value(), "enable tracing, or cmbintation of 1=signals and 2=TX text, 4=TX compressed text, 6=TX in SQLite")\
+ ("mem,m", po::value(), "the memory input file")
+ ("rv64", "run RV64");
+ try {
+ po::store(po::parse_command_line(argc, argv, desc), vm); // can throw
+ // --help option
+ if ( vm.count("help") ){
+ std::cout << "DBT-RISE-RiscV" << std::endl << desc << std::endl;
+ return SUCCESS;
+ }
+ po::notify(vm); // throws on error, so do after help in case
+ } catch(po::error& e){
+ // there are problems
+ std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
+ std::cerr << desc << std::endl;
+ return ERROR_IN_COMMAND_LINE;
+ }
+ return SUCCESS;
+}
+#endif /* _CLI_OPTIONS_H_ */
diff --git a/riscv.sc/incl/iss/arch/riscv_hart_msu_vp.h b/riscv.sc/incl/iss/arch/riscv_hart_msu_vp.h
new file mode 100644
index 0000000..b2c5d2f
--- /dev/null
+++ b/riscv.sc/incl/iss/arch/riscv_hart_msu_vp.h
@@ -0,0 +1,1249 @@
+/*******************************************************************************
+ * Copyright (C) 2017, MINRES Technologies GmbH
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Contributors:
+ * eyck@minres.com - initial API and implementation
+ ******************************************************************************/
+
+#ifndef _RISCV_CORE_H_
+#define _RISCV_CORE_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace iss {
+namespace arch {
+
+enum {
+ tohost_dflt = 0xF0001000,
+ fromhost_dflt = 0xF0001040
+};
+
+enum csr_name {
+ /* user-level CSR */
+ // User Trap Setup
+ ustatus=0x000,
+ uie=0x004,
+ utvec=0x005,
+ // User Trap Handling
+ uscratch=0x040,
+ uepc=0x041,
+ ucause=0x042,
+ utval=0x043,
+ uip=0x044,
+ // User Floating-Point CSRs
+ fflags=0x001,
+ frm=0x002,
+ fcsr=0x003,
+ // User Counter/Timers
+ cycle=0xC00,
+ time=0xC01,
+ instret=0xC02,
+ hpmcounter3=0xC03,
+ hpmcounter4=0xC04,
+ /*...*/
+ hpmcounter31=0xC1F,
+ cycleh=0xC80,
+ timeh=0xC81,
+ instreth=0xC82,
+ hpmcounter3h=0xC83,
+ hpmcounter4h=0xC84,
+ /*...*/
+ hpmcounter31h=0xC9F,
+ /* supervisor-level CSR */
+ // Supervisor Trap Setup
+ sstatus=0x100,
+ sedeleg=0x102,
+ sideleg=0x103,
+ sie=0x104,
+ stvec=0x105,
+ scounteren=0x106,
+ // Supervisor Trap Handling
+ sscratch=0x140,
+ sepc=0x141,
+ scause=0x142,
+ stval=0x143,
+ sip=0x144,
+ // Supervisor Protection and Translation
+ satp=0x180,
+ /* machine-level CSR */
+ // Machine Information Registers
+ mvendorid=0xF11,
+ marchid=0xF12,
+ mimpid=0xF13,
+ mhartid=0xF14,
+ // Machine Trap Setup
+ mstatus=0x300,
+ misa=0x301,
+ medeleg=0x302,
+ mideleg=0x303,
+ mie=0x304,
+ mtvec=0x305,
+ mcounteren=0x306,
+ // Machine Trap Handling
+ mscratch=0x340,
+ mepc=0x341,
+ mcause=0x342,
+ mtval=0x343,
+ mip=0x344,
+ // Machine Protection and Translation
+ pmpcfg0=0x3A0,
+ pmpcfg1=0x3A1,
+ pmpcfg2=0x3A2,
+ pmpcfg3=0x3A3,
+ pmpaddr0=0x3B0,
+ pmpaddr1=0x3B1,
+ /*...*/
+ pmpaddr15=0x3BF,
+ // Machine Counter/Timers
+ mcycle=0xB00,
+ minstret=0xB02,
+ mhpmcounter3=0xB03,
+ mhpmcounter4=0xB04,
+ /*...*/
+ mhpmcounter31=0xB1F,
+ mcycleh=0xB80,
+ minstreth=0xB82,
+ mhpmcounter3h=0xB83,
+ mhpmcounter4h=0xB84,
+ /*...*/
+ mhpmcounter31h=0xB9F,
+ // Machine Counter Setup
+ mhpmevent3=0x323,
+ mhpmevent4=0x324,
+ /*...*/
+ mhpmevent31=0x33F,
+ // Debug/Trace Registers (shared with Debug Mode)
+ tselect=0x7A0,
+ tdata1=0x7A1,
+ tdata2=0x7A2,
+ tdata3=0x7A3,
+ // Debug Mode Registers
+ dcsr=0x7B0,
+ dpc=0x7B1,
+ dscratch=0x7B2
+};
+
+namespace {
+
+const char lvl[]={'U', 'S', 'H', 'M'};
+
+const char* trap_str[] = {
+ "Instruction address misaligned",
+ "Instruction access fault",
+ "Illegal instruction",
+ "Breakpoint",
+ "Load address misaligned",
+ "Load access fault",
+ "Store/AMO address misaligned",
+ "Store/AMO access fault",
+ "Environment call from U-mode",
+ "Environment call from S-mode",
+ "Reserved",
+ "Environment call from M-mode",
+ "Instruction page fault",
+ "Load page fault",
+ "Reserved",
+ "Store/AMO page fault"
+};
+const char* irq_str[] = {
+ "User software interrupt",
+ "Supervisor software interrupt",
+ "Reserved",
+ "Machine software interrupt",
+ "User timer interrupt",
+ "Supervisor timer interrupt",
+ "Reserved",
+ "Machine timer interrupt",
+ "User external interrupt",
+ "Supervisor external interrupt",
+ "Reserved",
+ "Machine external interrupt"
+};
+
+enum {
+ PGSHIFT=12,
+ PTE_PPN_SHIFT=10,
+ // page table entry (PTE) fields
+ PTE_V = 0x001, // Valid
+ PTE_R = 0x002, // Read
+ PTE_W = 0x004, // Write
+ PTE_X = 0x008, // Execute
+ PTE_U = 0x010, // User
+ PTE_G = 0x020, // Global
+ PTE_A = 0x040, // Accessed
+ PTE_D = 0x080, // Dirty
+ PTE_SOFT = 0x300 // Reserved for Software
+};
+
+template
+inline bool PTE_TABLE(T PTE){
+ return (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V);
+}
+
+
+enum { PRIV_U=0, PRIV_S=1, PRIV_M=3};
+
+enum {
+ ISA_A=1,
+ ISA_B=1<<1,
+ ISA_C=1<<2,
+ ISA_D=1<<3,
+ ISA_E=1<<4,
+ ISA_F=1<<5,
+ ISA_G=1<<6,
+ ISA_I=1<<8,
+ ISA_M=1<<12,
+ ISA_N=1<<13,
+ ISA_Q=1<<16,
+ ISA_S=1<<18,
+ ISA_U=1<<20};
+
+struct vm_info {
+ int levels;
+ int idxbits;
+ int ptesize;
+ uint64_t ptbase;
+};
+
+
+struct trap_load_access_fault: public trap_access {
+ trap_load_access_fault(uint64_t badaddr) : trap_access(5<<16, badaddr) {}
+};
+struct illegal_instruction_fault: public trap_access {
+ illegal_instruction_fault(uint64_t badaddr) : trap_access(2<<16, badaddr) {}
+};
+struct trap_instruction_page_fault: public trap_access {
+ trap_instruction_page_fault(uint64_t badaddr) : trap_access(12<<16, badaddr) {}
+};
+struct trap_load_page_fault: public trap_access {
+ trap_load_page_fault(uint64_t badaddr) : trap_access(13<<16, badaddr) {}
+};
+struct trap_store_page_fault: public trap_access {
+ trap_store_page_fault(uint64_t badaddr) : trap_access(15<<16, badaddr) {}
+};
+}
+
+typedef union {
+ uint32_t val;
+ struct /*mstatus*/ {
+ uint32_t
+ SD:1, //SD bit is read-only and is set when either the FS or XS bits encode a Dirty state (i.e., SD=((FS==11) OR (XS==11)))
+ _WPRI3:8, //unused
+ TSR:1, //Trap SRET
+ TW:1, //Timeout Wait
+ TVM:1, //Trap Virtual Memory
+ MXR:1, //Make eXecutable Readable
+ SUM:1, //permit Supervisor User Memory access
+ MPRV:1, //Modify PRiVilege
+ XS:2, //status of additional user-mode extensions and associated state, All off/None dirty or clean, some on/None dirty, some clean/Some dirty
+ FS:2, //floating-point unit status Off/Initial/Clean/Dirty
+ MPP:2, // machine previous privilege
+ _WPRI2:2, // unused
+ SPP:1, // supervisor previous privilege
+ MPIE:1, //previous machine interrupt-enable
+ _WPRI1:1, // unused
+ SPIE:1, //previous supervisor interrupt-enable
+ UPIE:1, //previous user interrupt-enable
+ MIE:1, //machine interrupt-enable
+ _WPRI0:1, // unused
+ SIE:1, //supervisor interrupt-enable
+ UIE:1; //user interrupt-enable
+ } m;
+ struct /*sstatus*/ {
+ uint32_t
+ SD:1,
+ _WPRI4:11,
+ MXR:1,
+ SUM:1,
+ _WPRI3:1,
+ XS:2,
+ FS:2,
+ _WPRI2:4,
+ SPP:1,
+ _WPRI1:2,
+ SPIE:1,
+ UPIE:1,
+ _WPRI0:2,
+ SIE:1,
+ UIE:1;
+ } s;
+ struct /*ustatus*/ {
+ uint32_t
+ SD:1,
+ _WPRI4:11,
+ MXR:1,
+ SUM:1,
+ _WPRI3:1,
+ XS:2,
+ FS:2,
+ _WPRI2:8,
+ UPIE:1,
+ _WPRI0:3,
+ UIE:1;
+ } u;
+} mstatus32_t;
+
+typedef union {
+ uint64_t val;
+ struct /*mstatus*/ {
+ uint64_t
+ SD:1, // SD bit is read-only and is set when either the FS or XS bits encode a Dirty state (i.e., SD=((FS==11) OR (XS==11)))
+ _WPRI4:27,// unused
+ SXL:2, // value of XLEN for S-mode
+ UXL:2, // value of XLEN for U-mode
+ _WPRI3:9, // unused
+ TSR:1, // Trap SRET
+ TW:1, // Timeout Wait
+ TVM:1, // Trap Virtual Memory
+ MXR:1, // Make eXecutable Readable
+ SUM:1, // permit Supervisor User Memory access
+ MPRV:1, // Modify PRiVilege
+ XS:2, // status of additional user-mode extensions and associated state, All off/None dirty or clean, some on/None dirty, some clean/Some dirty
+ FS:2, // floating-point unit status Off/Initial/Clean/Dirty
+ MPP:2, // machine previous privilege
+ _WPRI2:2, // unused
+ SPP:1, // supervisor previous privilege
+ MPIE:1, // previous machine interrupt-enable
+ _WPRI1:1, // unused
+ SPIE:1, // previous supervisor interrupt-enable
+ UPIE:1, // previous user interrupt-enable
+ MIE:1, // machine interrupt-enable
+ _WPRI0:1, // unused
+ SIE:1, // supervisor interrupt-enable
+ UIE:1; // ‚user interrupt-enable
+ } m;
+ struct /*sstatus*/ {
+ uint64_t
+ SD:1,
+ _WPRI5:29,// unused
+ UXL:2, // value of XLEN for U-mode
+ _WPRI4:12,
+ MXR:1,
+ SUM:1,
+ _WPRI3:1,
+ XS:2,
+ FS:2,
+ _WPRI2:4,
+ SPP:1,
+ _WPRI1:2,
+ SPIE:1,
+ UPIE:1,
+ _WPRI0:2,
+ SIE:1,
+ UIE:1;
+ } s;
+ struct /*ustatus*/ {
+ uint32_t
+ SD:1,
+ _WPRI4:29,// unused
+ UXL:2, // value of XLEN for U-mode
+ _WPRI3:12,
+ MXR:1,
+ SUM:1,
+ _WPRI2:1,
+ XS:2,
+ FS:2,
+ _WPRI1:8,
+ UPIE:1,
+ _WPRI0:3,
+ UIE:1;
+ } u;
+} mstatus64_t;
+
+template
+inline vm_info decode_vm_info(uint32_t state, uint64_t sptbr);
+
+template<>
+inline vm_info decode_vm_info<32u>(uint32_t state, uint64_t sptbr){
+ if (state == PRIV_M) {
+ return {0, 0, 0, 0};
+ } else if (state <= PRIV_S) {
+ switch (bit_sub<31,1>(sptbr)) {
+ case 0: // off
+ return {0, 0, 0, 0};
+ case 1: // SV32
+ return {2, 10, 4, bit_sub<0, 22>(sptbr) << PGSHIFT};
+ default: abort();
+ }
+ } else {
+ abort();
+ }
+ return {0, 0, 0, 0}; // dummy
+}
+
+template<>
+inline vm_info decode_vm_info<64u>(uint32_t state, uint64_t sptbr){
+ if (state == PRIV_M) {
+ return {0, 0, 0, 0};
+ } else if (state <= PRIV_S) {
+ switch (bit_sub<60, 4>(sptbr)) {
+ case 0: // off
+ return {0, 0, 0, 0};
+ case 8: // SV39
+ return {3, 9, 8, bit_sub<0, 44>(sptbr) << PGSHIFT};
+ case 9: // SV48
+ return {4, 9, 8, bit_sub<0, 44>(sptbr) << PGSHIFT};
+ case 10: // SV57
+ return {5, 9, 8, bit_sub<0, 44>(sptbr) << PGSHIFT};
+ case 11: // SV64
+ return {6, 9, 8, bit_sub<0, 44>(sptbr) << PGSHIFT};
+ default: abort();
+ }
+ } else {
+ abort();
+ }
+ return {0, 0, 0, 0}; // dummy
+}
+
+
+constexpr uint32_t get_mask(unsigned priv_lvl, uint32_t mask){
+ switch(priv_lvl){
+ case PRIV_U:
+ return mask&0x80000011UL; // 0b1000 0000 0000 0000 0000 0000 0001 0001
+ case PRIV_S:
+ return mask&0x800de133UL; // 0b1000 0000 0000 1101 1110 0001 0011 0011
+ default:
+ return mask&0x807ff9ddUL; // 0b1000 0000 0111 1111 1111 1001 1011 1011
+ }
+}
+
+constexpr uint64_t get_mask(unsigned priv_lvl, uint64_t mask){
+ switch(priv_lvl){
+ case PRIV_U:
+ return mask&0x8000000000000011ULL; //0b1...0 1111 0000 0000 0111 1111 1111 1001 1011 1011
+ case PRIV_S:
+ return mask&0x80000003000de133ULL; //0b1...0 0011 0000 0000 0000 1101 1110 0001 0011 0011
+ default:
+ return mask&0x8000000f007ff9ddULL; //0b1...0 1111 0000 0000 0111 1111 1111 1001 1011 1011
+ }
+}
+
+constexpr uint32_t get_misa(uint32_t mask){
+ return (1UL<<30)| ISA_I | ISA_M | ISA_A | ISA_U | ISA_S | ISA_M ;
+}
+
+constexpr uint64_t get_misa(uint64_t mask){
+ return (2ULL<<62)| ISA_I | ISA_M | ISA_A | ISA_U | ISA_S | ISA_M ;
+}
+
+template
+struct riscv_hart_msu_vp: public BASE {
+ using super = BASE;
+ using this_class = riscv_hart_msu_vp;
+ using virt_addr_t= typename super::virt_addr_t;
+ using phys_addr_t= typename super::phys_addr_t;
+ using reg_t = typename super::reg_t;
+ using addr_t = typename super::addr_t;
+
+ using rd_csr_f = iss::status (this_class::*)(unsigned addr, reg_t&);
+ using wr_csr_f = iss::status (this_class::*)(unsigned addr, reg_t);
+
+ const typename super::reg_t PGSIZE = 1 << PGSHIFT;
+ const typename super::reg_t PGMASK = PGSIZE-1;
+
+ constexpr reg_t get_irq_mask(size_t mode){
+ const reg_t m[4] = {
+ 0b000100010001, //U mode
+ 0b001100110011, // S-mode
+ 0,
+ 0b101110111011 // M-mode
+ };
+ return m[mode];
+ }
+
+ riscv_hart_msu_vp();
+ virtual ~riscv_hart_msu_vp();
+
+ virtual void load_file(std::string name, int type=-1);
+
+ virtual phys_addr_t v2p(const iss::addr_t& addr);
+
+ virtual iss::status read(const iss::addr_t& addr, unsigned length, uint8_t* const data) override;
+ virtual iss::status write(const iss::addr_t& addr, unsigned length, const uint8_t* const data) override;
+
+ virtual uint64_t enter_trap(uint64_t flags) override {return riscv_hart_msu_vp::enter_trap(flags, fault_data);}
+ virtual uint64_t enter_trap(uint64_t flags, uint64_t addr) override;
+ virtual uint64_t leave_trap(uint64_t flags) override;
+ virtual void wait_until(uint64_t flags) override;
+
+ virtual std::string get_additional_disass_info(){
+ std::stringstream s;
+ s<<"[p:"<reg.machine_state]<<";s:0x"<reg.icount<<"]";
+ return s.str();
+ };
+
+protected:
+ virtual iss::status read_mem(phys_addr_t addr, unsigned length, uint8_t* const data);
+ virtual iss::status write_mem(phys_addr_t addr, unsigned length, const uint8_t* const data);
+
+ virtual iss::status read_csr(unsigned addr, reg_t& val);
+ virtual iss::status write_csr(unsigned addr, reg_t val);
+
+ uint64_t tohost = tohost_dflt;
+ uint64_t fromhost = fromhost_dflt;
+
+ reg_t fault_data;
+ using mem_type = util::sparse_array;
+ using csr_type = util::sparse_array::reg_t, 1ULL<<12, 12>;
+ using csr_page_type = typename csr_type::page_type;
+ mem_type mem;
+ csr_type csr;
+ reg_t& mstatus_r;
+ reg_t& satp_r;
+ unsigned to_host_wr_cnt=0;
+ std::stringstream uart_buf;
+ std::unordered_map ptw;
+ std::unordered_map atomic_reservation;
+ std::unordered_map csr_rd_cb;
+ std::unordered_map csr_wr_cb;
+
+private:
+ iss::status read_cycle(unsigned addr, reg_t& val);
+ iss::status read_status(unsigned addr, reg_t& val);
+ iss::status write_status(unsigned addr, reg_t val);
+ iss::status read_ie(unsigned addr, reg_t& val);
+ iss::status write_ie(unsigned addr, reg_t val);
+ iss::status read_ip(unsigned addr, reg_t& val);
+ iss::status write_ip(unsigned addr, reg_t val);
+ iss::status read_satp(unsigned addr, reg_t& val);
+ iss::status write_satp(unsigned addr, reg_t val);
+ void check_interrupt();
+};
+
+template
+riscv_hart_msu_vp::riscv_hart_msu_vp() : mstatus_r(csr[mstatus]), satp_r(csr[satp]) {
+ csr[misa]=traits::XLEN==32?1ULL<<(traits::XLEN-2):2ULL<<(traits::XLEN-2);
+ uart_buf.str("");
+ // read-only registers
+ csr_wr_cb[misa]=nullptr;
+ for(unsigned addr=mcycle; addr<=hpmcounter31; ++addr)
+ csr_wr_cb[addr]=nullptr;
+ for(unsigned addr=mcycleh; addr<=hpmcounter31h; ++addr)
+ csr_wr_cb[addr]=nullptr;
+ // special handling
+ csr_rd_cb[mcycle]=&riscv_hart_msu_vp::read_cycle;
+ csr_rd_cb[mcycleh]=&riscv_hart_msu_vp::read_cycle;
+ csr_rd_cb[minstret]=&riscv_hart_msu_vp::read_cycle;
+ csr_rd_cb[minstreth]=&riscv_hart_msu_vp::read_cycle;
+ csr_rd_cb[mstatus]=&riscv_hart_msu_vp::read_status;
+ csr_wr_cb[mstatus]=&riscv_hart_msu_vp::write_status;
+ csr_rd_cb[sstatus]=&riscv_hart_msu_vp::read_status;
+ csr_wr_cb[sstatus]=&riscv_hart_msu_vp::write_status;
+ csr_rd_cb[ustatus]=&riscv_hart_msu_vp::read_status;
+ csr_wr_cb[ustatus]=&riscv_hart_msu_vp::write_status;
+ csr_rd_cb[mip]=&riscv_hart_msu_vp::read_ip;
+ csr_wr_cb[mip]=&riscv_hart_msu_vp::write_ip;
+ csr_rd_cb[sip]=&riscv_hart_msu_vp::read_ip;
+ csr_wr_cb[sip]=&riscv_hart_msu_vp::write_ip;
+ csr_rd_cb[uip]=&riscv_hart_msu_vp::read_ip;
+ csr_wr_cb[uip]=&riscv_hart_msu_vp::write_ip;
+ csr_rd_cb[mie]=&riscv_hart_msu_vp::read_ie;
+ csr_wr_cb[mie]=&riscv_hart_msu_vp::write_ie;
+ csr_rd_cb[sie]=&riscv_hart_msu_vp::read_ie;
+ csr_wr_cb[sie]=&riscv_hart_msu_vp::write_ie;
+ csr_rd_cb[uie]=&riscv_hart_msu_vp::read_ie;
+ csr_wr_cb[uie]=&riscv_hart_msu_vp::write_ie;
+ csr_rd_cb[satp]=&riscv_hart_msu_vp::read_satp;
+ csr_wr_cb[satp]=&riscv_hart_msu_vp::write_satp;
+}
+
+template
+riscv_hart_msu_vp::~riscv_hart_msu_vp() {
+}
+
+template
+void riscv_hart_msu_vp::load_file(std::string name, int type) {
+ FILE* fp = fopen(name.c_str(), "r");
+ if(fp){
+ char buf[5];
+ auto n = fread(buf, 1,4,fp);
+ if(n!=4) throw std::runtime_error("input file has insufficient size");
+ buf[4]=0;
+ if(strcmp(buf+1, "ELF")==0){
+ fclose(fp);
+ //Create elfio reader
+ ELFIO::elfio reader;
+ // Load ELF data
+ if ( !reader.load( name ) ) throw std::runtime_error("could not process elf file");
+ // check elf properties
+ //TODO: fix ELFCLASS like:
+ // if ( reader.get_class() != ELFCLASS32 ) throw std::runtime_error("wrong elf class in file");
+ if ( reader.get_type() != ET_EXEC ) throw std::runtime_error("wrong elf type in file");
+ //TODO: fix machine type like:
+ // if ( reader.get_machine() != EM_RISCV ) throw std::runtime_error("wrong elf machine in file");
+ for (const auto pseg :reader.segments ) {
+ const auto fsize=pseg->get_file_size(); // 0x42c/0x0
+ const auto seg_data=pseg->get_data();
+ if(fsize>0){
+ this->write(typed_addr_t(iss::DEBUG_WRITE, traits::MEM, pseg->get_virtual_address()), fsize, reinterpret_cast(seg_data));
+ }
+ }
+ for (const auto sec :reader.sections ) {
+ if(sec->get_name() == ".tohost"){
+ tohost=sec->get_address();
+ fromhost=tohost+0x40;
+ }
+ }
+ return;
+ }
+ }
+}
+
+template
+iss::status riscv_hart_msu_vp::read(const iss::addr_t& addr, unsigned length, uint8_t* const data){
+#ifndef NDEBUG
+ if(addr.type& iss::DEBUG){
+ LOG(logging::DEBUG)<<"debug read of "<::MEM:{
+ if((addr.type&(iss::ACCESS_TYPE-iss::DEBUG))==iss::FETCH && (addr.val&0x1) == 1){
+ fault_data=addr.val;
+ if((addr.type&iss::DEBUG))
+ throw trap_access(0, addr.val);
+ this->reg.trap_state=(1<<31); // issue trap 0
+ return iss::Err;
+ }
+ try {
+ if((addr.val&~PGMASK) != ((addr.val+length-1)&~PGMASK)){ // we may cross a page boundary
+ vm_info vm = decode_vm_info::XLEN>(this->reg.machine_state, csr[satp]);
+ if(vm.levels!=0){ // VM is active
+ auto split_addr = (addr.val+length)&~PGMASK;
+ auto len1=split_addr-addr.val;
+ auto res = read(addr, len1, data);
+ if(res==iss::Ok)
+ res = read(iss::addr_t{addr.type, addr.space, split_addr}, length-len1, data+len1);
+ return res;
+ }
+ }
+ phys_addr_t paddr = (addr.type&iss::ADDRESS_TYPE)==iss::PHYSICAL?addr:v2p(addr);
+ if((paddr.val +length)>mem.size()) return iss::Err;
+ switch(paddr.val){
+ case 0x0200BFF8:{ // CLINT base, mtime reg
+ uint64_t mtime = this->reg.icount>>12/*12*/;
+ std::copy((uint8_t*)&mtime, ((uint8_t*)&mtime)+length, data);
+ }
+ break;
+ case 0x10008000:{
+ const mem_type::page_type& p = mem(paddr.val/mem.page_size);
+ uint64_t offs=paddr.val&mem.page_addr_mask;
+ std::copy(
+ p.data() + offs,
+ p.data() + offs+length,
+ data);
+ if(this->reg.icount>30000)
+ data[3]|=0x80;
+ }
+ break;
+ default:{
+ return read_mem(paddr, length, data);
+ }
+ }
+ } catch(trap_access& ta){
+ this->reg.trap_state=(1<<31)|ta.id;
+ return iss::Err;
+ }
+ }
+ break;
+ case traits::CSR:{
+ if(length!=sizeof(reg_t)) return iss::Err;
+ return read_csr(addr.val, *reinterpret_cast(data));
+ }
+ break;
+ case traits::FENCE:{
+ if((addr.val +length)>mem.size()) return iss::Err;
+ switch(addr.val){
+ case 2: // SFENCE:VMA lower
+ case 3:{// SFENCE:VMA upper
+ auto status = csr[mstatus];
+ auto tvm = status&(1<<20);
+ if(this->reg.machine_state==PRIV_S & tvm!=0){
+ this->reg.trap_state=(1<<31)|(2<<16);
+ this->fault_data=this->reg.PC;
+ return iss::Err;
+ }
+ return iss::Ok;
+ }
+ }
+ }
+ break;
+ case traits::RES:{
+ auto it = atomic_reservation.find(addr.val);
+ if(it!= atomic_reservation.end() && (*it).second != 0){
+ memset(data, 0xff, length);
+ atomic_reservation.erase(addr.val);
+ } else
+ memset(data, 0, length);
+ }
+ break;
+ default:
+ return iss::Err; //assert("Not supported");
+ }
+ return iss::Ok;
+}
+
+template
+iss::status riscv_hart_msu_vp::write(const iss::addr_t& addr, unsigned length, const uint8_t* const data){
+#ifndef NDEBUG
+ const char* prefix = addr.type & iss::DEBUG?"debug ":"";
+ switch(length){
+ case 8:
+ LOG(logging::DEBUG)<::MEM:{
+ phys_addr_t paddr = (addr.type&iss::ADDRESS_TYPE)==iss::PHYSICAL?addr:v2p(addr);
+ if((paddr.val +length)>mem.size()) return iss::Err;
+ switch(paddr.val){
+ case 0x10013000: // UART0 base, TXFIFO reg
+ case 0x10023000: // UART1 base, TXFIFO reg
+ uart_buf<<(char)data[0];
+ if(((char)data[0])=='\n' || data[0]==0){
+ // LOG(INFO)<<"UART"<<((paddr.val>>16)&0x3)<<" send '"<::CSR:{
+ if(length!=sizeof(reg_t)) return iss::Err;
+ return write_csr(addr.val, *reinterpret_cast(data));
+ }
+ break;
+ case traits::FENCE:{
+ if((addr.val +length)>mem.size()) return iss::Err;
+ switch(addr.val){
+ case 2:
+ case 3:{
+ ptw.clear();
+ auto status = csr[mstatus];
+ auto tvm = status&(1<<20);
+ if(this->reg.machine_state==PRIV_S & tvm!=0){
+ this->reg.trap_state=(1<<31)|(2<<16);
+ this->fault_data=this->reg.PC;
+ return iss::Err;
+ }
+ return iss::Ok;
+ }
+ }
+ }
+ break;
+ case traits::RES:{
+ atomic_reservation[addr.val] = data[0];
+ }
+ break;
+ default:
+ return iss::Err;
+ }
+ return iss::Ok;
+ } catch(trap_access& ta){
+ this->reg.trap_state=(1<<31)|ta.id;
+ return iss::Err;
+ }
+}
+
+template
+iss::status riscv_hart_msu_vp::read_csr(unsigned addr, reg_t& val){
+ if(addr >= csr.size()) return iss::Err;
+ auto it = csr_rd_cb.find(addr);
+ if(it == csr_rd_cb.end()){
+ val=csr[addr&csr.page_addr_mask];
+ return iss::Ok;
+ }
+ rd_csr_f f=it->second;
+ if(f==nullptr)
+ throw illegal_instruction_fault(this->fault_data);
+ return (this->*f)(addr, val);
+}
+
+template
+iss::status riscv_hart_msu_vp::write_csr(unsigned addr, reg_t val){
+ if(addr>=csr.size()) return iss::Err;
+ auto it = csr_wr_cb.find(addr);
+ if(it == csr_wr_cb.end()){
+ csr[addr&csr.page_addr_mask] = val;
+ return iss::Ok;
+ }
+ wr_csr_f f=it->second;
+ if(f==nullptr)
+ throw illegal_instruction_fault(this->fault_data);
+ return (this->*f)(addr, val);
+
+}
+
+template
+iss::status riscv_hart_msu_vp::read_cycle(unsigned addr, reg_t& val) {
+ if( addr== mcycle) {
+ val = static_cast(this->reg.icount);
+ }else if(addr==mcycleh) {
+ if(sizeof(typename traits::reg_t)!=4) return iss::Err;
+ val = static_cast((this->reg.icount)>>32);
+ }
+ return iss::Ok;
+}
+
+template
+iss::status riscv_hart_msu_vp::read_status(unsigned addr, reg_t& val) {
+ auto req_priv_lvl=addr>>8;
+ if(this->reg.machine_statefault_data);
+ auto mask = get_mask(req_priv_lvl, (reg_t) (std::numeric_limits::max()));
+ val = csr[mstatus] & mask;
+ return iss::Ok;
+}
+
+template
+iss::status riscv_hart_msu_vp::write_status(unsigned addr, reg_t val) {
+ auto req_priv_lvl=addr>>8;
+ if(this->reg.machine_statefault_data);
+ auto mask=get_mask(req_priv_lvl, (reg_t)std::numeric_limits::max());
+ auto old_val=csr[mstatus];
+ auto new_val = (old_val&~mask) |(val&mask);
+ csr[mstatus] = new_val;
+ check_interrupt();
+ return iss::Ok;
+}
+
+template
+iss::status riscv_hart_msu_vp::read_ie(unsigned addr, reg_t& val) {
+ auto req_priv_lvl=addr>>8;
+ if(this->reg.machine_statefault_data);
+ val = csr[mie];
+ if(addr
+iss::status riscv_hart_msu_vp::write_ie(unsigned addr, reg_t val) {
+ auto req_priv_lvl=addr>>8;
+ if(this->reg.machine_statefault_data);
+ auto mask=get_irq_mask(req_priv_lvl);
+ csr[mie] = (csr[mie] & ~mask) | (val & mask);
+ check_interrupt();
+ return iss::Ok;
+}
+
+template
+iss::status riscv_hart_msu_vp::read_ip(unsigned addr, reg_t& val) {
+ auto req_priv_lvl=addr>>8;
+ if(this->reg.machine_statefault_data);
+ val = csr[mie];
+ if(addr
+iss::status riscv_hart_msu_vp::write_ip(unsigned addr, reg_t val) {
+ auto req_priv_lvl=addr>>8;
+ if(this->reg.machine_statefault_data);
+ auto mask=get_irq_mask(req_priv_lvl);
+ csr[mip] = (csr[mip] & ~mask) | (val & mask);
+ check_interrupt();
+ return iss::Ok;
+}
+
+template
+iss::status riscv_hart_msu_vp::read_satp(unsigned addr, reg_t& val){
+ auto status = csr[mstatus];
+ auto tvm = status&(1<<20);
+ if(this->reg.machine_state==PRIV_S & tvm!=0){
+ this->reg.trap_state=(1<<31)|(2<<16);
+ this->fault_data=this->reg.PC;
+ return iss::Err;
+ }
+ val = csr[satp];
+ return iss::Ok;
+}
+
+template
+iss::status riscv_hart_msu_vp::write_satp(unsigned addr, reg_t val){
+ auto status = csr[mstatus];
+ auto tvm = status&(1<<20);
+ if(this->reg.machine_state==PRIV_S & tvm!=0){
+ this->reg.trap_state=(1<<31)|(2<<16);
+ this->fault_data=this->reg.PC;
+ return iss::Err;
+ }
+ csr[satp] = val;
+ return iss::Ok;
+}
+
+template
+iss::status riscv_hart_msu_vp::read_mem(phys_addr_t addr, unsigned length, uint8_t* const data) {
+ const auto& p = mem(addr.val/mem.page_size);
+ auto offs=addr.val&mem.page_addr_mask;
+ std::copy(p.data() + offs, p.data() + offs+length, data);
+ return iss::Ok;
+}
+
+template
+iss::status riscv_hart_msu_vp::write_mem(phys_addr_t addr, unsigned length, const uint8_t* const data) {
+ mem_type::page_type& p = mem(addr.val/mem.page_size);
+ std::copy(data, data+length, p.data()+(addr.val&mem.page_addr_mask));
+ // tohost handling in case of riscv-test
+ if((addr.type & iss::DEBUG)==0){
+ auto tohost_upper = (traits::XLEN==32 && addr.val == (tohost+4)) || (traits::XLEN==64 && addr.val == tohost);
+ auto tohost_lower = (traits::XLEN==32 && addr.val == tohost) || (traits::XLEN==64 && addr.val == tohost);
+ if(tohost_lower || tohost_upper){
+ uint64_t hostvar = *reinterpret_cast(p.data()+(tohost&mem.page_addr_mask));
+ if(tohost_upper || (tohost_lower && to_host_wr_cnt>0)){
+ switch(hostvar>>48){
+ case 0:
+ if(hostvar!=0x1)
+ LOG(logging::FATAL)<<"tohost value is 0x"<(hostvar & 0xff);
+ if(c=='\n' || c==0){
+ LOG(logging::INFO)<<"tohost send '"<::XLEN==32 && addr.val == fromhost+4) || (traits::XLEN==64 && addr.val == fromhost)){
+ uint64_t fhostvar = *reinterpret_cast(p.data()+(fromhost&mem.page_addr_mask));
+ *reinterpret_cast(p.data()+(tohost&mem.page_addr_mask)) = fhostvar;
+ }
+ }
+ return iss::Ok;
+}
+
+template
+void riscv_hart_msu_vp::check_interrupt(){
+ auto status = csr[mstatus];
+ auto ip = csr[mip];
+ auto ie = csr[mie];
+ auto ideleg = csr[mideleg];
+ // Multiple simultaneous interrupts and traps at the same privilege level are handled in the following decreasing priority order:
+ // external interrupts, software interrupts, timer interrupts, then finally any synchronous traps.
+ auto ena_irq=ip&ie;
+
+ auto mie = (csr[mstatus]>>3)&1;
+ auto m_enabled = this->reg.machine_state < PRIV_M || (this->reg.machine_state == PRIV_M && mie);
+ auto enabled_interrupts = m_enabled?ena_irq & ~ideleg :0;
+
+ if (enabled_interrupts == 0){
+ auto sie = (csr[mstatus]>>1)&1;
+ auto s_enabled = this->reg.machine_state < PRIV_S || (this->reg.machine_state == PRIV_S && sie);
+ enabled_interrupts = s_enabled?ena_irq & ideleg : 0;
+ }
+ if (enabled_interrupts!=0){
+ int res = 0;
+ while ((enabled_interrupts & 1) == 0)
+ enabled_interrupts >>= 1, res++;
+ this->reg.pending_trap = res<<16 | 1;
+ }
+
+}
+
+template
+typename riscv_hart_msu_vp::phys_addr_t riscv_hart_msu_vp::v2p(const iss::addr_t& addr){
+ const uint64_t tmp = reg_t(1) << (traits::XLEN-1);
+ const uint64_t msk = tmp | (tmp-1);
+
+ if(addr.space!=traits::MEM){ //non-memory access
+ phys_addr_t ret(addr);
+ ret.val &= msk;
+ return ret;
+ }
+
+ const access_type type = (access_type)(addr.getAccessType()&~iss::DEBUG);
+ uint32_t mode =type != iss::FETCH && bit_sub<17,1>(mstatus_r)? // MPRV
+ mode = bit_sub<11,2>(mstatus_r):// MPV
+ this->reg.machine_state;
+
+ const vm_info vm = decode_vm_info::XLEN>(mode, satp_r);
+
+ if (vm.levels == 0){
+ phys_addr_t ret(addr);
+ ret.val &= msk;
+ return ret;
+ }
+
+ const bool s_mode = mode == PRIV_S;
+ const bool sum = bit_sub<18,1>(mstatus_r); // MSTATUS_SUM);
+ const bool mxr = bit_sub<19,1>(mstatus_r);// MSTATUS_MXR);
+
+ auto it = ptw.find(addr.val >> PGSHIFT);
+ if(it!=ptw.end()){
+ const reg_t pte=it->second;
+ const reg_t ad = PTE_A | ((type == iss::WRITE) * PTE_D);
+#ifdef RISCV_ENABLE_DIRTY
+ // set accessed and possibly dirty bits.
+ *(uint32_t*)ppte |= ad;
+ return {addr.getAccessType(), addr.space, (pte&(~PGMASK)) | (addr.val & PGMASK)};
+#else
+ // take exception if access or possibly dirty bit is not set.
+ if ((pte & ad) == ad)
+ return {addr.getAccessType(), addr.space, (pte&(~PGMASK)) | (addr.val & PGMASK)};
+ else
+ ptw.erase(it);
+#endif
+ } else {
+ // verify bits xlen-1:va_bits-1 are all equal
+ const int va_bits = PGSHIFT + vm.levels * vm.idxbits;
+ const reg_t mask = (reg_t(1) << (traits::XLEN> - (va_bits-1))) - 1;
+ const reg_t masked_msbs = (addr.val >> (va_bits-1)) & mask;
+ const int levels = (masked_msbs != 0 && masked_msbs != mask)? 0: vm.levels;
+
+ reg_t base = vm.ptbase;
+ for (int i = levels - 1; i >= 0; i--) {
+ const int ptshift = i * vm.idxbits;
+ const reg_t idx = (addr.val >> (PGSHIFT + ptshift)) & ((1 << vm.idxbits) - 1);
+
+ // check that physical address of PTE is legal
+ reg_t pte = 0;
+ const uint8_t res = this->read(phys_addr_t(addr.getAccessType(), traits::MEM, base + idx * vm.ptesize), vm.ptesize, (uint8_t*)&pte);
+ if (res!=0)
+ throw trap_load_access_fault(addr.val);
+ const reg_t ppn = pte >> PTE_PPN_SHIFT;
+
+ if (PTE_TABLE(pte)) { // next level of page table
+ base = ppn << PGSHIFT;
+ } else if ((pte & PTE_U) ? s_mode && (type == iss::FETCH || !sum) : !s_mode) {
+ break;
+ } else if (!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) {
+ break;
+ } else if (type == iss::FETCH ? !(pte & PTE_X) :
+ type == iss::READ ? !(pte & PTE_R) && !(mxr && (pte & PTE_X)) :
+ !((pte & PTE_R) && (pte & PTE_W))) {
+ break;
+ } else if ((ppn & ((reg_t(1) << ptshift) - 1)) != 0) {
+ break;
+ } else {
+ const reg_t ad = PTE_A | ((type == iss::WRITE) * PTE_D);
+#ifdef RISCV_ENABLE_DIRTY
+ // set accessed and possibly dirty bits.
+ *(uint32_t*)ppte |= ad;
+#else
+ // take exception if access or possibly dirty bit is not set.
+ if ((pte & ad) != ad)
+ break;
+#endif
+ // for superpage mappings, make a fake leaf PTE for the TLB's benefit.
+ const reg_t vpn = addr.val >> PGSHIFT;
+ const reg_t value = (ppn | (vpn & ((reg_t(1) << ptshift) - 1))) << PGSHIFT;
+ const reg_t offset = addr.val & PGMASK;
+ ptw[vpn]=value | (pte&0xff);
+ return {addr.getAccessType(), addr.space, value | offset};
+ }
+ }
+ }
+ switch (type) {
+ case FETCH:
+ this->fault_data=addr.val;
+ throw trap_instruction_page_fault(addr.val);
+ case READ:
+ this->fault_data=addr.val;
+ throw trap_load_page_fault(addr.val);
+ case WRITE:
+ this->fault_data=addr.val;
+ throw trap_store_page_fault(addr.val);
+ default: abort();
+ }
+}
+
+template
+uint64_t riscv_hart_msu_vp::enter_trap(uint64_t flags, uint64_t addr) {
+ auto cur_priv=this->reg.machine_state;
+ // calculate and write mcause val
+ auto trap_id=flags&0xffff;
+ auto cause = (flags>>16)&0x7fff;
+ if(trap_id==0 && cause==11) cause = 0x8+cur_priv; // adjust environment call cause
+ // calculate effective privilege level
+ auto new_priv=PRIV_M;
+ if(trap_id==0){ // exception
+ if(cur_priv!=PRIV_M && ((csr[medeleg]>>cause)&0x1)!=0)
+ new_priv=(csr[sedeleg]>>cause)&0x1?PRIV_U:PRIV_S;
+ // store ret addr in xepc register
+ csr[uepc|(new_priv<<8)]=static_cast(addr); // store actual address instruction of exception
+ /*
+ * write mtval if new_priv=M_MODE, spec says:
+ * When a hardware breakpoint is triggered, or an instruction-fetch, load, or store address-misaligned,
+ * access, or page-fault exception occurs, mtval is written with the faulting effective address.
+ */
+ csr[utval|(new_priv<<8)]=fault_data;
+ fault_data=0;
+ }else{
+ if(cur_priv!=PRIV_M && ((csr[mideleg]>>cause)&0x1)!=0)
+ new_priv=(csr[sideleg]>>cause)&0x1?PRIV_U:PRIV_S;
+ csr[uepc|(new_priv<<8)]=this->reg.NEXT_PC; // store next address if interrupt
+ this->reg.pending_trap=0;
+ }
+ csr[ucause|(new_priv<<8)]=cause;
+ // update mstatus
+ // xPP field of mstatus is written with the active privilege mode at the time of the trap; the x PIE field of mstatus
+ // is written with the value of the active interrupt-enable bit at the time of the trap; and the x IE field of mstatus
+ // is cleared
+ auto status=csr[mstatus];
+ auto xie = (status>>cur_priv) & 1;
+ // store the actual privilege level in yPP
+ switch(new_priv){
+ case PRIV_M:
+ status&=~(3<<11);
+ status|=(cur_priv&0x3)<<11;
+ break;
+ case PRIV_S:
+ status&=~(1<<8);
+ status|=(cur_priv&0x1)<<8;
+ break;
+ default:
+ break;
+ }
+ // store interrupt enable flags
+ status&=~(1<<(new_priv+4) | 1<reg.NEXT_PC=ivec & ~0x1UL;
+ if((ivec&0x1)==1 && trap_id!=0)
+ this->reg.NEXT_PC+=4*cause;
+ // reset trap state
+ this->reg.machine_state=new_priv;
+ this->reg.trap_state=0;
+ char buffer[32];
+ sprintf(buffer, "0x%016lx", addr);
+ CLOG(logging::INFO, "disass")<<(trap_id?"Interrupt ":"Trap ")<reg.NEXT_PC;
+}
+
+template
+uint64_t riscv_hart_msu_vp::leave_trap(uint64_t flags) {
+ auto cur_priv=this->reg.machine_state;
+ auto inst_priv=flags&0x3;
+ auto status=csr[mstatus];
+ auto ppl = inst_priv; //previous privilege level
+
+ auto tsr = status&(1<<22);
+ if(cur_priv==PRIV_S && inst_priv==PRIV_S && tsr!=0){
+ this->reg.trap_state=(1<<31)|(2<<16);
+ this->fault_data=this->reg.PC;
+ return this->reg.PC;
+ }
+
+ // pop the relevant lower-privilege interrupt enable and privilege mode stack
+ switch(inst_priv){
+ case PRIV_M:
+ ppl=(status>>11)&0x3;
+ status&=~(0x3<<11); // clear mpp to U mode
+ break;
+ case PRIV_S:
+ ppl=(status>>8)&1;
+ status&=~(1<<8); // clear spp to U mode
+ break;
+ case PRIV_U:
+ ppl=0;
+ break;
+ }
+ // sets the pc to the value stored in the x epc register.
+ this->reg.NEXT_PC=csr[uepc|inst_priv<<8];
+ status&=~(1<>(inst_priv+4))&0x1; //previous interrupt enable
+ status|= pie<reg.machine_state=ppl;
+ CLOG(logging::INFO, "disass")<<"Executing xRET , changing privilege level from "<reg.NEXT_PC;
+}
+
+template
+void riscv_hart_msu_vp::wait_until(uint64_t flags) {
+ auto status=csr[mstatus];
+ auto tw = status & (1<<21);
+ if(this->reg.machine_state==PRIV_S && tw!=0){
+ this->reg.trap_state=(1<<31)|(2<<16);
+ this->fault_data=this->reg.PC;
+ }
+}
+}
+}
+
+#endif /* _RISCV_CORE_H_ */
diff --git a/riscv.sc/incl/iss/arch/rv32imac.h b/riscv.sc/incl/iss/arch/rv32imac.h
new file mode 100644
index 0000000..9800349
--- /dev/null
+++ b/riscv.sc/incl/iss/arch/rv32imac.h
@@ -0,0 +1,200 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2017, 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.
+//
+// Created on: Thu Sep 21 17:01:54 CEST 2017
+// * rv32imac.h Author:
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef _RV32IMAC_H_
+#define _RV32IMAC_H_
+
+#include
+#include
+#include
+
+namespace iss {
+namespace arch {
+
+struct rv32imac;
+
+template<>
+struct traits {
+
+ enum constants {XLEN=32,XLEN2=64,XLEN_BIT_MASK=31,PCLEN=32,fence=0,fencei=1,fencevmal=2,fencevmau=3,MISA_VAL=1075056897,PGSIZE=4096,PGMASK=4095};
+
+ enum reg_e {
+ X0,
+ X1,
+ X2,
+ X3,
+ X4,
+ X5,
+ X6,
+ X7,
+ X8,
+ X9,
+ X10,
+ X11,
+ X12,
+ X13,
+ X14,
+ X15,
+ X16,
+ X17,
+ X18,
+ X19,
+ X20,
+ X21,
+ X22,
+ X23,
+ X24,
+ X25,
+ X26,
+ X27,
+ X28,
+ X29,
+ X30,
+ X31,
+ PC,
+ NUM_REGS,
+ NEXT_PC=NUM_REGS,
+ TRAP_STATE,
+ PENDING_TRAP,
+ MACHINE_STATE,
+ ICOUNT
+ };
+
+ typedef uint32_t reg_t;
+
+ typedef uint32_t addr_t;
+
+ typedef uint32_t code_word_t; //TODO: check removal
+
+ typedef iss::typed_addr_t virt_addr_t;
+
+ typedef iss::typed_addr_t phys_addr_t;
+
+ constexpr static unsigned reg_bit_width(unsigned r) {
+ const uint32_t RV32IMAC_reg_size[] = {32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,64};
+ return RV32IMAC_reg_size[r];
+ }
+
+ constexpr static unsigned reg_byte_offset(unsigned r) {
+ const uint32_t RV32IMAC_reg_byte_offset[] = {0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140,144,152,160};
+ return RV32IMAC_reg_byte_offset[r];
+ }
+
+ enum sreg_flag_e {FLAGS};
+
+ enum mem_type_e {MEM,CSR,FENCE,RES};
+
+};
+
+struct rv32imac: public arch_if {
+
+ using virt_addr_t = typename traits::virt_addr_t;
+ using phys_addr_t = typename traits::phys_addr_t;
+ using reg_t = typename traits::reg_t;
+ using addr_t = typename traits::addr_t;
+
+ rv32imac();
+ ~rv32imac();
+
+ virtual void reset(uint64_t address=0) override;
+
+ virtual uint8_t* get_regs_base_ptr() override;
+ /// deprecated
+ virtual void get_reg(short idx, std::vector& value) override {}
+ virtual void set_reg(short idx, const std::vector& value) override {}
+ /// deprecated
+ virtual bool get_flag(int flag) override {return false;}
+ virtual void set_flag(int, bool value) override {};
+ /// deprecated
+ virtual void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {};
+
+ virtual void notify_phase(exec_phase phase){
+ if(phase==ISTART){
+ ++reg.icount;
+ reg.PC=reg.NEXT_PC;
+ reg.trap_state=reg.pending_trap;
+ }
+ }
+
+ uint64_t get_icount() { return reg.icount;}
+
+ virtual phys_addr_t v2p(const iss::addr_t& pc);
+
+ virtual iss::sync_type needed_sync() const { return iss::PRE_SYNC; }
+
+protected:
+ struct RV32IMAC_regs {
+ uint32_t X0;
+ uint32_t X1;
+ uint32_t X2;
+ uint32_t X3;
+ uint32_t X4;
+ uint32_t X5;
+ uint32_t X6;
+ uint32_t X7;
+ uint32_t X8;
+ uint32_t X9;
+ uint32_t X10;
+ uint32_t X11;
+ uint32_t X12;
+ uint32_t X13;
+ uint32_t X14;
+ uint32_t X15;
+ uint32_t X16;
+ uint32_t X17;
+ uint32_t X18;
+ uint32_t X19;
+ uint32_t X20;
+ uint32_t X21;
+ uint32_t X22;
+ uint32_t X23;
+ uint32_t X24;
+ uint32_t X25;
+ uint32_t X26;
+ uint32_t X27;
+ uint32_t X28;
+ uint32_t X29;
+ uint32_t X30;
+ uint32_t X31;
+ uint32_t PC;
+ uint32_t NEXT_PC;
+ uint32_t trap_state, pending_trap, machine_state;
+ uint64_t icount;
+ } reg;
+};
+
+}
+}
+#endif /* _RV32IMAC_H_ */
diff --git a/riscv.sc/incl/iss/arch/rv64ia.h b/riscv.sc/incl/iss/arch/rv64ia.h
new file mode 100644
index 0000000..c45cfe2
--- /dev/null
+++ b/riscv.sc/incl/iss/arch/rv64ia.h
@@ -0,0 +1,200 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2017, 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.
+//
+// Created on: Thu Sep 21 17:01:54 CEST 2017
+// * rv64ia.h Author:
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef _RV64IA_H_
+#define _RV64IA_H_
+
+#include
+#include
+#include
+
+namespace iss {
+namespace arch {
+
+struct rv64ia;
+
+template<>
+struct traits {
+
+ enum constants {XLEN=64,XLEN2=128,XLEN_BIT_MASK=63,PCLEN=64,fence=0,fencei=1,fencevmal=2,fencevmau=3,MISA_VAL=2147750144,PGSIZE=4096,PGMASK=4095};
+
+ enum reg_e {
+ X0,
+ X1,
+ X2,
+ X3,
+ X4,
+ X5,
+ X6,
+ X7,
+ X8,
+ X9,
+ X10,
+ X11,
+ X12,
+ X13,
+ X14,
+ X15,
+ X16,
+ X17,
+ X18,
+ X19,
+ X20,
+ X21,
+ X22,
+ X23,
+ X24,
+ X25,
+ X26,
+ X27,
+ X28,
+ X29,
+ X30,
+ X31,
+ PC,
+ NUM_REGS,
+ NEXT_PC=NUM_REGS,
+ TRAP_STATE,
+ PENDING_TRAP,
+ MACHINE_STATE,
+ ICOUNT
+ };
+
+ typedef uint64_t reg_t;
+
+ typedef uint64_t addr_t;
+
+ typedef uint64_t code_word_t; //TODO: check removal
+
+ typedef iss::typed_addr_t virt_addr_t;
+
+ typedef iss::typed_addr_t phys_addr_t;
+
+ constexpr static unsigned reg_bit_width(unsigned r) {
+ const uint32_t RV64IA_reg_size[] = {64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,32,32,32,64};
+ return RV64IA_reg_size[r];
+ }
+
+ constexpr static unsigned reg_byte_offset(unsigned r) {
+ const uint32_t RV64IA_reg_byte_offset[] = {0,8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128,136,144,152,160,168,176,184,192,200,208,216,224,232,240,248,256,264,272,276,280,288,296};
+ return RV64IA_reg_byte_offset[r];
+ }
+
+ enum sreg_flag_e {FLAGS};
+
+ enum mem_type_e {MEM,CSR,FENCE,RES};
+
+};
+
+struct rv64ia: public arch_if {
+
+ using virt_addr_t = typename traits::virt_addr_t;
+ using phys_addr_t = typename traits::phys_addr_t;
+ using reg_t = typename traits::reg_t;
+ using addr_t = typename traits::addr_t;
+
+ rv64ia();
+ ~rv64ia();
+
+ virtual void reset(uint64_t address=0) override;
+
+ virtual uint8_t* get_regs_base_ptr() override;
+ /// deprecated
+ virtual void get_reg(short idx, std::vector& value) override {}
+ virtual void set_reg(short idx, const std::vector& value) override {}
+ /// deprecated
+ virtual bool get_flag(int flag) override {return false;}
+ virtual void set_flag(int, bool value) override {};
+ /// deprecated
+ virtual void update_flags(operations op, uint64_t opr1, uint64_t opr2) override {};
+
+ virtual void notify_phase(exec_phase phase){
+ if(phase==ISTART){
+ ++reg.icount;
+ reg.PC=reg.NEXT_PC;
+ reg.trap_state=reg.pending_trap;
+ }
+ }
+
+ uint64_t get_icount() { return reg.icount;}
+
+ virtual phys_addr_t v2p(const iss::addr_t& pc);
+
+ virtual iss::sync_type needed_sync() const { return iss::PRE_SYNC; }
+
+protected:
+ struct RV64IA_regs {
+ uint64_t X0;
+ uint64_t X1;
+ uint64_t X2;
+ uint64_t X3;
+ uint64_t X4;
+ uint64_t X5;
+ uint64_t X6;
+ uint64_t X7;
+ uint64_t X8;
+ uint64_t X9;
+ uint64_t X10;
+ uint64_t X11;
+ uint64_t X12;
+ uint64_t X13;
+ uint64_t X14;
+ uint64_t X15;
+ uint64_t X16;
+ uint64_t X17;
+ uint64_t X18;
+ uint64_t X19;
+ uint64_t X20;
+ uint64_t X21;
+ uint64_t X22;
+ uint64_t X23;
+ uint64_t X24;
+ uint64_t X25;
+ uint64_t X26;
+ uint64_t X27;
+ uint64_t X28;
+ uint64_t X29;
+ uint64_t X30;
+ uint64_t X31;
+ uint64_t PC;
+ uint64_t NEXT_PC;
+ uint32_t trap_state, pending_trap, machine_state;
+ uint64_t icount;
+ } reg;
+};
+
+}
+}
+#endif /* _RV64IA_H_ */
diff --git a/riscv/incl/sysc/SiFive/core_complex.h b/riscv.sc/incl/sysc/SiFive/core_complex.h
similarity index 100%
rename from riscv/incl/sysc/SiFive/core_complex.h
rename to riscv.sc/incl/sysc/SiFive/core_complex.h
diff --git a/riscv/incl/sysc/SiFive/gen/e300_plat_t.h b/riscv.sc/incl/sysc/SiFive/gen/e300_plat_t.h
similarity index 100%
rename from riscv/incl/sysc/SiFive/gen/e300_plat_t.h
rename to riscv.sc/incl/sysc/SiFive/gen/e300_plat_t.h
diff --git a/riscv/incl/sysc/SiFive/gen/gpio_regs.h b/riscv.sc/incl/sysc/SiFive/gen/gpio_regs.h
similarity index 100%
rename from riscv/incl/sysc/SiFive/gen/gpio_regs.h
rename to riscv.sc/incl/sysc/SiFive/gen/gpio_regs.h
diff --git a/riscv/incl/sysc/SiFive/gen/plic_regs.h b/riscv.sc/incl/sysc/SiFive/gen/plic_regs.h
similarity index 100%
rename from riscv/incl/sysc/SiFive/gen/plic_regs.h
rename to riscv.sc/incl/sysc/SiFive/gen/plic_regs.h
diff --git a/riscv/incl/sysc/SiFive/gen/spi_regs.h b/riscv.sc/incl/sysc/SiFive/gen/spi_regs.h
similarity index 100%
rename from riscv/incl/sysc/SiFive/gen/spi_regs.h
rename to riscv.sc/incl/sysc/SiFive/gen/spi_regs.h
diff --git a/riscv/incl/sysc/SiFive/gen/uart_regs.h b/riscv.sc/incl/sysc/SiFive/gen/uart_regs.h
similarity index 100%
rename from riscv/incl/sysc/SiFive/gen/uart_regs.h
rename to riscv.sc/incl/sysc/SiFive/gen/uart_regs.h
diff --git a/riscv/incl/sysc/SiFive/gpio.h b/riscv.sc/incl/sysc/SiFive/gpio.h
similarity index 100%
rename from riscv/incl/sysc/SiFive/gpio.h
rename to riscv.sc/incl/sysc/SiFive/gpio.h
diff --git a/riscv/incl/sysc/SiFive/platform.h b/riscv.sc/incl/sysc/SiFive/platform.h
similarity index 100%
rename from riscv/incl/sysc/SiFive/platform.h
rename to riscv.sc/incl/sysc/SiFive/platform.h
diff --git a/riscv/incl/sysc/SiFive/plic.h b/riscv.sc/incl/sysc/SiFive/plic.h
similarity index 100%
rename from riscv/incl/sysc/SiFive/plic.h
rename to riscv.sc/incl/sysc/SiFive/plic.h
diff --git a/riscv/incl/sysc/SiFive/spi.h b/riscv.sc/incl/sysc/SiFive/spi.h
similarity index 100%
rename from riscv/incl/sysc/SiFive/spi.h
rename to riscv.sc/incl/sysc/SiFive/spi.h
diff --git a/riscv/incl/sysc/SiFive/uart.h b/riscv.sc/incl/sysc/SiFive/uart.h
similarity index 100%
rename from riscv/incl/sysc/SiFive/uart.h
rename to riscv.sc/incl/sysc/SiFive/uart.h
diff --git a/riscv.sc/src/CMakeLists.txt b/riscv.sc/src/CMakeLists.txt
new file mode 100644
index 0000000..871c18e
--- /dev/null
+++ b/riscv.sc/src/CMakeLists.txt
@@ -0,0 +1,62 @@
+# library files
+FILE(GLOB RiscVSCHeaders *.h)
+set(LIB_HEADERS ${RiscVSCHeaders} )
+set(LIB_SOURCES
+ sysc/core_complex.cpp
+ sysc/gpio.cpp
+ sysc/plic.cpp
+ sysc/platform.cpp
+ sysc/spi.cpp
+ sysc/uart.cpp
+)
+
+set(APP_HEADERS )
+
+set(APP_SOURCES sc_main.cpp
+)
+
+# Define two variables in order not to repeat ourselves.
+set(LIBRARY_NAME risc-v.sc)
+
+# Define the library
+add_library(${LIBRARY_NAME} ${LIB_SOURCES})
+
+set_target_properties(${LIBRARY_NAME} PROPERTIES
+ VERSION ${VERSION} # ${VERSION} was defined in the main CMakeLists.
+ FRAMEWORK FALSE
+ PUBLIC_HEADER "${LIB_HEADERS}" # specify the public headers
+)
+
+# This is a make target, so you can do a "make riscv-sc"
+set(APPLICATION_NAME riscv.sc)
+
+add_executable(${APPLICATION_NAME} ${APP_SOURCES})
+
+# Links the target exe against the libraries
+target_link_libraries(${APPLICATION_NAME} ${LIBRARY_NAME})
+target_link_libraries(${APPLICATION_NAME} dbt-core)
+target_link_libraries(${APPLICATION_NAME} sc-components)
+target_link_libraries(${APPLICATION_NAME} external)
+target_link_libraries(${APPLICATION_NAME} risc-v)
+target_link_libraries(${APPLICATION_NAME} ${llvm_libs})
+target_link_libraries(${APPLICATION_NAME} ${SystemC_LIBRARIES} )
+if(SCV_FOUND)
+ target_link_libraries (${APPLICATION_NAME} ${SCV_LIBRARIES})
+endif()
+target_link_libraries(${APPLICATION_NAME} ${Boost_LIBRARIES} )
+
+# Says how and where to install software
+# Targets:
+# * /lib/
+# * header location after install: /include//*.h
+# * headers can be included by C++ code `#/Bar.hpp>`
+install(TARGETS ${LIBRARY_NAME} ${APPLICATION_NAME}
+ EXPORT ${PROJECT_NAME}Targets # for downstream dependencies
+ ARCHIVE DESTINATION lib COMPONENT libs # static lib
+ RUNTIME DESTINATION bin COMPONENT libs # binaries
+ LIBRARY DESTINATION lib COMPONENT libs # shared lib
+ FRAMEWORK DESTINATION bin COMPONENT libs # for mac
+ PUBLIC_HEADER DESTINATION incl/${PROJECT_NAME} COMPONENT devel # headers for mac (note the different component -> different package)
+ INCLUDES DESTINATION incl # headers
+)
+
diff --git a/riscv.sc/src/internal/vm_riscv.in.cpp b/riscv.sc/src/internal/vm_riscv.in.cpp
new file mode 100644
index 0000000..b5c7b7c
--- /dev/null
+++ b/riscv.sc/src/internal/vm_riscv.in.cpp
@@ -0,0 +1,695 @@
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2017, MINRES Technologies GmbH
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors
+// may be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Contributors:
+// eyck@minres.com - initial API and implementation
+//
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+#include
+#include
+#include
+
+#include "iss/vm_base.h"
+#include "iss/arch/CORE_DEF_NAME.h"
+#include "iss/debugger/server.h"
+
+#include
+#include "iss/arch/riscv_hart_msu_vp.h"
+
+namespace iss {
+namespace CORE_DEF_NAME {
+using namespace iss::arch;
+using namespace llvm;
+using namespace iss::debugger;
+
+template
+struct vm_impl;
+
+template
+struct target_adapter: public target_adapter_base {
+
+ target_adapter(server_if* srv, vm_impl* vm)
+ : target_adapter_base(srv)
+ , vm(vm)
+ {
+ }
+
+ /*============== Thread Control ===============================*/
+
+ /* Set generic thread */
+ status set_gen_thread(rp_thread_ref& thread) override;
+
+ /* Set control thread */
+ status set_ctrl_thread(rp_thread_ref& thread) override;
+
+ /* Get thread status */
+ status is_thread_alive(rp_thread_ref& thread, bool& alive) override;
+
+ /*============= Register Access ================================*/
+
+ /* Read all registers. buf is 4-byte aligned and it is in
+ target byte order. If register is not available
+ corresponding bytes in avail_buf are 0, otherwise
+ avail buf is 1 */
+ status read_registers(std::vector& data, std::vector& avail) override;
+
+ /* Write all registers. buf is 4-byte aligned and it is in target
+ byte order */
+ status write_registers(const std::vector& data) override;
+
+ /* Read one register. buf is 4-byte aligned and it is in
+ target byte order. If register is not available
+ corresponding bytes in avail_buf are 0, otherwise
+ avail buf is 1 */
+ status read_single_register(unsigned int reg_no, std::vector& buf, std::vector& avail_buf) override;
+
+ /* Write one register. buf is 4-byte aligned and it is in target byte
+ order */
+ status write_single_register(unsigned int reg_no, const std::vector& buf) override;
+
+ /*=================== Memory Access =====================*/
+
+ /* Read memory, buf is 4-bytes aligned and it is in target
+ byte order */
+ status read_mem(uint64_t addr, std::vector& buf) override;
+
+ /* Write memory, buf is 4-bytes aligned and it is in target
+ byte order */
+ status write_mem(uint64_t addr, const std::vector& buf) override;
+
+ status process_query(unsigned int& mask, const rp_thread_ref& arg, rp_thread_info& info) override;
+
+ status thread_list_query(int first, const rp_thread_ref& arg, std::vector& result, size_t max_num, size_t& num, bool& done) override;
+
+ status current_thread_query(rp_thread_ref& thread) override;
+
+ status offsets_query(uint64_t& text, uint64_t& data, uint64_t& bss) override;
+
+ status crc_query(uint64_t addr, size_t len, uint32_t& val) override;
+
+ status raw_query(std::string in_buf, std::string& out_buf) override;
+
+ status threadinfo_query(int first, std::string& out_buf) override;
+
+ status threadextrainfo_query(const rp_thread_ref& thread, std::string& out_buf) override;
+
+ status packetsize_query(std::string& out_buf) override;
+
+ status add_break(int type, uint64_t addr, unsigned int length) override;
+
+ status remove_break(int type, uint64_t addr, unsigned int length) override;
+
+ status resume_from_addr(bool step, int sig, uint64_t addr) override;
+
+protected:
+ static inline constexpr addr_t map_addr(const addr_t& i){
+ return i;
+ }
+
+ vm_impl* vm;
+ rp_thread_ref thread_idx;
+};
+
+template
+struct vm_impl: public vm::vm_base {
+ using super = typename vm::vm_base;
+ using virt_addr_t = typename super::virt_addr_t;
+ using phys_addr_t = typename super::phys_addr_t;
+ using code_word_t = typename super::code_word_t;
+ using addr_t = typename super::addr_t ;
+
+ vm_impl();
+
+ vm_impl(ARCH& core, bool dump=false);
+
+ void enableDebug(bool enable) {
+ super::sync_exec=super::ALL_SYNC;
+ }
+
+ target_adapter_if* accquire_target_adapter(server_if* srv){
+ debugger_if::dbg_enabled=true;
+ if(vm::vm_base::tgt_adapter==nullptr)
+ vm::vm_base::tgt_adapter=new target_adapter(srv, this);
+ return vm::vm_base::tgt_adapter;
+ }
+
+
+protected:
+
+ template inline
+ llvm::ConstantInt* size(T type){
+ return llvm::ConstantInt::get(getContext(), llvm::APInt(32, type->getType()->getScalarSizeInBits()));
+ }
+
+ inline llvm::Value * gen_choose(llvm::Value * cond, llvm::Value * trueVal, llvm::Value * falseVal, unsigned size) const {
+ return this->gen_cond_assign(cond, this->gen_ext(trueVal, size), this->gen_ext(falseVal, size));
+ }
+
+ std::tuple gen_single_inst_behavior(virt_addr_t&, unsigned int&, llvm::BasicBlock*) override;
+
+ void gen_leave_behavior(llvm::BasicBlock* leave_blk) override;
+
+ void gen_raise_trap(uint16_t trap_id, uint16_t cause);
+
+ void gen_leave_trap(unsigned lvl);
+
+ void gen_wait(unsigned type);
+
+ void gen_trap_behavior(llvm::BasicBlock*) override;
+
+ void gen_trap_check(llvm::BasicBlock* bb);
+
+ inline
+ void gen_set_pc(virt_addr_t pc, unsigned reg_num){
+ llvm::Value* next_pc_v = this->builder->CreateSExtOrTrunc(this->gen_const(traits::XLEN, pc.val), this->get_type(traits::XLEN));
+ this->builder->CreateStore(next_pc_v, get_reg_ptr(reg_num), true);
+ }
+
+ inline
+ llvm::Value* get_reg_ptr(unsigned i){
+ void* ptr = this->core.get_regs_base_ptr()+traits::reg_byte_offset(i);
+ llvm::PointerType* ptrType=nullptr;
+ switch (traits::reg_bit_width(i)>>3) {
+ case 8:
+ ptrType=llvm::Type::getInt64PtrTy(this->mod->getContext());
+ break;
+ case 4:
+ ptrType=llvm::Type::getInt32PtrTy(this->mod->getContext());
+ break;
+ case 2:
+ ptrType=llvm::Type::getInt16PtrTy(this->mod->getContext());
+ break;
+ case 1:
+ ptrType=llvm::Type::getInt8PtrTy(this->mod->getContext());
+ break;
+ default:
+ throw std::runtime_error("unsupported access with");
+ break;
+ }
+ return llvm::ConstantExpr::getIntToPtr(
+ llvm::ConstantInt::get(this->mod->getContext(), llvm::APInt(
+ 8/*bits*/ * sizeof(uint8_t*),
+ reinterpret_cast(ptr)
+ )),
+ ptrType);
+ }
+
+ inline
+ llvm::Value* gen_reg_load(unsigned i, unsigned level=0){
+// if(level){
+ return this->builder->CreateLoad(get_reg_ptr(i), false);
+// } else {
+// if(!this->loaded_regs[i])
+// this->loaded_regs[i]=this->builder->CreateLoad(get_reg_ptr(i), false);
+// return this->loaded_regs[i];
+// }
+ }
+
+ inline
+ void gen_set_pc(virt_addr_t pc){
+ llvm::Value* pc_l = this->builder->CreateSExt(this->gen_const(traits::caddr_bit_width, (unsigned)pc), this->get_type(traits::caddr_bit_width));
+ super::gen_set_reg(traits::PC, pc_l);
+ }
+
+ // some compile time constants
+ enum {MASK16 = 0b1111110001100011, MASK32 = 0b11111111111100000111000001111111};
+ enum {EXTR_MASK16 = MASK16>>2, EXTR_MASK32 = MASK32>>2};
+ enum {LUT_SIZE = 1<< bit_count(EXTR_MASK32), LUT_SIZE_C = 1<;
+ using compile_func = std::tuple (this_class::*)(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb);
+ compile_func lut[LUT_SIZE];
+
+ std::array lut_00, lut_01, lut_10;
+ std::array lut_11;
+
+ compile_func* qlut[4];// = {lut_00, lut_01, lut_10, lut_11};
+
+ const uint32_t lutmasks[4]={EXTR_MASK16, EXTR_MASK16, EXTR_MASK16, EXTR_MASK32};
+
+ void expand_bit_mask(int pos, uint32_t mask, uint32_t value, uint32_t valid, uint32_t idx, compile_func lut[], compile_func f){
+ if(pos<0){
+ lut[idx]=f;
+ } else {
+ auto bitmask = 1UL<>2, lutmasks[val&0x3], 0);
+ }
+
+ uint32_t extract_fields(int pos, uint32_t val, uint32_t mask, uint32_t lut_val){
+ if(pos>=0) {
+ auto bitmask = 1UL< illegal_intruction(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){
+ //this->gen_sync(iss::PRE_SYNC);
+ this->builder->CreateStore(
+ this->builder->CreateLoad(get_reg_ptr(traits::NEXT_PC), true),
+ get_reg_ptr(traits::PC), true);
+ this->builder->CreateStore(
+ this->builder->CreateAdd(
+ this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), true),
+ this->gen_const(64U, 1)),
+ get_reg_ptr(traits::ICOUNT), true);
+ if(this->debugging_enabled()) this->gen_sync(iss::PRE_SYNC);
+ pc=pc+((instr&3) == 3?4:2);
+ this->gen_raise_trap(0, 2); // illegal instruction trap
+ this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */
+ this->gen_trap_check(this->leave_blk);
+ return std::make_tuple(iss::vm::BRANCH, nullptr);
+ }
+
+};
+
+template
+void debug_fn(CODE_WORD insn){
+ volatile CODE_WORD x=insn;
+ insn=2*x;
+}
+
+template
+vm_impl::vm_impl(){
+ this(new ARCH());
+}
+
+template
+vm_impl::vm_impl(ARCH& core, bool dump) : vm::vm_base(core, dump) {
+ qlut[0] = lut_00.data();
+ qlut[1] = lut_01.data();
+ qlut[2] = lut_10.data();
+ qlut[3] = lut_11.data();
+ for(auto instr: instr_descr){
+ auto quantrant = instr.value&0x3;
+ expand_bit_mask(29, lutmasks[quantrant], instr.value>>2, instr.mask>>2, 0, qlut[quantrant], instr.op);
+ }
+ this->sync_exec=static_cast(this->sync_exec|core.needed_sync());
+}
+
+template
+std::tuple vm_impl::gen_single_inst_behavior(virt_addr_t& pc, unsigned int& inst_cnt, llvm::BasicBlock* this_block){
+ // we fetch at max 4 byte, alignment is 2
+ code_word_t insn = 0;
+ iss::addr_t paddr;
+ const typename traits::addr_t upper_bits = ~traits::PGMASK;
+ try {
+ uint8_t* const data = (uint8_t*)&insn;
+ paddr=this->core.v2p(pc);
+ if((pc.val&upper_bits) != ((pc.val+2)&upper_bits)){ // we may cross a page boundary
+ auto res = this->core.read(paddr, 2, data);
+ if(res!=iss::Ok)
+ throw trap_access(1, pc.val);
+ if((insn & 0x3) == 0x3){ // this is a 32bit instruction
+ res = this->core.read(this->core.v2p(pc+2), 2, data+2);
+ }
+ } else {
+ auto res = this->core.read(paddr, 4, data);
+ if(res!=iss::Ok)
+ throw trap_access(1, pc.val);
+ }
+ } catch(trap_access& ta){
+ throw trap_access(ta.id, pc.val);
+ }
+ if(insn==0x0000006f)
+ throw simulation_stopped(0);
+ // curr pc on stack
+ typename vm_impl::processing_pc_entry addr(*this, pc, paddr);
+ ++inst_cnt;
+ auto lut_val = extract_fields(insn);
+ auto f = qlut[insn&0x3][lut_val];
+ if (f==nullptr){
+ f=&this_class::illegal_intruction;
+ }
+ return (this->*f)(pc, insn, this_block);
+}
+
+template
+void vm_impl::gen_leave_behavior(llvm::BasicBlock* leave_blk){
+ this->builder->SetInsertPoint(leave_blk);
+ this->builder->CreateRet(this->builder->CreateLoad(get_reg_ptr(arch::traits::NEXT_PC), false));
+}
+
+template
+void vm_impl::gen_raise_trap(uint16_t trap_id, uint16_t cause){
+ auto* TRAP_val = this->gen_const(32, 0x80<<24| (cause<<16) | trap_id );
+ this->builder->CreateStore(TRAP_val, get_reg_ptr(traits::TRAP_STATE), true);
+}
+
+template
+void vm_impl::gen_leave_trap(unsigned lvl){
+ std::vector args {
+ this->core_ptr,
+ llvm::ConstantInt::get(getContext(), llvm::APInt(64, lvl)),
+ };
+ this->builder->CreateCall(this->mod->getFunction("leave_trap"), args);
+ auto* PC_val = this->gen_read_mem(traits::CSR, (lvl<<8)+0x41, traits::XLEN/8);
+ this->builder->CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false);
+}
+
+template
+void vm_impl::gen_wait(unsigned type){
+ std::vector args {
+ this->core_ptr,
+ llvm::ConstantInt::get(getContext(), llvm::APInt(64, type)),
+ };
+ this->builder->CreateCall(this->mod->getFunction("wait"), args);
+}
+
+template
+void vm_impl::gen_trap_behavior(llvm::BasicBlock* trap_blk){
+ this->builder->SetInsertPoint(trap_blk);
+ auto* trap_state_val = this->builder->CreateLoad(get_reg_ptr(traits::TRAP_STATE), true);
+ std::vector args {
+ this->core_ptr,
+ this->adj_to64(trap_state_val),
+ this->adj_to64(this->builder->CreateLoad(get_reg_ptr(traits::PC), false))
+ };
+ this->builder->CreateCall(this->mod->getFunction("enter_trap"), args);
+ auto* trap_addr_val = this->builder->CreateLoad(get_reg_ptr(traits::NEXT_PC), false);
+ this->builder->CreateRet(trap_addr_val);
+}
+
+template inline
+void vm_impl::gen_trap_check(llvm::BasicBlock* bb){
+ auto* v = this->builder->CreateLoad(get_reg_ptr(arch::traits::TRAP_STATE), true);
+ this->gen_cond_branch(
+ this->builder->CreateICmp(
+ ICmpInst::ICMP_EQ,
+ v,
+ llvm::ConstantInt::get(getContext(), llvm::APInt(v->getType()->getIntegerBitWidth(), 0))),
+ bb,
+ this->trap_blk, 1);
+}
+
+} // namespace CORE_DEF_NAME
+
+#define CREATE_FUNCS(ARCH) \
+template<> std::unique_ptr create(ARCH* core, unsigned short port, bool dump) {\
+ std::unique_ptr > ret = std::make_unique >(*core, dump);\
+ debugger::server::run_server(ret.get(), port);\
+ return ret;\
+}\
+template<> std::unique_ptr create(std::string inst_name, unsigned short port, bool dump) {\
+ return create(new arch::riscv_hart_msu_vp(), port, dump); /* FIXME: memory leak!!!!!!! */\
+}\
+template<> std::unique_ptr create(ARCH* core, bool dump) {\
+ return std::make_unique >(*core, dump); /* FIXME: memory leak!!!!!!! */ \
+}\
+template<> std::unique_ptr create(std::string inst_name, bool dump) { \
+ return create(new arch::riscv_hart_msu_vp(), dump);\
+}
+
+CREATE_FUNCS(arch::CORE_DEF_NAME)
+
+namespace CORE_DEF_NAME {
+
+ template
+ status target_adapter::set_gen_thread(rp_thread_ref& thread) {
+ thread_idx=thread;
+ return Ok;
+ }
+
+ template
+ status target_adapter::set_ctrl_thread(rp_thread_ref& thread) {
+ thread_idx=thread;
+ return Ok;
+ }
+
+ template
+ status target_adapter::is_thread_alive(rp_thread_ref& thread, bool& alive) {
+ alive=1;
+ return Ok;
+ }
+
+ /* List threads. If first is non-zero then start from the first thread,
+ * otherwise start from arg, result points to array of threads to be
+ * filled out, result size is number of elements in the result,
+ * num points to the actual number of threads found, done is
+ * set if all threads are processed.
+ */
+ template
+ status target_adapter::thread_list_query(int first, const rp_thread_ref& arg, std::vector& result, size_t max_num,
+ size_t& num, bool& done) {
+ if(first==0){
+ result.clear();
+ result.push_back(thread_idx);
+ num=1;
+ done=true;
+ return Ok;
+ } else
+ return NotSupported;
+ }
+
+ template
+ status target_adapter::current_thread_query(rp_thread_ref& thread) {
+ thread=thread_idx;
+ return Ok;
+ }
+
+ template
+ status target_adapter::read_registers(std::vector& data, std::vector& avail) {
+ LOG(logging::TRACE)<<"reading target registers";
+ //return idx<0?:;
+ data.clear();
+ avail.clear();
+ std::vector reg_data;
+ for(size_t reg_no = 0; reg_no < arch::traits::NUM_REGS; ++reg_no){
+ auto reg_bit_width = arch::traits::reg_bit_width(static_cast::reg_e>(reg_no));
+ auto reg_width=reg_bit_width/8;
+ reg_data.resize(reg_width);
+ vm->get_arch()->get_reg(reg_no, reg_data);
+ for(size_t j=0; j::NUM_REGS < 65){
+ auto reg_width=sizeof(typename arch::traits::reg_t);
+ for(size_t reg_no = 0; reg_no < 33; ++reg_no){
+ for(size_t j=0; j
+ status target_adapter::write_registers(const std::vector& data) {
+ size_t data_index=0;
+ auto reg_count=arch::traits::NUM_REGS;
+ std::vector reg_data;
+ for(size_t reg_no = 0; reg_no < reg_count; ++reg_no){
+ auto reg_bit_width = arch::traits::reg_bit_width(static_cast::reg_e>(reg_no));
+ auto reg_width=reg_bit_width/8;
+ vm->get_arch()->set_reg(reg_no, std::vector(data.begin()+data_index, data.begin()+data_index+reg_width));
+ data_index+=reg_width;
+ }
+ return Ok;
+ }
+
+ template
+ status target_adapter::read_single_register(unsigned int reg_no, std::vector