From 4ee7118b70f25fb72205eb50b7cd4ef5c1ff0ebf Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Sun, 27 Aug 2017 12:10:38 +0200 Subject: [PATCH] Initial commit --- .cproject | 546 ++ .gitignore | 32 + .gitmodules | 15 + .project | 27 + CMakeLists.txt | 32 + LICENSE | 29 + README.md | 42 + cmake/Common.cmake | 20 + cmake/DoxygenTarget.cmake | 24 + cmake/FindSystemC.cmake | 91 + cmake/GetGitRevisionDescription.cmake | 130 + cmake/GetGitRevisionDescription.cmake.in | 41 + cmake/PackageConfigurator.cmake | 44 + cmake/Submodules.cmake | 53 + dbt-core | 1 + external/CMakeLists.txt | 31 + external/easyloggingpp | 1 + external/elfio | 1 + external/libGIS | 1 + riscv/.gitignore | 1 + riscv/.project | 17 + riscv/.settings/.gitignore | 1 + riscv/CMakeLists.txt | 95 + riscv/incl/cli_options.h | 168 + riscv/incl/iss/arch/minrv_ima.h | 200 + riscv/incl/iss/arch/riscv_core.h | 1249 +++++ riscv/src/CMakeLists.txt | 56 + riscv/src/RV32A.core_desc | 108 + riscv/src/RV32C.core_desc | 310 ++ riscv/src/RV32F.core_desc | 105 + riscv/src/RV32IBase.core_desc | 308 ++ riscv/src/RV32M.core_desc | 81 + riscv/src/RV64A.core_desc | 111 + riscv/src/RV64IBase.core_desc | 99 + riscv/src/RV64M.core_desc | 41 + riscv/src/internal/vm_minrv_ima.cpp | 5760 ++++++++++++++++++++++ riscv/src/internal/vm_riscv.in.cpp | 682 +++ riscv/src/iss/minrv_ima.cpp | 147 + riscv/src/main.cpp | 103 + riscv/src/minres_rv.core_desc | 38 + sc-components | 1 + 41 files changed, 10842 insertions(+) create mode 100644 .cproject create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 .project create mode 100644 CMakeLists.txt create mode 100644 LICENSE create mode 100644 README.md create mode 100644 cmake/Common.cmake create mode 100644 cmake/DoxygenTarget.cmake create mode 100644 cmake/FindSystemC.cmake create mode 100644 cmake/GetGitRevisionDescription.cmake create mode 100644 cmake/GetGitRevisionDescription.cmake.in create mode 100644 cmake/PackageConfigurator.cmake create mode 100644 cmake/Submodules.cmake create mode 160000 dbt-core create mode 100644 external/CMakeLists.txt create mode 160000 external/easyloggingpp create mode 160000 external/elfio create mode 160000 external/libGIS create mode 100644 riscv/.gitignore create mode 100644 riscv/.project create mode 100644 riscv/.settings/.gitignore create mode 100644 riscv/CMakeLists.txt create mode 100644 riscv/incl/cli_options.h create mode 100644 riscv/incl/iss/arch/minrv_ima.h create mode 100644 riscv/incl/iss/arch/riscv_core.h create mode 100644 riscv/src/CMakeLists.txt create mode 100644 riscv/src/RV32A.core_desc create mode 100644 riscv/src/RV32C.core_desc create mode 100644 riscv/src/RV32F.core_desc create mode 100644 riscv/src/RV32IBase.core_desc create mode 100644 riscv/src/RV32M.core_desc create mode 100644 riscv/src/RV64A.core_desc create mode 100644 riscv/src/RV64IBase.core_desc create mode 100644 riscv/src/RV64M.core_desc create mode 100644 riscv/src/internal/vm_minrv_ima.cpp create mode 100644 riscv/src/internal/vm_riscv.in.cpp create mode 100644 riscv/src/iss/minrv_ima.cpp create mode 100644 riscv/src/main.cpp create mode 100644 riscv/src/minres_rv.core_desc create mode 160000 sc-components diff --git a/.cproject b/.cproject new file mode 100644 index 0000000..5c92890 --- /dev/null +++ b/.cproject @@ -0,0 +1,546 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + make + + all VERBOSE=1 + true + true + true + + + make + + clean + true + true + true + + + make + + all + true + true + true + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..70c3057 --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +.DS_Store +/*.il +/avr-instr.html +/blink.S +/flash.* +/avr-gdb.cmd +/main.cpp +/Debug/ +/Reelease/ +/core +/*.launch +/*.csv +/Release/ +/*.vcd +/*.ods +/build/ +/*.logs +language.settings.xml +/*.gtkw +/Debug wo LLVM/ +/atmega.txdb +/atmega.txlgz +/atmega.txlog +/.??*bdb.d.0 +/.??*bdb.i.0 +/.??*bdb.t +/tmp/ +/test1.elf +/logs/ +/*.log +/.gdbinit +/*.out diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..f828775 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,15 @@ +[submodule "dbt-core"] + path = dbt-core + url = https://minres.com/git/SystemC/DBT-Core.git +[submodule "sc-components"] + path = sc-components + url = https://minres.com/git/SystemC/SystemC-Components.git +[submodule "external/easyloggingpp"] + path = external/easyloggingpp + url = https://github.com/muflihun/easyloggingpp.git +[submodule "external/elfio"] + path = external/elfio + url = http://git.code.sf.net/p/elfio/code +[submodule "external/libGIS"] + path = external/libGIS + url = https://github.com/vsergeev/libGIS.git diff --git a/.project b/.project new file mode 100644 index 0000000..3e68573 --- /dev/null +++ b/.project @@ -0,0 +1,27 @@ + + + dbt-riscv + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..af30b57 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 2.8.12) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) + +### set the directory names of the submodules +set(GIT_SUBMODULES elfio libGIS sc-components) +set(GIT_SUBMODULE_DIR_sc-components .) +set(GIT_SUBMODULE_DIR_dbt-core .) +### set each submodules's commit or tag that is to be checked out +### (leave empty if you want master) +#set(GIT_SUBMODULE_VERSION_sc-comp 3af6b9836589b082c19d9131c5d0b7afa8ddd7cd) + +include(GNUInstallDirs) +include(cmake/Submodules.cmake) + +#enable_testing() + +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + set(warnings "-Wall -Wextra -Werror") + set(CMAKE_CXX_FLAG_RELEASE "-O2 -DNDEBUG") + set(CMAKE_C_FLAG_RELEASE "-O2 -DNDEBUG") + set(CMAKE_CXX_FLAG_DEBUG "-Og") + set(CMAKE_C_FLAG_DEBUG "-Og") +elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + set(warnings "/W4 /WX /EHsc") +endif() + +FIND_PACKAGE(Threads) + +add_subdirectory(external) +add_subdirectory(dbt-core) +add_subdirectory(sc-components) +add_subdirectory(riscv) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..086dfce --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2016, 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: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* 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. + +* 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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2e51ee3 --- /dev/null +++ b/README.md @@ -0,0 +1,42 @@ +# JIT-ISS +A versatile Just-in-time (JIT) compiling instruction set simulator (ISS) + +**JIT-ISS README** + +This is currently a proof of concept and work in progress, so use at your own risk. It is currently set-up as an Eclipse CDT project and based on LLVM. To build it you need latest LLVM and Eclipse CDT version 4.6 aka Neon. + +To build with SystemC the define WITH_SYSTEMC needs to be set. Then a simple proof-of-concept system is created. Mainly missing are platform peripherals and interrupt handling. It reaches about 5 MIPS in lock-step mode on a MacBook Pro (Core i7-4870HQ@2.5GHz) running in a Docker container. + +JIT-ISS uses libGIS (https://github.com/vsergeev/libGIS) as well as ELFIO (http://elfio.sourceforge.net/), both under MIT license + +**What's missing** + +* only AVR instruction set implemented but not verified + +**Planned features** + +* add platform peripherals + * timers + * gpio + * ext interrupt registers and functionality +* and more + +**Quick start** + +* you need to have a decent compiler, make and cmake installed +* install LLVM 3.9 or 4.0 according to http://apt.llvm.org/ +* download and install SystemC from http://accellera.org/downloads/standards/systemc + * optionally download and install SystemC Verification Library (SCV) from Accelera into the same location +* checkout source from git +* start an out-of-source build like so (e.g. when using LLVM 3.9 and bash) +``` + cd JIT-ISS + mkdir build + cd build + LLVM_HOME=/usr/lib/llvm-3.9 cmake .. + make +``` +* if the SystemC installation is not to be found be cmake you can optionally specify the location by either setting the following environment variables pointing to the installation + - SYSTEMC_HOME + - SYSTEMC_PREFIX + \ No newline at end of file diff --git a/cmake/Common.cmake b/cmake/Common.cmake new file mode 100644 index 0000000..673ec59 --- /dev/null +++ b/cmake/Common.cmake @@ -0,0 +1,20 @@ +# Function to link between sub-projects +function(add_dependent_subproject subproject_name) + #if (NOT TARGET ${subproject_name}) # target unknown + if(NOT PROJECT_${subproject_name}) # var unknown because we build only this subproject + find_package(${subproject_name} CONFIG REQUIRED) + else () # we know the target thus we are doing a build from the top directory + include_directories(../${subproject_name}/incl) + endif () +endfunction(add_dependent_subproject) + +# Make sure we tell the topdir CMakeLists that we exist (if build from topdir) +get_directory_property(hasParent PARENT_DIRECTORY) +if(hasParent) + set(PROJECT_${PROJECT_NAME} true PARENT_SCOPE) +endif() + +# Function to link between sub-projects +function(add_dependent_header subproject_name) + include_directories(../${subproject_name}/incl) +endfunction(add_dependent_header) diff --git a/cmake/DoxygenTarget.cmake b/cmake/DoxygenTarget.cmake new file mode 100644 index 0000000..49d5dd4 --- /dev/null +++ b/cmake/DoxygenTarget.cmake @@ -0,0 +1,24 @@ +function(PrepareDocTarget) + + # Configure the doxygen config file with current settings: + configure_file(documentation-config.doxygen.in ${CMAKE_CURRENT_BINARY_DIR}/documentation-config.doxygen @ONLY) + + # Set the name of the target : "doc" if it doesn't already exist and "doc" if it does. + # This way we make sure to have a single "doc" target. Either it is the one of the top directory or + # it is the one of the subproject that we are compiling alone. + set(DOC_TARGET_NAME "doc") + if(TARGET doc) + set(DOC_TARGET_NAME "doc${PROJECT_NAME}") + endif() + + add_custom_target(${DOC_TARGET_NAME} ${TARGET_ALL} + ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/documentation-config.doxygen + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating API documentation using doxygen for ${PROJECT_NAME}" VERBATIM) + + set(INSTALL_DOC_DIR ${CMAKE_BINARY_DIR}/doc/${PROJECT_NAME}/html) + file(MAKE_DIRECTORY ${INSTALL_DOC_DIR}) # needed for install + + install(DIRECTORY ${INSTALL_DOC_DIR} DESTINATION share/${PROJECT_NAME}-${VERSION_MAJOR} COMPONENT doc) + +endfunction() \ No newline at end of file diff --git a/cmake/FindSystemC.cmake b/cmake/FindSystemC.cmake new file mode 100644 index 0000000..5f55a7c --- /dev/null +++ b/cmake/FindSystemC.cmake @@ -0,0 +1,91 @@ +SET(_SYSTEMC_HINTS + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\SystemC\\2.2;SystemcHome]/include" + ${SYSTEMC_PREFIX}/include + ${SYSTEMC_PREFIX}/lib + ${SYSTEMC_PREFIX}/lib-linux + ${SYSTEMC_PREFIX}/lib-linux64 + ${SYSTEMC_PREFIX}/lib-macos + $ENV{SYSTEMC_PREFIX}/include + $ENV{SYSTEMC_PREFIX}/lib + $ENV{SYSTEMC_PREFIX}/lib-linux + $ENV{SYSTEMC_PREFIX}/lib-linux64 + $ENV{SYSTEMC_PREFIX}/lib-macos + $ENV{SYSTEMC_HOME}/include + $ENV{SYSTEMC_HOME}/lib + $ENV{SYSTEMC_HOME}/lib-linux + $ENV{SYSTEMC_HOME}/lib-linux64 + $ENV{SYSTEMC_HOME}/lib-macos + ${CMAKE_INSTALL_PREFIX}/include + ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/lib-linux + ${CMAKE_INSTALL_PREFIX}/lib-linux64 + ${CMAKE_INSTALL_PREFIX}/lib-macos + ) +SET(_SYSTEMC_PATHS + /usr/include/systemc + /usr/lib + /usr/lib-linux + /usr/lib-linux64 + /usr/lib-macos + /usr/local/include/sysc + /usr/local/lib + /usr/local/lib-linux + /usr/local/lib-linux64 + /usr/local/lib-macos + ) +FIND_FILE(_SYSTEMC_HEADER_FILE + NAMES systemc + HINTS ${_SYSTEMC_HINTS} + PATHS ${_SYSTEMC_PATHS} + PATH_SUFFIXES sysc/kernel +) + +FIND_FILE(_SCV_HEADER_FILE + NAMES scv.h + HINTS ${_SYSTEMC_HINTS} + PATHS ${_SYSTEMC_PATHS} + PATH_SUFFIXES sysc/kernel +) + +if(NOT _SYSTEMC_HEADER_FILE STREQUAL _SYSTEMC_HEADER_FILE-NOTFOUND) + set(SystemC_FOUND TRUE) +endif(NOT _SYSTEMC_HEADER_FILE STREQUAL _SYSTEMC_HEADER_FILE-NOTFOUND) + +if(NOT _SCV_HEADER_FILE STREQUAL _SCV_HEADER_FILE-NOTFOUND) + set(SCV_FOUND TRUE) +endif(NOT _SCV_HEADER_FILE STREQUAL _SCV_HEADER_FILE-NOTFOUND) + +FIND_PATH(SystemC_INCLUDE_DIRS + NAMES systemc.h + HINTS ${_SYSTEMC_HINTS} + PATHS ${_SYSTEMC_PATHS} +) + +FIND_PATH(SystemC_LIBRARY_DIR + NAMES libsystemc.a + HINTS ${_SYSTEMC_HINTS} + PATHS ${_SYSTEMC_PATHS} +) + +FIND_PATH(SCV_INCLUDE_DIRS + NAMES scv.h + HINTS ${_SYSTEMC_HINTS} + PATHS ${_SYSTEMC_PATHS} +) + +FIND_PATH(SCV_LIBRARY_DIRS + NAMES libscv.a + HINTS ${_SYSTEMC_HINTS} + PATHS ${_SYSTEMC_PATHS} +) + +if(SystemC_FOUND) + set(SystemC_LIBRARIES systemc) + message(STATUS "SystemC header files are taken from ${SystemC_INCLUDE_DIRS}") + message(STATUS "SystemC library is taken from ${SystemC_LIBRARY_DIR}") + if(SCV_FOUND) + set(SCV_LIBRARIES scv) + message(STATUS "SCV header files are taken from ${SCV_INCLUDE_DIRS}") + message(STATUS "SCV library is taken from ${SCV_LIBRARY_DIRS}") + endif(SCV_FOUND) +endif(SystemC_FOUND) diff --git a/cmake/GetGitRevisionDescription.cmake b/cmake/GetGitRevisionDescription.cmake new file mode 100644 index 0000000..bcd1d72 --- /dev/null +++ b/cmake/GetGitRevisionDescription.cmake @@ -0,0 +1,130 @@ +# - Returns a version string from Git +# +# These functions force a re-configure on each git commit so that you can +# trust the values of the variables in your build system. +# +# get_git_head_revision( [ ...]) +# +# Returns the refspec and sha hash of the current head revision +# +# git_describe( [ ...]) +# +# Returns the results of git describe on the source tree, and adjusting +# the output so that it tests false if an error occurs. +# +# git_get_exact_tag( [ ...]) +# +# Returns the results of git describe --exact-match on the source tree, +# and adjusting the output so that it tests false if there was no exact +# matching tag. +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +if(__get_git_revision_description) + return() +endif() +set(__get_git_revision_description YES) + +# We must run the following at "include" time, not at function call time, +# to find the path to this module rather than the path to a calling list file +get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) + +function(get_git_head_revision _refspecvar _hashvar) + set(GIT_PARENT_DIR "${CMAKE_CURRENT_LIST_DIR}") + set(GIT_DIR "${GIT_PARENT_DIR}/.git") + while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories + set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}") + get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH) + if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT) + # We have reached the root directory, we are not in git + set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE) + set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE) + return() + endif() + set(GIT_DIR "${GIT_PARENT_DIR}/.git") + endwhile() + # check if this is a submodule + if(NOT IS_DIRECTORY ${GIT_DIR}) + file(READ ${GIT_DIR} submodule) + string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule}) + get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH) + get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE) + endif() + set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") + if(NOT EXISTS "${GIT_DATA}") + file(MAKE_DIRECTORY "${GIT_DATA}") + endif() + + if(NOT EXISTS "${GIT_DIR}/HEAD") + return() + endif() + set(HEAD_FILE "${GIT_DATA}/HEAD") + configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY) + + configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" + "${GIT_DATA}/grabRef.cmake" + @ONLY) + include("${GIT_DATA}/grabRef.cmake") + + set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE) + set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE) +endfunction() + +function(git_describe _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + get_git_head_revision(refspec hash) + if(NOT GIT_FOUND) + set(${_var} "GIT-NOTFOUND" PARENT_SCOPE) + return() + endif() + if(NOT hash) + set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) + return() + endif() + + # TODO sanitize + #if((${ARGN}" MATCHES "&&") OR + # (ARGN MATCHES "||") OR + # (ARGN MATCHES "\\;")) + # message("Please report the following error to the project!") + # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") + #endif() + + #message(STATUS "Arguments to execute_process: ${ARGN}") + + execute_process(COMMAND + "${GIT_EXECUTABLE}" + describe + ${hash} + ${ARGN} + WORKING_DIRECTORY + "${CMAKE_SOURCE_DIR}" + RESULT_VARIABLE + res + OUTPUT_VARIABLE + out + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT res EQUAL 0) + set(out "${out}-${res}-NOTFOUND") + endif() + + set(${_var} "${out}" PARENT_SCOPE) +endfunction() + +function(git_get_exact_tag _var) + git_describe(out --exact-match ${ARGN}) + set(${_var} "${out}" PARENT_SCOPE) +endfunction() diff --git a/cmake/GetGitRevisionDescription.cmake.in b/cmake/GetGitRevisionDescription.cmake.in new file mode 100644 index 0000000..6d8b708 --- /dev/null +++ b/cmake/GetGitRevisionDescription.cmake.in @@ -0,0 +1,41 @@ +# +# Internal file for GetGitRevisionDescription.cmake +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +set(HEAD_HASH) + +file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) + +string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) +if(HEAD_CONTENTS MATCHES "ref") + # named branch + string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") + if(EXISTS "@GIT_DIR@/${HEAD_REF}") + configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) + else() + configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY) + file(READ "@GIT_DATA@/packed-refs" PACKED_REFS) + if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}") + set(HEAD_HASH "${CMAKE_MATCH_1}") + endif() + endif() +else() + # detached HEAD + configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) +endif() + +if(NOT HEAD_HASH) + file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) + string(STRIP "${HEAD_HASH}" HEAD_HASH) +endif() diff --git a/cmake/PackageConfigurator.cmake b/cmake/PackageConfigurator.cmake new file mode 100644 index 0000000..b67615d --- /dev/null +++ b/cmake/PackageConfigurator.cmake @@ -0,0 +1,44 @@ +# Create package-config files : +# - ConfigVersion.cmake +# - Config.cmake +# They are installed in lib/cmake/. +# +# Required variables : +# - VERSION +# - PROJECT_NAME +# + +# Include needed for 'write_basic_package_version_file' +include(CMakePackageConfigHelpers) + +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}ConfigVersion.cmake" + VERSION ${VERSION} + COMPATIBILITY AnyNewerVersion +) + +configure_file(cmake/${PROJECT_NAME}Config.cmake + "${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}Config.cmake" + COPYONLY +) + +# Destination +set(config_install_dir lib/cmake/${PROJECT_NAME}) + +# Config installation +# * /lib/cmake//Targets.cmake +install( + EXPORT ${PROJECT_NAME}Targets + DESTINATION ${config_install_dir} +) + +# Config installation +# * /lib/cmake//Config.cmake +# * /lib/cmake//ConfigVersion.cmake +install( + FILES + cmake/${PROJECT_NAME}Config.cmake + "${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}ConfigVersion.cmake" + DESTINATION ${config_install_dir} + COMPONENT devel +) \ No newline at end of file diff --git a/cmake/Submodules.cmake b/cmake/Submodules.cmake new file mode 100644 index 0000000..f2612b8 --- /dev/null +++ b/cmake/Submodules.cmake @@ -0,0 +1,53 @@ +if(EXISTS "${PROJECT_SOURCE_DIR}/.gitmodules") +message(STATUS "Updating submodules to their latest/fixed versions") +message(STATUS "(this can take a while, please be patient)") + +### First, get all submodules in +if(${GIT_SUBMODULES_CHECKOUT_QUIET}) + execute_process( + COMMAND git submodule update --init --recursive + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + OUTPUT_QUIET + ERROR_QUIET + ) +else() + execute_process( + COMMAND git submodule update --init --recursive + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + ) +endif() + +### Then, checkout each submodule to the specified commit +# Note: Execute separate processes here, to make sure each one is run, +# should one crash (because of branch not existing, this, that ... whatever) +foreach(GIT_SUBMODULE ${GIT_SUBMODULES}) + + if( "${GIT_SUBMODULE_VERSION_${GIT_SUBMODULE}}" STREQUAL "" ) + message(STATUS "no specific version given for submodule ${GIT_SUBMODULE}, checking out master") + set(GIT_SUBMODULE_VERSION_${GIT_SUBMODULE} "master") + endif() + + if( "${GIT_SUBMODULE_DIR_${GIT_SUBMODULE}}" STREQUAL "" ) + set(GIT_SUBMODULES_DIRECTORY external) + else() + set(GIT_SUBMODULES_DIRECTORY ${GIT_SUBMODULE_DIR_${GIT_SUBMODULE}}) + endif() + + if(${GIT_SUBMODULES_CHECKOUT_QUIET}) + execute_process( + COMMAND git checkout ${GIT_SUBMODULE_VERSION_${GIT_SUBMODULE}} + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/${GIT_SUBMODULES_DIRECTORY}/${GIT_SUBMODULE} + OUTPUT_QUIET + ERROR_QUIET + ) + else() + message(STATUS "checking out ${GIT_SUBMODULE}'s commit/tag ${GIT_SUBMODULE_VERSION_${GIT_SUBMODULE}}") + execute_process( + COMMAND git checkout ${GIT_SUBMODULE_VERSION_${GIT_SUBMODULE}} + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/${GIT_SUBMODULES_DIRECTORY}/${GIT_SUBMODULE} + ) + endif() + +endforeach(${GIT_SUBMODULE}) + +endif() diff --git a/dbt-core b/dbt-core new file mode 160000 index 0000000..8bdb487 --- /dev/null +++ b/dbt-core @@ -0,0 +1 @@ +Subproject commit 8bdb487d2e635db487c81ad745f49edf871369d3 diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt new file mode 100644 index 0000000..a27d214 --- /dev/null +++ b/external/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 2.8) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) +set(CMAKE_CXX_STANDARD 14) + +# Set the name of your project here +project("external") + +include(Common) + + +include_directories( ${PROJECT_SOURCE_DIR}/external/libGIS ${PROJECT_SOURCE_DIR}/external/easyloggingpp/src ) + +FILE(GLOB ElfioHeaders elfio *.hpp) +FILE(GLOB GISHeaders libGis *.h) +FILE(GLOB LogHeaders easyloggingpp/src *.h) + +set(LIB_HEADERS ${ElfioHeaders} ${GISHeaders} ${LogHeaders}) +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. +set(LIBRARY_NAME external) + +# Define the library +add_library(${LIBRARY_NAME} ${LIB_SOURCES}) + + diff --git a/external/easyloggingpp b/external/easyloggingpp new file mode 160000 index 0000000..850ea2a --- /dev/null +++ b/external/easyloggingpp @@ -0,0 +1 @@ +Subproject commit 850ea2a9f151ed648a989dda1cf44e503e45831f diff --git a/external/elfio b/external/elfio new file mode 160000 index 0000000..fbf8eaf --- /dev/null +++ b/external/elfio @@ -0,0 +1 @@ +Subproject commit fbf8eafc2dab3ac441bc5221d967e23a2e6fdc46 diff --git a/external/libGIS b/external/libGIS new file mode 160000 index 0000000..f82b9dd --- /dev/null +++ b/external/libGIS @@ -0,0 +1 @@ +Subproject commit f82b9dd3018d479230ad68a02da41fa95cad9123 diff --git a/riscv/.gitignore b/riscv/.gitignore new file mode 100644 index 0000000..b34c537 --- /dev/null +++ b/riscv/.gitignore @@ -0,0 +1 @@ +/src-gen/ diff --git a/riscv/.project b/riscv/.project new file mode 100644 index 0000000..e0318a8 --- /dev/null +++ b/riscv/.project @@ -0,0 +1,17 @@ + + + riscv + + + + + + org.eclipse.xtext.ui.shared.xtextBuilder + + + + + + org.eclipse.xtext.ui.shared.xtextNature + + diff --git a/riscv/.settings/.gitignore b/riscv/.settings/.gitignore new file mode 100644 index 0000000..c2e16bb --- /dev/null +++ b/riscv/.settings/.gitignore @@ -0,0 +1 @@ +/com.minres.coredsl.CoreDsl.prefs diff --git a/riscv/CMakeLists.txt b/riscv/CMakeLists.txt new file mode 100644 index 0000000..f311c99 --- /dev/null +++ b/riscv/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") + +# 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}/../external/easyloggingpp/src + ${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/incl/cli_options.h b/riscv/incl/cli_options.h new file mode 100644 index 0000000..78e3d0a --- /dev/null +++ b/riscv/incl/cli_options.h @@ -0,0 +1,168 @@ +/******************************************************************************* + * 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 + +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(el::Configurations& conf, int level){ + switch(level){ + case 0: + conf.set(el::Level::Fatal, el::ConfigurationType::Enabled, "false"); + /* no break */ + case 1: + conf.set(el::Level::Error, el::ConfigurationType::Enabled, "false"); + /* no break */ + case 2: + conf.set(el::Level::Warning, el::ConfigurationType::Enabled, "false"); + /* no break */ + case 3: + conf.set(el::Level::Info, el::ConfigurationType::Enabled, "false"); + /* no break */ + case 4: + conf.set(el::Level::Debug, el::ConfigurationType::Enabled, "false"); + /* no break */ + case 5: + conf.set(el::Level::Trace, el::ConfigurationType::Enabled, "false"); + /* 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(defaultConf, vm["verbose"].as()); + if(vm.count("log-file")) + defaultConf.set(el::Level::Global,el::ConfigurationType::Filename, vm["log-file"].as()); + // 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"); + try { + po::store(po::parse_command_line(argc, argv, desc), vm); // can throw + // --help option + if ( vm.count("help") ){ + std::cout << "JIT-ISS simulator for AVR" << 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/incl/iss/arch/minrv_ima.h b/riscv/incl/iss/arch/minrv_ima.h new file mode 100644 index 0000000..7657800 --- /dev/null +++ b/riscv/incl/iss/arch/minrv_ima.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. + * + * Contributors: + * eyck@minres.com - initial API and implementation + ******************************************************************************/ + +#ifndef _MINRV_IMA_H_ +#define _MINRV_IMA_H_ + +#include +#include +#include + +namespace iss { +namespace arch { + +struct minrv_ima; + +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 MinRV_IMA_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 MinRV_IMA_reg_size[r]; + } + + constexpr static unsigned reg_byte_offset(unsigned r) { + const uint32_t MinRV_IMA_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 MinRV_IMA_reg_byte_offset[r]; + } + + enum sreg_flag_e {FLAGS}; + + enum mem_type_e {MEM,CSR,FENCE,RES}; + +}; + +struct minrv_ima: 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; + + minrv_ima(); + ~minrv_ima(); + + void reset(uint64_t address=0); + +// virtual void loadFile(std::string name, int type=-1); + + uint8_t* get_regs_base_ptr() override; + + void get_reg(short idx, std::vector& value) override; + void set_reg(short idx, const std::vector& value) override; + + bool get_flag(int flag) override; + void set_flag(int, bool value) override; + + void update_flags(operations op, uint64_t opr1, uint64_t opr2) override; + + void notify_phase(exec_phase phase){ + if(phase==ISTART){ + ++reg.icount; + reg.PC=reg.NEXT_PC; + } + } + + 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 MinRV_IMA_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 /* _MINRV_IMA_H_ */ diff --git a/riscv/incl/iss/arch/riscv_core.h b/riscv/incl/iss/arch/riscv_core.h new file mode 100644 index 0000000..459a145 --- /dev/null +++ b/riscv/incl/iss/arch/riscv_core.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 + +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 +}; + +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" +}; + +namespace { +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_core: public BASE { + using super = BASE; + using this_class = riscv_core; + 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_core(); + virtual ~riscv_core(); + + 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_core::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; + auto status = csr[mstatus]; + 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; + 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_core::riscv_core() { + 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_core::read_cycle; + csr_rd_cb[mcycleh]=&riscv_core::read_cycle; + csr_rd_cb[minstret]=&riscv_core::read_cycle; + csr_rd_cb[minstreth]=&riscv_core::read_cycle; + csr_rd_cb[mstatus]=&riscv_core::read_status; + csr_wr_cb[mstatus]=&riscv_core::write_status; + csr_rd_cb[sstatus]=&riscv_core::read_status; + csr_wr_cb[sstatus]=&riscv_core::write_status; + csr_rd_cb[ustatus]=&riscv_core::read_status; + csr_wr_cb[ustatus]=&riscv_core::write_status; + csr_rd_cb[mip]=&riscv_core::read_ip; + csr_wr_cb[mip]=&riscv_core::write_ip; + csr_rd_cb[sip]=&riscv_core::read_ip; + csr_wr_cb[sip]=&riscv_core::write_ip; + csr_rd_cb[uip]=&riscv_core::read_ip; + csr_wr_cb[uip]=&riscv_core::write_ip; + csr_rd_cb[mie]=&riscv_core::read_ie; + csr_wr_cb[mie]=&riscv_core::write_ie; + csr_rd_cb[sie]=&riscv_core::read_ie; + csr_wr_cb[sie]=&riscv_core::write_ie; + csr_rd_cb[uie]=&riscv_core::read_ie; + csr_wr_cb[uie]=&riscv_core::write_ie; + csr_rd_cb[satp]=&riscv_core::read_satp; + csr_wr_cb[satp]=&riscv_core::write_satp; +} + +template +riscv_core::~riscv_core() { +} + +template +void riscv_core::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_core::read(const iss::addr_t& addr, unsigned length, uint8_t* const data){ +#ifndef NDEBUG + if(addr.type& iss::DEBUG){ + LOG(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_core::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(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_core::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_core::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_core::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_core::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_core::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_core::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_core::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_core::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_core::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_core::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_core::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_core::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_core::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: + (hostvar!=0x1?LOG(FATAL):LOG(INFO))<<"tohost value is 0x"<(hostvar & 0xff); + if(c=='\n' || c==0){ + LOG(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_core::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_core::phys_addr_t riscv_core::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 reg_t mstatus_r = csr[mstatus]; + 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, csr[satp]); + + 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_core::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); + if(trap_id) + el::Loggers::getLogger("disass", true)->info("Interrupt %v with cause '%v' at address %v occurred, changing privilege level from %v to %v", + trap_id, irq_str[cause], buffer , lvl[cur_priv], lvl[new_priv]); + else + el::Loggers::getLogger("disass", true)->info("Trap %v with cause '%v' at address %v occurred, changing privilege level from %v to %v", + trap_id, trap_str[cause], buffer , lvl[cur_priv], lvl[new_priv]); + return this->reg.NEXT_PC; +} + +template +uint64_t riscv_core::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; + el::Loggers::getLogger("disass", true)->info("Executing xRET , changing privilege level from %v to %v", + lvl[cur_priv], lvl[ppl]); + return this->reg.NEXT_PC; +} + +template +void riscv_core::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/src/CMakeLists.txt b/riscv/src/CMakeLists.txt new file mode 100644 index 0000000..3e28610 --- /dev/null +++ b/riscv/src/CMakeLists.txt @@ -0,0 +1,56 @@ +# library files +FILE(GLOB RiscVHeaders *.h) +set(LIB_HEADERS ${RiscVHeaders} ) +set(LIB_SOURCES + iss/minrv_ima.cpp + internal/vm_minrv_ima.cpp +) + +set(APP_HEADERS ) + +set(APP_SOURCES main.cpp) + +# Define two variables in order not to repeat ourselves. +set(LIBRARY_NAME riscv) + +# 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} ${llvm_libs}) +#target_link_libraries(${APPLICATION_NAME} ${SystemC_LIBRARIES} ) +#if(SCV_FOUND) + #target_link_libraries (${APPLICATION_NAME} ${SCV_LIBRARIES}) +#endif(SCV_FOUND) +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/src/RV32A.core_desc b/riscv/src/RV32A.core_desc new file mode 100644 index 0000000..67e0c89 --- /dev/null +++ b/riscv/src/RV32A.core_desc @@ -0,0 +1,108 @@ +import "RV32IBase.core_desc" + +InsructionSet RV32A extends RV32IBase{ + + address_spaces { + RES[8] + } + + instructions{ + LR.W { + encoding: b00010 | aq[0:0] | rl[0:0] | b00000 | rs1[4:0] | b010 | rd[4:0] | b0101111; + args_disass: "x%rd$d, x%rs1$d"; + if(rd!=0){ + val offs[XLEN] <= X[rs1]; + X[rd]<= sext(MEM[offs]{32}, XLEN); + RES[offs]{32}<=sext(-1, 32); + } + } + SC.W { + encoding: b00011 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b0101111; + args_disass: "x%rd$d, x%rs1$d, x%rs2$d"; + val offs[XLEN] <= X[rs1]; + val res1[32] <= RES[offs]{32}; + if(res1!=0) + MEM[offs]{32} <= X[rs2]; + if(rd!=0) X[rd]<= choose(res1!=0, 0, 1); + } + AMOSWAP.W{ + encoding: b00001 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b0101111; + args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%aq$d,rel=%rl$d)"; + val offs[XLEN]<=X[rs1]; + if(rd!=0) X[rd]<=sext(MEM[offs]{32}); + MEM[offs]{32}<=X[rs2]; + } + AMOADD.W{ + encoding: b00000 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b0101111; + args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%aq$d,rel=%rl$d)"; + val offs[XLEN]<=X[rs1]; + val res1[XLEN] <= sext(MEM[offs]{32}); + if(rd!=0) X[rd]<=res1; + val res2[XLEN]<=res1 + X[rs2]; + MEM[offs]{32}<=res2; + } + AMOXOR.W{ + encoding: b00100 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b0101111; + args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%aq$d,rel=%rl$d)"; + val offs[XLEN]<=X[rs1]; + val res1[XLEN] <= sext(MEM[offs]{32}); + if(rd!=0) X[rd]<=res1; + val res2[XLEN]<=res1 ^ X[rs2]; + MEM[offs]{32}<=res2; + } + AMOAND.W{ + encoding: b01100 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b0101111; + args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%aq$d,rel=%rl$d)"; + val offs[XLEN]<=X[rs1]; + val res1[XLEN] <= sext(MEM[offs]{32}); + if(rd!=0) X[rd]<=res1; + val res2[XLEN] <=res1 & X[rs2]; + MEM[offs]{32}<=res2; + } + AMOOR.W { + encoding: b01000 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b0101111; + args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%aq$d,rel=%rl$d)"; + val offs[XLEN]<=X[rs1]; + val res1[XLEN] <= sext(MEM[offs]{32}); + if(rd!=0) X[rd]<=res1; + val res2[XLEN]<=res1 | X[rs2]; + MEM[offs]{32}<=res2; + } + AMOMIN.W{ + encoding: b10000 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b0101111; + args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%aq$d,rel=%rl$d)"; + val offs[XLEN]<=X[rs1]; + val res1[XLEN] <= sext(MEM[offs]{32}); + if(rd!=0) X[rd]<=res1; + val res2[XLEN]<= choose(res1's>X[rs2]s, X[rs2], res1); + MEM[offs]{32}<=res2; + } + AMOMAX.W{ + encoding: b10100 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b0101111; + args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%aq$d,rel=%rl$d)"; + val offs[XLEN]<=X[rs1]; + val res1[XLEN] <= sext(MEM[offs]{32}); + if(rd!=0) X[rd]<=res1; + val res2[XLEN]<= choose(res1'sX[rs2], X[rs2], res1); + MEM[offs]{32}<=res2; + } + AMOMAXU.W{ + encoding: b11100 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b0101111; + args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%aq$d,rel=%rl$d)"; + val offs[XLEN]<=X[rs1]; + val res1[XLEN] <= zext(MEM[offs]{32}); + if(rd!=0) X[rd]<=res1; + val res2[XLEN]<= choose(res1'u 31) raise(0, 2); + val rs1_idx[5] <= rs1+8; + X[rs1_idx] <= shrl(X[rs1_idx], shamt); + } + C.SRAI {//(RV32) + encoding:b100 | shamt[5:5] | b01 | rs1[2:0] | shamt[4:0] | b01; + args_disass: "x(8+%rs1$d), %shamt$d"; + if(shamt > 31) raise(0, 2); + val rs1_idx[5] <= rs1+8; + X[rs1_idx] <= shra(X[rs1_idx], shamt); + } + C.ANDI {//(RV32) + encoding:b100 | imm[5:5]s | b10 | rs1[2:0] | imm[4:0]s | b01; + args_disass: "x(8+%rs1$d), 0x%imm$05x"; + val rs1_idx[5] <= rs1 + 8; + X[rs1_idx] <= X[rs1_idx] & imm; + } + C.SUB {//(RV32) + encoding:b100 | b0 | b11 | rd[2:0] | b00 | rs2[2:0] | b01; + args_disass: "x(8+%rd$d), x(8+%rs2$d)"; + val rd_idx[5] <= rd + 8; + val rs2_idx[5] <= rs2 + 8; + X[rd_idx] <= X[rd_idx] - X[rs2_idx]; + } + C.XOR {//(RV32) + encoding:b100 | b0 | b11 | rd[2:0] | b01 | rs2[2:0] | b01; + args_disass: "x(8+%rd$d), x(8+%rs2$d)"; + val rd_idx[5] <= rd + 8; + val rs2_idx[5] <= rs2 + 8; + X[rd_idx] <= X[rd_idx] ^ X[rs2_idx]; + } + C.OR {//(RV32) + encoding:b100 | b0 | b11 | rd[2:0] | b10 | rs2[2:0] | b01; + args_disass: "x(8+%rd$d), x(8+%rs2$d)"; + val rd_idx[5] <= rd + 8; + val rs2_idx[5] <= rs2 + 8; + X[rd_idx] <= X[rd_idx] | X[rs2_idx]; + } + C.AND {//(RV32) + encoding:b100 | b0 | b11 | rd[2:0] | b11 | rs2[2:0] | b01; + args_disass: "x(8+%rd$d), x(8+%rs2$d)"; + val rd_idx[5] <= rd + 8; + val rs2_idx[5] <= rs2 + 8; + X[rd_idx] <= X[rd_idx] & X[rs2_idx]; + } + C.J(no_cont) {//(RV32) + encoding:b101 | imm[11:11]s | imm[4:4]s | imm[9:8]s | imm[10:10]s | imm[6:6]s | imm[7:7]s | imm[3:1]s | imm[5:5]s | b01; + args_disass: "0x%imm$05x"; + PC<=PC+imm; + } + C.BEQZ(no_cont) {//(RV32) + encoding:b110 | imm[8:8]s | imm[4:3]s | rs1d[2:0] | imm[7:6]s |imm[2:1]s | imm[5:5]s | b01; + args_disass: "x(8+%rs1d$d), 0x%imm$05x"; + val rs1[5] <= rs1d+8; + PC<=choose(X[rs1]==0, PC+imm, PC+2); + } + C.BNEZ(no_cont) {//(RV32) + encoding:b111 | imm[8:8] | imm[4:3] | rs1d[2:0] | imm[7:6] | imm[2:1] | imm[5:5] | b01; + args_disass: "x(8+%rs1d$d),, 0x%imm$05x"; + val rs1[5] <= rs1d+8; + PC<=choose(X[rs1]!=0, PC+imm, PC+2); + } + C.SLLI {//(RV32) + encoding:b000 | shamt[5:5] | rs1[4:0] | shamt[4:0] | b10; + args_disass: "x%rs1$d, %shamt$d"; + if(rs1 == 0) raise(0, 2); + if(shamt > 31) raise(0, 2); + X[rs1] <= shll(X[rs1], shamt); + } + C.LQSP {//(RV128) + encoding:b001 | uimm[5:5] | rd[4:0] | uimm[4:4] | uimm[9:6] | b10; + } + C.LWSP {// + encoding:b010 | uimm[5:5] | rd[4:0] | uimm[4:2] | uimm[7:6] | b10; + args_disass: "x%rd$d, sp, 0x%uimm$05x"; + val x2_idx[5] <= 2; + val offs[XLEN] <= X[x2_idx] + uimm; + X[rd] <= MEM[offs]{32}; + } + // order matters as C.JR is a special case of C.JR + C.MV {//(RV32) + encoding:b100 | b0 | rd[4:0] | rs2[4:0] | b10; + args_disass: "x%rd$d, x%rs2$d"; + X[rd] <= X[rs2]; + } + C.JR(no_cont) {//(RV32) + encoding:b100 | b0 | rs1[4:0] | b00000 | b10; + args_disass: "x%rs1$d"; + PC <= X[rs1]; + } + C.EBREAK(no_cont) {//(RV32) + encoding:b100 | b1 | b00000 | b00000 | b10; + raise(0, 3); + } + // order matters as C.JALR is a special case of C.ADD + C.ADD {//(RV32) + encoding:b100 | b1 | rd[4:0] | rs2[4:0] | b10; + args_disass: "x%rd$d, x%rs2$d"; + X[rd] <= X[rd] + X[rs2]; + } + C.JALR(no_cont) {//(RV32) + encoding:b100 | b1 | rs1[4:0] | b00000 | b10; + args_disass: "x%rs1$d"; + val rd[5] <= 1; + X[rd] <= PC+2; + PC<=X[rs1]; + } + C.SWSP {// + encoding:b110 | uimm[5:2] | uimm[7:6] | rs2[4:0] | b10; + args_disass: "x2+0x%uimm$05x, x%rs2$d"; + val x2_idx[5] <= 2; + val offs[XLEN] <= X[x2_idx] + uimm; + MEM[offs]{32} <= X[rs2]; + } + } +} + +InsructionSet RV32CF extends RV32CI { + constants { + XLEN, FLEN + } + address_spaces { + MEM[8] + } + registers { + [31:0] X[XLEN], + [31:0] F[FLEN] + } + instructions{ + C.FLD { //(RV32/64) + encoding: b001 | uimm[5:3] | rs1[2:0] | uimm[7:6] | rd[2:0] | b00; + } + C.FLW {//(RV32) + encoding: b011 | uimm[5:3] | rs1[2:0] | uimm[2:2] | uimm[6:6] | rd[2:0] | b00; + } + C.FSD { //(RV32/64) + encoding: b101 | uimm[5:3] | rs1[2:0] | uimm[7:6] | rs2[2:0] | b00; + } + C.FSW {//(RV32) + encoding: b111 | uimm[5:3] | rs1[2:0] | uimm[2:2] | uimm[6:6] | rs2[2:0] | b00; + } + C.FLDSP {//(RV32/64) + encoding:b001 | uimm[5:5] | rd[4:0] | uimm[4:3] | uimm[8:6] | b10; + } + C.FLWSP {//RV32 + encoding:b011 | uimm[5:5] | rd[4:0] | uimm[4:2] | uimm[7:6] | b10; + } + C.FSDSP {//(RV32/64) + encoding:b101 | uimm[5:3] | uimm[8:6] | rs2[4:0] | b10; + } + C.FSWSP {//(RV32) + encoding:b111 | uimm[5:2] | uimm[7:6] | rs2[4:0] | b10; + } + } +} + +InsructionSet RV64CI extends RV32CI { + constants { + XLEN + } + address_spaces { + MEM[8] + } + registers { + [31:0] X[XLEN], + PC[XLEN](is_pc) + } + instructions{ + C.LD {//(RV64/128) + encoding:b011 | uimm[5:3] | rs1[2:0] | uimm[7:6] | rd[2:0] | b00; + } + C.SD { //(RV64/128) + encoding:b111 | uimm[5:3] | rs1[2:0] | uimm[7:6] | rs2[2:0] | b00; + } + C.SUBW {//(RV64/128, RV32 res) + encoding:b100 | b1 | b11 | rd[2:0] | b00 | rs2[2:0] | b01; + args_disass: "x%rd$d, sp, 0x%imm$05x"; + } + C.ADDW {//(RV64/128 RV32 res) + encoding:b100 | b1 | b11 | rd[2:0] | b01 | rs2[2:0] | b01; + args_disass: "x%rd$d, sp, 0x%imm$05x"; + } + C.ADDIW {//(RV64/128) + encoding:b001 | imm[5:5] | rs1[4:0] | imm[4:0] | b01; + } + C.SRLI64 {//(RV32/64/128) + encoding:b100 | b0 | b00 | rs1[2:0] | b00000 | b01; + } + C.SRAI64 {//(RV32/64/128) + encoding:b100 | b0 | b01 | rs1[2:0] | b00000 | b01; + } + C.SLLI64 {//(RV128 RV32/64) + encoding:b000 | b0 | rs1[4:0] | b00000 | b10; + } + C.LDSP {//(RV64/128 + encoding:b011 | uimm[5:5] | rd[4:0] | uimm[4:3] | uimm[8:6] | b10; + args_disass: "x%rd$d, sp, 0x%imm$05x"; + } + C.SDSP {//(RV64/128) + encoding:b111 | uimm[5:3] | uimm[8:6] | rs2[4:0] | b10; + } + } +} + +InsructionSet RV128CI extends RV64CI { + constants { + XLEN + } + address_spaces { + MEM[8] + } + registers { + [31:0] X[XLEN], + PC[XLEN](is_pc) + } + instructions{ + C.LQ { //(RV128) + encoding:b001 | uimm[5:4] | uimm[8:8] | rs1[2:0] | uimm[7:6] | rd[2:0] | b00; + } + C.SQ { //(RV128) + encoding:b101 | uimm[5:4] | uimm[8:8] | rs1[2:0] | uimm[7:6] | rs2[2:0] | b00; + } + C.SQSP {//(RV128) + encoding:b101 | uimm[5:4] | uimm[9:6] | rs2[4:0] | b10; + } + } +} diff --git a/riscv/src/RV32F.core_desc b/riscv/src/RV32F.core_desc new file mode 100644 index 0000000..6efb8fb --- /dev/null +++ b/riscv/src/RV32F.core_desc @@ -0,0 +1,105 @@ +import "RV32IBase.core_desc" + +InsructionSet RV32F extends RV32IBase{ + constants { + FLEN, fcsr + } + registers { + [31:0] F[FLEN] + } + instructions{ + FLW { + encoding: imm[11:0]s | rs1[4:0] | b010 | rd[4:0] | b0000111; + val offs[XLEN] <= X[rs1]+imm; + F[rd]<=MEM[offs]; + } + FSW { + encoding: imm[11:5]s | rs2[4:0] | rs1[4:0] | b010 | imm[4:0]s | b0100111; + val offs[XLEN] <= X[rs1]+imm; + MEM[offs]<=F[rs2]; + } + FMADD.S { + encoding: rs3[4:0] | b00 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1000011; + F[rd]f<= F[rs1]f * F[rs2]f * F[rs3]f; + } + FMSUB.S { + encoding: rs3[4:0] | b00 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1000111; + F[rd]f<=F[rs1]f * F[rs2]f -F[rs3]f; + } + FNMSUB.S { + encoding: rs3[4:0] | b00 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1001011; + F[rd]f<=-F[rs1]f * F[rs2]f- F[rs3]f; + } + FNMADD.S { + encoding: rs3[4:0] | b00 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1001111; + F[rd]f<=-F[rs1]f*F[rs2]f+F[rs3]f; + } + FADD.S { + encoding: b0000000 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011; + F[rd]f <= F[rs1]f + F[rs2]f; + } + FSUB.S { + encoding: b0000100 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011; + F[rd]f <= F[rs1]f - F[rs2]f; + } + FMUL.S { + encoding: b0001000 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011; + F[rd]f <= F[rs1]f * F[rs2]; + } + FDIV.S { + encoding: b0001100 | rs2[4:0] | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011; + F[rd]f <= F[rs1]f / F[rs2]f; + } + FSQRT.S { + encoding: b0101100 | b00000 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011; + F[rd]f<=sqrt(F[rs1]f); + } + FSGNJ.S { + encoding: b0010000 | rs2[4:0] | rs1[4:0] | b000 | rd[4:0] | b1010011; + } + FSGNJN.S { + encoding: b0010000 | rs2[4:0] | rs1[4:0] | b001 | rd[4:0] | b1010011; + } + FSGNJX.S { + encoding: b0010000 | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b1010011; + } + FMIN.S { + encoding: b0010100 | rs2[4:0] | rs1[4:0] | b000 | rd[4:0] | b1010011; + F[rd]f<= choose(F[rs1]fF[rs2]f, F[rs1]f, F[rs2]f); + } + FCVT.W.S { + encoding: b1100000 | b00000 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011; + } + FCVT.WU.S { + encoding: b1100000 | b00001 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011; + } + FMV.X.W { + encoding: b1110000 | b00000 | rs1[4:0] | b000 | rd[4:0] | b1010011; + } + FEQ.S { + encoding: b1010000 | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b1010011; + } + FLT.S { + encoding: b1010000 | rs2[4:0] | rs1[4:0] | b001 | rd[4:0] | b1010011; + } + FLE.S { + encoding: b1010000 | rs2[4:0] | rs1[4:0] | b000 | rd[4:0] | b1010011; + } + FCLASS.S { + encoding: b1110000 | b00000 | rs1[4:0] | b001 | rd[4:0] | b1010011; + } + FCVT.S.W { + encoding: b1101000 | b00000 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011; + } + FCVT.S.WU { + encoding: b1101000 | b00001 | rs1[4:0] | rm[2:0] | rd[4:0] | b1010011; + } + FMV.W.X { + encoding: b1111000 | b00000 | rs1[4:0] | b000 | rd[4:0] | b1010011; + } + } +} \ No newline at end of file diff --git a/riscv/src/RV32IBase.core_desc b/riscv/src/RV32IBase.core_desc new file mode 100644 index 0000000..9b0d16b --- /dev/null +++ b/riscv/src/RV32IBase.core_desc @@ -0,0 +1,308 @@ +InsructionSet RV32IBase { + constants { + XLEN, + XLEN_BIT_MASK, + PCLEN, + fence, + fencei, + fencevmal, + fencevmau + } + + address_spaces { + MEM[8], CSR[XLEN], FENCE[XLEN] + } + + registers { + [31:0] X[XLEN], + PC[XLEN](is_pc) + } + + instructions { + LUI{ + encoding: imm[31:12]s | rd[4:0] | b0110111; + args_disass: "x%rd$d, 0x%imm$05x"; + if(rd!=0) X[rd] <= imm; + } + AUIPC{ + encoding: imm[31:12]s | rd[4:0] | b0010111; + args_disass: "x%rd%, 0x%imm$08x"; + if(rd!=0) X[rd] <= PC+imm; + } + JAL(no_cont){ + encoding: imm[20:20]s | imm[10:1]s | imm[11:11]s | imm[19:12]s | rd[4:0] | b1101111; + args_disass: "x%rd$d, 0x%imm$x"; + if(rd!=0) X[rd] <= PC+4; + PC<=PC+imm; + } + JALR(no_cont){ + encoding: imm[11:0]s | rs1[4:0] | b000 | rd[4:0] | b1100111; + args_disass: "x%rd$d, x%rs1$d, 0x%imm$x"; + if(rd!=0) X[rd] <= PC+4; + val ret[XLEN] <= X[rs1]+ imm; + PC<=ret& ~0x1; + } + BEQ(no_cont){ + encoding: imm[12:12]s |imm[10:5]s | rs2[4:0] | rs1[4:0] | b000 | imm[4:1]s | imm[11:11]s | b1100011; + args_disass:"x%rs1$d, x%rs2$d, 0x%imm$x"; + PC<=choose(X[rs1]==X[rs2], PC+imm, PC+4); + } + BNE(no_cont){ + encoding: imm[12:12]s |imm[10:5]s | rs2[4:0] | rs1[4:0] | b001 | imm[4:1]s | imm[11:11]s | b1100011; + args_disass:"x%rs1$d, x%rs2$d, 0x%imm$x"; + PC<=choose(X[rs1]!=X[rs2], PC+imm, PC+4); + } + BLT(no_cont){ + encoding: imm[12:12]s |imm[10:5]s | rs2[4:0] | rs1[4:0] | b100 | imm[4:1]s | imm[11:11]s | b1100011; + args_disass:"x%rs1$d, x%rs2$d, 0x%imm$x"; + PC<=choose(X[rs1]s=X[rs2]s, PC+imm, PC+4); + } + BLTU(no_cont) { + encoding: imm[12:12]s |imm[10:5]s | rs2[4:0] | rs1[4:0] | b110 | imm[4:1]s | imm[11:11]s | b1100011; + args_disass:"x%rs1$d, x%rs2$d, 0x%imm$x"; + PC<=choose(X[rs1]=X[rs2], PC+imm, PC+4); + } + LB { + encoding: imm[11:0]s | rs1[4:0] | b000 | rd[4:0] | b0000011; + args_disass:"x%rd$d, %imm%(x%rs1$d)"; + val offs[XLEN] <= X[rs1]+imm; + if(rd!=0) X[rd]<=sext(MEM[offs]); + } + LH { + encoding: imm[11:0]s | rs1[4:0] | b001 | rd[4:0] | b0000011; + args_disass:"x%rd$d, %imm%(x%rs1$d)"; + val offs[XLEN] <= X[rs1]+imm; + if(rd!=0) X[rd]<=sext(MEM[offs]{16}); + } + LW { + encoding: imm[11:0]s | rs1[4:0] | b010 | rd[4:0] | b0000011; + args_disass:"x%rd$d, %imm%(x%rs1$d)"; + val offs[XLEN] <= X[rs1]+imm; + if(rd!=0) X[rd]<=sext(MEM[offs]{32}); + } + LBU { + encoding: imm[11:0]s | rs1[4:0] | b100 | rd[4:0] | b0000011; + args_disass:"x%rd$d, %imm%(x%rs1$d)"; + val offs[XLEN] <= X[rs1]+imm; + if(rd!=0) X[rd]<=zext(MEM[offs]); + } + LHU { + encoding: imm[11:0]s | rs1[4:0] | b101 | rd[4:0] | b0000011; + args_disass:"x%rd$d, %imm%(x%rs1$d)"; + val offs[XLEN] <= X[rs1]+imm; + if(rd!=0) X[rd]<=zext(MEM[offs]{16}); + } + SB { + encoding: imm[11:5]s | rs2[4:0] | rs1[4:0] | b000 | imm[4:0]s | b0100011; + args_disass:"x%rs2$d, %imm%(x%rs1$d)"; + val offs[XLEN] <= X[rs1] + imm; + MEM[offs] <= X[rs2]; + } + SH { + encoding: imm[11:5]s | rs2[4:0] | rs1[4:0] | b001 | imm[4:0]s | b0100011; + args_disass:"x%rs2$d, %imm%(x%rs1$d)"; + val offs[XLEN] <= X[rs1] + imm; + MEM[offs]{16} <= X[rs2]; + } + SW { + encoding: imm[11:5]s | rs2[4:0] | rs1[4:0] | b010 | imm[4:0]s | b0100011; + args_disass:"x%rs2$d, %imm%(x%rs1$d)"; + val offs[XLEN] <= X[rs1] + imm; + MEM[offs]{32} <= X[rs2]; + } + ADDI { + encoding: imm[11:0]s | rs1[4:0] | b000 | rd[4:0] | b0010011; + args_disass:"x%rd$d, x%rs1$d, %imm%"; + if(rd != 0) X[rd] <= X[rs1] + imm; + } + SLTI { + encoding: imm[11:0]s | rs1[4:0] | b010 | rd[4:0] | b0010011; + args_disass:"x%rd$d, x%rs1$d, %imm%"; + if (rd != 0) X[rd] <= choose(X[rs1]s < imm's, 1, 0); //TODO: needs fix + } + SLTIU { + encoding: imm[11:0]s | rs1[4:0] | b011 | rd[4:0] | b0010011; + args_disass:"x%rd$d, x%rs1$d, %imm%"; + val full_imm[XLEN] <= imm's; + if (rd != 0) X[rd] <= choose(X[rs1]'u < full_imm'u, 1, 0); + } + XORI { + encoding: imm[11:0]s | rs1[4:0] | b100 | rd[4:0] | b0010011; + args_disass:"x%rd$d, x%rs1$d, %imm%"; + if(rd != 0) X[rd] <= X[rs1] ^ imm; + } + ORI { + encoding: imm[11:0]s | rs1[4:0] | b110 | rd[4:0] | b0010011; + args_disass:"x%rd$d, x%rs1$d, %imm%"; + if(rd != 0) X[rd] <= X[rs1] | imm; + } + ANDI { + encoding: imm[11:0]s | rs1[4:0] | b111 | rd[4:0] | b0010011; + args_disass:"x%rd$d, x%rs1$d, %imm%"; + if(rd != 0) X[rd] <= X[rs1] & imm; + } + SLLI { + encoding: b0000000 | shamt[4:0] | rs1[4:0] | b001 | rd[4:0] | b0010011; + args_disass:"x%rd$d, x%rs1$d, %shamt%"; + if(rd != 0) X[rd] <= shll(X[rs1], shamt); + } + SRLI { + encoding: b0000000 | shamt[4:0] | rs1[4:0] | b101 | rd[4:0] | b0010011; + args_disass:"x%rd$d, x%rs1$d, %shamt%"; + if(rd != 0) X[rd] <= shrl(X[rs1], shamt); + } + SRAI { + encoding: b0100000 | shamt[4:0] | rs1[4:0] | b101 | rd[4:0] | b0010011; + args_disass:"x%rd$d, x%rs1$d, %shamt%"; + if(rd != 0) X[rd] <= shra(X[rs1], shamt); + } + ADD { + encoding: b0000000 | rs2[4:0] | rs1[4:0] | b000 | rd[4:0] | b0110011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0) X[rd] <= X[rs1] + X[rs2]; + } + SUB { + encoding: b0100000 | rs2[4:0] | rs1[4:0] | b000 | rd[4:0] | b0110011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0) X[rd] <= X[rs1] - X[rs2]; + } + SLL { + encoding: b0000000 | rs2[4:0] | rs1[4:0] | b001 | rd[4:0] | b0110011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0) X[rd] <= shll(X[rs1], X[rs2]&XLEN_BIT_MASK); + } + SLT { + encoding: b0000000 | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b0110011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if (rd != 0) X[rd] <= choose(X[rs1]s < X[rs2]s, 1, 0); + } + SLTU { + encoding: b0000000 | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0110011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if (rd != 0) X[rd] <= choose(zext(X[rs1]) < zext(X[rs2]), 1, 0); + } + XOR { + encoding: b0000000 | rs2[4:0] | rs1[4:0] | b100 | rd[4:0] | b0110011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0) X[rd] <= X[rs1] ^ X[rs2]; + } + SRL { + encoding: b0000000 | rs2[4:0] | rs1[4:0] | b101 | rd[4:0] | b0110011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0) X[rd] <= shrl(X[rs1], X[rs2]&XLEN_BIT_MASK); + } + SRA { + encoding: b0100000 | rs2[4:0] | rs1[4:0] | b101 | rd[4:0] | b0110011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0) X[rd] <= shra(X[rs1], X[rs2]&XLEN_BIT_MASK); + } + OR { + encoding: b0000000 | rs2[4:0] | rs1[4:0] | b110 | rd[4:0] | b0110011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0) X[rd] <= X[rs1] | X[rs2]; + } + AND { + encoding: b0000000 | rs2[4:0] | rs1[4:0] | b111 | rd[4:0] | b0110011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0) X[rd] <= X[rs1] & X[rs2]; + } + FENCE { + encoding: b0000 | pred[3:0] | succ[3:0] | rs1[4:0] | b000 | rd[4:0] | b0001111; + FENCE[fence] <= pred<<4 | succ; + } + FENCE_I(flush) { + encoding: imm[11:0] | rs1[4:0] | b001 | rd[4:0] | b0001111 ; + FENCE[fencei] <= imm; + } + ECALL(no_cont) { + encoding: b000000000000 | b00000 | b000 | b00000 | b1110011; + raise(0, 11); + } + EBREAK(no_cont) { + encoding: b000000000001 | b00000 | b000 | b00000 | b1110011; + raise(0, 3); + } + URET(no_cont) { + encoding: b0000000 | b00010 | b00000 | b000 | b00000 | b1110011; + leave(0); + } + SRET(no_cont) { + encoding: b0001000 | b00010 | b00000 | b000 | b00000 | b1110011; + leave(1); + } + MRET(no_cont) { + encoding: b0011000 | b00010 | b00000 | b000 | b00000 | b1110011; + leave(3); + } + WFI { + encoding: b0001000 | b00101 | b00000 | b000 | b00000 | b1110011; + wait(1); + } + SFENCE.VMA { + encoding: b0001001 | rs2[4:0] | rs1[4:0] | b000 | b00000 | b1110011; + FENCE[fencevmal] <= rs1; + FENCE[fencevmau] <= rs2; + } + CSRRW { + encoding: csr[11:0] | rs1[4:0] | b001 | rd[4:0] | b1110011; + args_disass:"x%rd$d, %csr$d, x%rs1$d"; + val rs_val[XLEN] <= X[rs1]; + if(rd!=0){ + val csr_val[XLEN] <= CSR[csr]; + CSR[csr] <= rs_val; + // make sure Xrd is updated once CSR write succeeds + X[rd] <= csr_val; + } else { + CSR[csr] <= rs_val; + } + } + CSRRS { + encoding: csr[11:0] | rs1[4:0] | b010 | rd[4:0] | b1110011; + args_disass:"x%rd$d, %csr$d, x%rs1$d"; + val xrd[XLEN] <= CSR[csr]; + val xrs1[XLEN] <= X[rs1]; + if(rd!=0) X[rd] <= xrd; + if(rs1!=0) CSR[csr] <= xrd | xrs1; + } + CSRRC { + encoding: csr[11:0] | rs1[4:0] | b011 | rd[4:0] | b1110011; + args_disass:"x%rd$d, %csr$d, x%rs1$d"; + val xrd[XLEN] <= CSR[csr]; + val xrs1[XLEN] <= X[rs1]; + if(rd!=0) X[rd] <= xrd; + if(rs1!=0) CSR[csr] <= xrd & ~xrs1; + } + CSRRWI { + encoding: csr[11:0] | zimm[4:0] | b101 | rd[4:0] | b1110011; + args_disass:"x%rd$d, %csr$d, 0x%zimm$x"; + if(rd!=0) X[rd] <= CSR[csr]; + CSR[csr] <= zext(zimm); + } + CSRRSI { + encoding: csr[11:0] | zimm[4:0] | b110 | rd[4:0] | b1110011; + args_disass:"x%rd$d, %csr$d, 0x%zimm$x"; + val res[XLEN] <= CSR[csr]; + if(zimm!=0) CSR[csr] <= res | zext(zimm); + // make sure rd is written after csr write succeeds + if(rd!=0) X[rd] <= res; + } + CSRRCI { + encoding: csr[11:0] | zimm[4:0] | b111 | rd[4:0] | b1110011; + args_disass:"x%rd$d, %csr$d, 0x%zimm$x"; + val res[XLEN] <= CSR[csr]; + if(rd!=0) X[rd] <= res; + if(zimm!=0) CSR[csr] <= res & ~zext(zimm, XLEN); + } + } +} + diff --git a/riscv/src/RV32M.core_desc b/riscv/src/RV32M.core_desc new file mode 100644 index 0000000..d8a15dd --- /dev/null +++ b/riscv/src/RV32M.core_desc @@ -0,0 +1,81 @@ +import "RV32IBase.core_desc" + +InsructionSet RV32M extends RV32IBase { + constants { + XLEN2 + } + instructions{ + MUL{ + encoding: b0000001 | rs2[4:0] | rs1[4:0] | b000 | rd[4:0] | b0110011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0){ + val res[XLEN2] <= zext(X[rs1], XLEN2) * zext(X[rs2], XLEN2); + X[rd]<= zext(res , XLEN); + } + } + MULH { + encoding: b0000001 | rs2[4:0] | rs1[4:0] | b001 | rd[4:0] | b0110011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0){ + val res[XLEN2] <= sext(X[rs1], XLEN2) * sext(X[rs2], XLEN2); + X[rd]<= zext(res >> XLEN, XLEN); + } + } + MULHSU { + encoding: b0000001 | rs2[4:0] | rs1[4:0] | b010 | rd[4:0] | b0110011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0){ + val res[XLEN2] <= sext(X[rs1], XLEN2) * zext(X[rs2], XLEN2); + X[rd]<= zext(res >> XLEN, XLEN); + } + } + MULHU { + encoding: b0000001 | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0110011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0){ + val res[XLEN2] <= zext(X[rs1], XLEN2) * zext(X[rs2], XLEN2); + X[rd]<= zext(res >> XLEN, XLEN); + } + } + DIV { + encoding: b0000001 | rs2[4:0] | rs1[4:0] | b100 | rd[4:0] | b0110011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0){ + if(X[rs2]!=0) + X[rd] <= sext(X[rs1], 32) / sext(X[rs2], 32); + else + X[rd] <= -1; + } + } + DIVU { + encoding: b0000001 | rs2[4:0] | rs1[4:0] | b101 | rd[4:0] | b0110011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0){ + if(X[rs2]!=0) + X[rd] <= zext(X[rs1], 32) / zext(X[rs2], 32); + else + X[rd] <= -1; + } + } + REM { + encoding: b0000001 | rs2[4:0] | rs1[4:0] | b110 | rd[4:0] | b0110011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0){ + if(X[rs2]!=0) + X[rd] <= sext(X[rs1], 32) % sext(X[rs2], 32); + else + X[rd] <= X[rs1]; + } + } + REMU { + encoding: b0000001 | rs2[4:0] | rs1[4:0] | b111 | rd[4:0] | b0110011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0){ + if(X[rs2]!=0) + X[rd] <= zext(X[rs1], 32) % zext(X[rs2], 32); + else + X[rd] <= X[rs1]; + } + } + } +} \ No newline at end of file diff --git a/riscv/src/RV64A.core_desc b/riscv/src/RV64A.core_desc new file mode 100644 index 0000000..f7875d9 --- /dev/null +++ b/riscv/src/RV64A.core_desc @@ -0,0 +1,111 @@ +import "RV64IBase.core_desc" + +InsructionSet RV64A extends RV64IBase{ + + address_spaces { + RES[8] + } + + instructions{ + LR.D { + encoding: b00010 | aq[0:0] | rl[0:0] | b00000 | rs1[4:0] | b011 | rd[4:0] | b0101111; + args_disass: "x%rd$d, x%rs1$d"; + if(rd!=0){ + val offs[XLEN] <= X[rs1]; + X[rd]<= sext(MEM[offs]{64}, XLEN); + RES[offs]{64}<=sext(-1, 64); + } + } + SC.D { + encoding: b00011 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111; + args_disass: "x%rd$d, x%rs1$d, x%rs2$d"; + val offs[XLEN] <= X[rs1]; + val res[64] <= RES[offs]; + if(res!=0){ + MEM[offs]{64} <= X[rs2]; + if(rd!=0) X[rd]<=0; + } else{ + if(rd!=0) X[rd]<= 1; + } + } + AMOSWAP.D{ + encoding: b00001 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111; + args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%a,rel=%rl)"; + val offs[XLEN] <= X[rs1]; + if(rd!=0) X[rd] <= sext(MEM[offs]{64}); + MEM[offs]{64} <= X[rs2]; + } + AMOADD.D{ + encoding: b00000 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111; + args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%a,rel=%rl)"; + val offs[XLEN] <= X[rs1]; + val res[XLEN] <= sext(MEM[offs]{64}); + if(rd!=0) X[rd]<=res; + val res2[XLEN] <= res + X[rs2]; + MEM[offs]{64}<=res2; + } + AMOXOR.D{ + encoding: b00100 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111; + args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%a,rel=%rl)"; + val offs[XLEN] <= X[rs1]; + val res[XLEN] <= sext(MEM[offs]{64}); + if(rd!=0) X[rd] <= res; + val res2[XLEN] <= res ^ X[rs2]; + MEM[offs]{64} <= res2; + } + AMOAND.D{ + encoding: b01100 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111; + args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%a,rel=%rl)"; + val offs[XLEN] <= X[rs1]; + val res[XLEN] <= sext(MEM[offs]{64}); + if(rd!=0) X[rd] <= res; + val res2[XLEN] <= res & X[rs2]; + MEM[offs]{64} <= res2; + } + AMOOR.D { + encoding: b01000 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111; + args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%a,rel=%rl)"; + val offs[XLEN] <= X[rs1]; + val res[XLEN] <= sext(MEM[offs]{64}); + if(rd!=0) X[rd] <= res; + val res2[XLEN] <= res | X[rs2]; + MEM[offs]{64} <= res2; + } + AMOMIN.D{ + encoding: b10000 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111; + args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%a,rel=%rl)"; + val offs[XLEN] <= X[rs1]; + val res[XLEN] <= sext(MEM[offs]{64}); + if(rd!=0) X[rd] <= res; + val res2[XLEN] <= choose(res s > X[rs2]s, X[rs2], res); + MEM[offs]{64} <= res; + } + AMOMAX.D{ + encoding: b10100 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111; + args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%a,rel=%rl)"; + val offs[XLEN] <= X[rs1]; + val res[XLEN] <= sext(MEM[offs]{64}); + if(rd!=0) X[rd] <= res; + val res2[XLEN] <= choose(res s < X[rs2]s, X[rs2], res); + MEM[offs]{64} <= res2; + } + AMOMINU.D{ + encoding: b11000 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111; + args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%a,rel=%rl)"; + val offs[XLEN] <= X[rs1]; + val res[XLEN] <= zext(MEM[offs]{64}); + if(rd!=0) X[rd] <= res; + val res2[XLEN] <= choose(res > X[rs2], X[rs2], res); + MEM[offs]{64} <= res2; + } + AMOMAXU.D{ + encoding: b11100 | aq[0:0] | rl[0:0] | rs2[4:0] | rs1[4:0] | b011 | rd[4:0] | b0101111; + args_disass: "x%rd$d, x%rs1$d, x%rs2$d (aqu=%a,rel=%rl)"; + val offs[XLEN] <= X[rs1]; + val res[XLEN] <= zext(MEM[offs]{64}); + if(rd!=0) X[rd] <= res; + val res2[XLEN] <= choose(res < X[rs2], X[rs2], res); + MEM[offs]{64} <= res2; + } + } +} \ No newline at end of file diff --git a/riscv/src/RV64IBase.core_desc b/riscv/src/RV64IBase.core_desc new file mode 100644 index 0000000..5508bb9 --- /dev/null +++ b/riscv/src/RV64IBase.core_desc @@ -0,0 +1,99 @@ +import "RV32IBase.core_desc" + +InsructionSet RV64IBase extends RV32IBase { + instructions{ + LWU { + encoding: imm[11:0]s | rs1[4:0] | b010 | rd[4:0] | b0000011; + args_disass:"x%rd$d, %imm%(x%rs1$d)"; + val offs[XLEN] <= X[rs1]+imm; + if(rd!=0) X[rd]<=zext(MEM[offs]{32}); + } + LD{ + encoding: imm[11:0]s | rs1[4:0] | b011 | rd[4:0] | b0000011; + args_disass:"x%rd$d, %imm%(x%rs1$d)"; + val offs[XLEN] <= X[rs1]+imm; + if(rd!=0) X[rd]<=sext(MEM[offs]{64}); + } + SD{ + encoding: imm[11:5]s | rs2[4:0] | rs1[4:0] | b011 | imm[4:0] | b0100011; + args_disass:"x%rs2$d, %imm%(x%rs1$d)"; + val offs[XLEN] <= X[rs1] + sext(imm, XLEN); + MEM[offs]{64} <= X[rs2]; + } + SLLI { + encoding: b000000 | shamt[5:0] | rs1[4:0] | b001 | rd[4:0] | b0010011; + args_disass:"x%rd$d, x%rs1$d, %shamt%"; + if(rd != 0) X[rd] <= shll(X[rs1], shamt); + } + SRLI { + encoding: b000000 | shamt[5:0] | rs1[4:0] | b101 | rd[4:0] | b0010011; + args_disass:"x%rd$d, x%rs1$d, %shamt%"; + if(rd != 0) X[rd] <= shrl(X[rs1], shamt); + } + SRAI { + encoding: b010000 | shamt[5:0] | rs1[4:0] | b101 | rd[4:0] | b0010011; + args_disass:"x%rd$d, x%rs1$d, %shamt%"; + if(rd != 0) X[rd] <= shra(X[rs1], shamt); + } + ADDIW { + encoding: imm[11:0]s | rs1[4:0] | b000 | rd[4:0] | b0011011; + args_disass:"x%rd$d, x%rs1$d, %imm%"; + if(rd != 0) X[rd] <= sext(X[rs1]{32}, XLEN) + sext(imm, XLEN); + } + SLLIW { + encoding: b0000000 | shamt[4:0] | rs1[4:0] | b001 | rd[4:0] | b0011011; + args_disass:"x%rd$d, x%rs1$d, %shamt%"; + if(rd != 0){ + val sh_val[32] <= shll(X[rs1]{32}, shamt); + X[rd] <= sext(sh_val, XLEN); + } + } + SRLIW { + encoding: b0000000 | shamt[4:0] | rs1[4:0] | b101 | rd[4:0] | b0011011; + args_disass:"x%rd$d, x%rs1$d, %shamt%"; + if(rd != 0){ + val sh_val[32] <= shrl(X[rs1], shamt); + X[rd] <= sext(sh_val, XLEN); + } + } + SRAIW { + encoding: b0100000 | shamt[4:0] | rs1[4:0] | b101 | rd[4:0] | b0011011; + args_disass:"x%rd$d, x%rs1$d, %shamt%"; + if(rd != 0){ + val sh_val[32] <= shra(X[rs1], shamt); + X[rd] <= sext(sh_val, XLEN); + } + } + ADDW { + encoding: b0000000 | rs2[4:0] | rs1[4:0] | b000 | rd[4:0] | b0111011; + } + SUBW { + encoding: b0100000 | rs2[4:0] | rs1[4:0] | b000 | rd[4:0] | b0111011; + } + SLLW { + encoding: b0000000 | rs2[4:0] | rs1[4:0] | b001 | rd[4:0] | b0111011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0){ + val sh_val[32] <= shll(X[rs1], X[rs2]&0x1f); + X[rd] <= sext(sh_val, XLEN); + } + } + SRLW { + encoding: b0000000 | rs2[4:0] | rs1[4:0] | b101 | rd[4:0] | b0111011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0){ + val sh_val[32] <= shrl(X[rs1], X[rs2]&0x1f); + X[rd] <= sext(sh_val, XLEN); + } + } + SRAW { + encoding: b0100000 | rs2[4:0] | rs1[4:0] | b101 | rd[4:0] | b0111011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0){ + val sh_val[32] <= shra(X[rs1], X[rs2]&0x1f); + X[rd] <= sext(sh_val, XLEN); + } + } + } +} + diff --git a/riscv/src/RV64M.core_desc b/riscv/src/RV64M.core_desc new file mode 100644 index 0000000..32728bb --- /dev/null +++ b/riscv/src/RV64M.core_desc @@ -0,0 +1,41 @@ +import "RV64IBase.core_desc" + +InsructionSet RV64M extends RV64IBase { + instructions{ + MULW{ + encoding: b0000001 | rs2[4:0] | rs1[4:0] | b000 | rd[4:0] | b0111011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0){ + X[rd]<= X[rs1] * X[rs2]; + } + } + DIVW { + encoding: b0000001 | rs2[4:0] | rs1[4:0] | b100 | rd[4:0] | b0111011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0){ + X[rd] <= X[rs1]s / X[rs2]s; + } + } + DIVUW { + encoding: b0000001 | rs2[4:0] | rs1[4:0] | b101 | rd[4:0] | b0111011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0){ + X[rd] <= X[rs1] / X[rs2]; + } + } + REMW { + encoding: b0000001 | rs2[4:0] | rs1[4:0] | b110 | rd[4:0] | b0111011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0){ + X[rd] <= X[rs1]s % X[rs2]s; + } + } + REMUW { + encoding: b0000001 | rs2[4:0] | rs1[4:0] | b111 | rd[4:0] | b0111011; + args_disass:"x%rd$d, x%rs1$d, x%rs2$d"; + if(rd != 0){ + X[rd] <= X[rs1] % X[rs2]; + } + } + } +} \ No newline at end of file diff --git a/riscv/src/internal/vm_minrv_ima.cpp b/riscv/src/internal/vm_minrv_ima.cpp new file mode 100644 index 0000000..85267ac --- /dev/null +++ b/riscv/src/internal/vm_minrv_ima.cpp @@ -0,0 +1,5760 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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/minrv_ima.h" +#include "iss/arch/riscv_core.h" +#include "iss/debugger/server.h" + +#include + +namespace iss { +namespace minrv_ima { +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 + 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< __lui(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("LUI"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + int32_t fld_imm_val = 0 | (signed_bit_sub<12,20>(instr) << 12); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("LUI x%1$d, 0x%2$05x"); + ins_fmter % (uint64_t)fld_rd_val % (int64_t)fld_imm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* X_rd_val = this->gen_const(32U, fld_imm_val); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction AUIPC + std::tuple __auipc(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("AUIPC"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + int32_t fld_imm_val = 0 | (signed_bit_sub<12,20>(instr) << 12); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("AUIPC x%1%, 0x%2$08x"); + ins_fmter % (uint64_t)fld_rd_val % (int64_t)fld_imm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* X_rd_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, fld_imm_val)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction JAL + std::tuple __jal(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("JAL"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + int32_t fld_imm_val = 0 | (bit_sub<12,8>(instr) << 12) | (bit_sub<20,1>(instr) << 11) | (bit_sub<21,10>(instr) << 1) | (signed_bit_sub<31,1>(instr) << 20); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("JAL x%1$d, 0x%2$x"); + ins_fmter % (uint64_t)fld_rd_val % (int64_t)fld_imm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* X_rd_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, 4)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + Value* PC_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, fld_imm_val)); + this->builder->CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); + 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); + } + + // instruction JALR + std::tuple __jalr(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("JALR"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + int16_t fld_imm_val = 0 | (signed_bit_sub<20,12>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("JALR x%1$d, x%2$d, 0x%3$x"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (int64_t)fld_imm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* X_rd_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, 4)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + Value* ret_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->gen_const(32U, fld_imm_val)); + Value* PC_val = this->builder->CreateAnd( + ret_val, + this->builder->CreateNot(this->gen_const(32U, 1))); + this->builder->CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); + 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); + } + + // instruction BEQ + std::tuple __beq(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("BEQ"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + int16_t fld_imm_val = 0 | (bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (signed_bit_sub<31,1>(instr) << 12); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("BEQ x%1$d, x%2$d, 0x%3$x"); + ins_fmter % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (int64_t)fld_imm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* PC_val = this->gen_choose( + this->builder->CreateICmp( + ICmpInst::ICMP_EQ, + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false)), + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, fld_imm_val)), + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, 4)), + 32); + this->builder->CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); + 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); + } + + // instruction BNE + std::tuple __bne(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("BNE"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + int16_t fld_imm_val = 0 | (bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (signed_bit_sub<31,1>(instr) << 12); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("BNE x%1$d, x%2$d, 0x%3$x"); + ins_fmter % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (int64_t)fld_imm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* PC_val = this->gen_choose( + this->builder->CreateICmp( + ICmpInst::ICMP_NE, + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false)), + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, fld_imm_val)), + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, 4)), + 32); + this->builder->CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); + 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); + } + + // instruction BLT + std::tuple __blt(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("BLT"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + int16_t fld_imm_val = 0 | (bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (signed_bit_sub<31,1>(instr) << 12); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("BLT x%1$d, x%2$d, 0x%3$x"); + ins_fmter % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (int64_t)fld_imm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* PC_val = this->gen_choose( + this->builder->CreateICmp( + ICmpInst::ICMP_SLT, + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + 32, true), + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + 32, true)), + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, fld_imm_val)), + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, 4)), + 32); + this->builder->CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); + 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); + } + + // instruction BGE + std::tuple __bge(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("BGE"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + int16_t fld_imm_val = 0 | (bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (signed_bit_sub<31,1>(instr) << 12); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("BGE x%1$d, x%2$d, 0x%3$x"); + ins_fmter % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (int64_t)fld_imm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* PC_val = this->gen_choose( + this->builder->CreateICmp( + ICmpInst::ICMP_SGE, + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + 32, true), + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + 32, true)), + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, fld_imm_val)), + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, 4)), + 32); + this->builder->CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); + 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); + } + + // instruction BLTU + std::tuple __bltu(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("BLTU"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + int16_t fld_imm_val = 0 | (bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (signed_bit_sub<31,1>(instr) << 12); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("BLTU x%1$d, x%2$d, 0x%3$x"); + ins_fmter % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (int64_t)fld_imm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* PC_val = this->gen_choose( + this->builder->CreateICmp( + ICmpInst::ICMP_ULT, + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false)), + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, fld_imm_val)), + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, 4)), + 32); + this->builder->CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); + 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); + } + + // instruction BGEU + std::tuple __bgeu(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("BGEU"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + int16_t fld_imm_val = 0 | (bit_sub<7,1>(instr) << 11) | (bit_sub<8,4>(instr) << 1) | (bit_sub<25,6>(instr) << 5) | (signed_bit_sub<31,1>(instr) << 12); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("BGEU x%1$d, x%2$d, 0x%3$x"); + ins_fmter % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (int64_t)fld_imm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* PC_val = this->gen_choose( + this->builder->CreateICmp( + ICmpInst::ICMP_UGE, + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false)), + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, fld_imm_val)), + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, 4)), + 32); + this->builder->CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); + 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); + } + + // instruction LB + std::tuple __lb(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("LB"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + int16_t fld_imm_val = 0 | (signed_bit_sub<20,12>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("LB x%1$d, %2%(x%3$d)"); + ins_fmter % (uint64_t)fld_rd_val % (int64_t)fld_imm_val % (uint64_t)fld_rs1_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* offs_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->gen_const(32U, fld_imm_val)); + if(fld_rd_val != 0){ + Value* X_rd_val = this->gen_ext( + this->gen_read_mem(traits::MEM, offs_val, 8/8), + 32, + true); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction LH + std::tuple __lh(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("LH"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + int16_t fld_imm_val = 0 | (signed_bit_sub<20,12>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("LH x%1$d, %2%(x%3$d)"); + ins_fmter % (uint64_t)fld_rd_val % (int64_t)fld_imm_val % (uint64_t)fld_rs1_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* offs_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->gen_const(32U, fld_imm_val)); + if(fld_rd_val != 0){ + Value* X_rd_val = this->gen_ext( + this->gen_read_mem(traits::MEM, offs_val, 16/8), + 32, + true); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction LW + std::tuple __lw(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("LW"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + int16_t fld_imm_val = 0 | (signed_bit_sub<20,12>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("LW x%1$d, %2%(x%3$d)"); + ins_fmter % (uint64_t)fld_rd_val % (int64_t)fld_imm_val % (uint64_t)fld_rs1_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* offs_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->gen_const(32U, fld_imm_val)); + if(fld_rd_val != 0){ + Value* X_rd_val = this->gen_ext( + this->gen_read_mem(traits::MEM, offs_val, 32/8), + 32, + true); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction LBU + std::tuple __lbu(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("LBU"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + int16_t fld_imm_val = 0 | (signed_bit_sub<20,12>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("LBU x%1$d, %2%(x%3$d)"); + ins_fmter % (uint64_t)fld_rd_val % (int64_t)fld_imm_val % (uint64_t)fld_rs1_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* offs_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->gen_const(32U, fld_imm_val)); + if(fld_rd_val != 0){ + Value* X_rd_val = this->gen_ext( + this->gen_read_mem(traits::MEM, offs_val, 8/8), + 32, + false); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction LHU + std::tuple __lhu(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("LHU"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + int16_t fld_imm_val = 0 | (signed_bit_sub<20,12>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("LHU x%1$d, %2%(x%3$d)"); + ins_fmter % (uint64_t)fld_rd_val % (int64_t)fld_imm_val % (uint64_t)fld_rs1_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* offs_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->gen_const(32U, fld_imm_val)); + if(fld_rd_val != 0){ + Value* X_rd_val = this->gen_ext( + this->gen_read_mem(traits::MEM, offs_val, 16/8), + 32, + false); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction SB + std::tuple __sb(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("SB"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + int16_t fld_imm_val = 0 | (bit_sub<7,5>(instr)) | (signed_bit_sub<25,7>(instr) << 5); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("SB x%1$d, %2%(x%3$d)"); + ins_fmter % (uint64_t)fld_rs2_val % (int64_t)fld_imm_val % (uint64_t)fld_rs1_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* offs_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->gen_const(32U, fld_imm_val)); + Value* MEM_offs_val = this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false); + this->gen_write_mem( + traits::MEM, + offs_val, + this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(8))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction SH + std::tuple __sh(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("SH"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + int16_t fld_imm_val = 0 | (bit_sub<7,5>(instr)) | (signed_bit_sub<25,7>(instr) << 5); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("SH x%1$d, %2%(x%3$d)"); + ins_fmter % (uint64_t)fld_rs2_val % (int64_t)fld_imm_val % (uint64_t)fld_rs1_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* offs_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->gen_const(32U, fld_imm_val)); + Value* MEM_offs_val = this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false); + this->gen_write_mem( + traits::MEM, + offs_val, + this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(16))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction SW + std::tuple __sw(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("SW"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + int16_t fld_imm_val = 0 | (bit_sub<7,5>(instr)) | (signed_bit_sub<25,7>(instr) << 5); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("SW x%1$d, %2%(x%3$d)"); + ins_fmter % (uint64_t)fld_rs2_val % (int64_t)fld_imm_val % (uint64_t)fld_rs1_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* offs_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->gen_const(32U, fld_imm_val)); + Value* MEM_offs_val = this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false); + this->gen_write_mem( + traits::MEM, + offs_val, + this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(32))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction ADDI + std::tuple __addi(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("ADDI"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + int16_t fld_imm_val = 0 | (signed_bit_sub<20,12>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("ADDI x%1$d, x%2$d, %3%"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (int64_t)fld_imm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* X_rd_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->gen_const(32U, fld_imm_val)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction SLTI + std::tuple __slti(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("SLTI"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + int16_t fld_imm_val = 0 | (signed_bit_sub<20,12>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("SLTI x%1$d, x%2$d, %3%"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (int64_t)fld_imm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* X_rd_val = this->gen_choose( + this->builder->CreateICmp( + ICmpInst::ICMP_SLT, + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + 32, true), + this->gen_ext( + this->gen_const(32U, fld_imm_val), + 32, true)), + this->gen_const(32U, 1), + this->gen_const(32U, 0), + 32); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction SLTIU + std::tuple __sltiu(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("SLTIU"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + int16_t fld_imm_val = 0 | (signed_bit_sub<20,12>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("SLTIU x%1$d, x%2$d, %3%"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (int64_t)fld_imm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + int32_t full_imm_val = fld_imm_val; + if(fld_rd_val != 0){ + Value* X_rd_val = this->gen_choose( + this->builder->CreateICmp( + ICmpInst::ICMP_ULT, + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + 32, false), + this->gen_ext( + full_imm_val, + 32, false)), + this->gen_const(32U, 1), + this->gen_const(32U, 0), + 32); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction XORI + std::tuple __xori(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("XORI"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + int16_t fld_imm_val = 0 | (signed_bit_sub<20,12>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("XORI x%1$d, x%2$d, %3%"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (int64_t)fld_imm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* X_rd_val = this->builder->CreateXor( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->gen_const(32U, fld_imm_val)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction ORI + std::tuple __ori(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("ORI"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + int16_t fld_imm_val = 0 | (signed_bit_sub<20,12>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("ORI x%1$d, x%2$d, %3%"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (int64_t)fld_imm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* X_rd_val = this->builder->CreateOr( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->gen_const(32U, fld_imm_val)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction ANDI + std::tuple __andi(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("ANDI"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + int16_t fld_imm_val = 0 | (signed_bit_sub<20,12>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("ANDI x%1$d, x%2$d, %3%"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (int64_t)fld_imm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* X_rd_val = this->builder->CreateAnd( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->gen_const(32U, fld_imm_val)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction SLLI + std::tuple __slli(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("SLLI"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_shamt_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("SLLI x%1$d, x%2$d, %3%"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_shamt_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* X_rd_val = this->builder->CreateShl( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->gen_const(32U, fld_shamt_val)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction SRLI + std::tuple __srli(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("SRLI"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_shamt_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("SRLI x%1$d, x%2$d, %3%"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_shamt_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* X_rd_val = this->builder->CreateLShr( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->gen_const(32U, fld_shamt_val)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction SRAI + std::tuple __srai(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("SRAI"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_shamt_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("SRAI x%1$d, x%2$d, %3%"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_shamt_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* X_rd_val = this->builder->CreateAShr( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->gen_const(32U, fld_shamt_val)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction ADD + std::tuple __add(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("ADD"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("ADD x%1$d, x%2$d, x%3$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* X_rd_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction SUB + std::tuple __sub(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("SUB"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("SUB x%1$d, x%2$d, x%3$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* X_rd_val = this->builder->CreateSub( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction SLL + std::tuple __sll(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("SLL"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("SLL x%1$d, x%2$d, x%3$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* X_rd_val = this->builder->CreateShl( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->builder->CreateAnd( + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + 31)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction SLT + std::tuple __slt(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("SLT"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("SLT x%1$d, x%2$d, x%3$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* X_rd_val = this->gen_choose( + this->builder->CreateICmp( + ICmpInst::ICMP_SLT, + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + 32, true), + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + 32, true)), + this->gen_const(32U, 1), + this->gen_const(32U, 0), + 32); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction SLTU + std::tuple __sltu(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("SLTU"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("SLTU x%1$d, x%2$d, x%3$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* X_rd_val = this->gen_choose( + this->builder->CreateICmp( + ICmpInst::ICMP_ULT, + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + 32, + false), + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + 32, + false)), + this->gen_const(32U, 1), + this->gen_const(32U, 0), + 32); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction XOR + std::tuple __xor(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("XOR"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("XOR x%1$d, x%2$d, x%3$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* X_rd_val = this->builder->CreateXor( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction SRL + std::tuple __srl(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("SRL"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("SRL x%1$d, x%2$d, x%3$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* X_rd_val = this->builder->CreateLShr( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->builder->CreateAnd( + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + 31)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction SRA + std::tuple __sra(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("SRA"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("SRA x%1$d, x%2$d, x%3$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* X_rd_val = this->builder->CreateAShr( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->builder->CreateAnd( + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + 31)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction OR + std::tuple __or(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("OR"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("OR x%1$d, x%2$d, x%3$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* X_rd_val = this->builder->CreateOr( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction AND + std::tuple __and(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("AND"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("AND x%1$d, x%2$d, x%3$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* X_rd_val = this->builder->CreateAnd( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction FENCE + std::tuple __fence(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("FENCE"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_succ_val = 0 | (bit_sub<20,4>(instr)); + uint8_t fld_pred_val = 0 | (bit_sub<24,4>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + std::string opcode("FENCE"); + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % opcode; + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* FENCE_fence_val = this->builder->CreateOr( + this->builder->CreateShl( + this->gen_const(32U, fld_pred_val), + this->gen_const(32U, 4)), + this->gen_const(32U, fld_succ_val)); + this->gen_write_mem( + traits::FENCE, + (uint64_t)0, + this->builder->CreateZExtOrTrunc(FENCE_fence_val,this->get_type(32))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction FENCE_I + std::tuple __fence_i(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("FENCE_I"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint16_t fld_imm_val = 0 | (bit_sub<20,12>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + std::string opcode("FENCE_I"); + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % opcode; + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* FENCE_fencei_val = this->gen_const(32U, fld_imm_val); + this->gen_write_mem( + traits::FENCE, + (uint64_t)1, + this->builder->CreateZExtOrTrunc(FENCE_fencei_val,this->get_type(32))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + this->gen_trap_check(this->leave_blk); + return std::make_tuple(iss::vm::FLUSH, nullptr); + } + + // instruction ECALL + std::tuple __ecall(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("ECALL"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + ; + if(this->disass_enabled){ + /* generate console output when executing the command */ + std::string opcode("ECALL"); + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % opcode; + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + this->gen_raise_trap(0, 11); + 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); + } + + // instruction EBREAK + std::tuple __ebreak(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("EBREAK"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + ; + if(this->disass_enabled){ + /* generate console output when executing the command */ + std::string opcode("EBREAK"); + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % opcode; + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + this->gen_raise_trap(0, 3); + 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); + } + + // instruction URET + std::tuple __uret(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("URET"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + ; + if(this->disass_enabled){ + /* generate console output when executing the command */ + std::string opcode("URET"); + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % opcode; + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + this->gen_leave_trap(0); + 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); + } + + // instruction SRET + std::tuple __sret(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("SRET"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + ; + if(this->disass_enabled){ + /* generate console output when executing the command */ + std::string opcode("SRET"); + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % opcode; + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + this->gen_leave_trap(1); + 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); + } + + // instruction MRET + std::tuple __mret(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("MRET"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + ; + if(this->disass_enabled){ + /* generate console output when executing the command */ + std::string opcode("MRET"); + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % opcode; + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + this->gen_leave_trap(3); + 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); + } + + // instruction WFI + std::tuple __wfi(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("WFI"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + ; + if(this->disass_enabled){ + /* generate console output when executing the command */ + std::string opcode("WFI"); + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % opcode; + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + this->gen_wait(1); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction SFENCE.VMA + std::tuple __sfence_vma(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("SFENCE.VMA"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + std::string opcode("SFENCE.VMA"); + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % opcode; + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* FENCE_fencevmal_val = this->gen_const(32U, fld_rs1_val); + this->gen_write_mem( + traits::FENCE, + (uint64_t)2, + this->builder->CreateZExtOrTrunc(FENCE_fencevmal_val,this->get_type(32))); + Value* FENCE_fencevmau_val = this->gen_const(32U, fld_rs2_val); + this->gen_write_mem( + traits::FENCE, + (uint64_t)3, + this->builder->CreateZExtOrTrunc(FENCE_fencevmau_val,this->get_type(32))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction CSRRW + std::tuple __csrrw(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("CSRRW"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint16_t fld_csr_val = 0 | (bit_sub<20,12>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("CSRRW x%1$d, %2$d, x%3$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_csr_val % (uint64_t)fld_rs1_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* rs_val_val = this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false); + if(fld_rd_val != 0){ + Value* csr_val_val = this->gen_read_mem(traits::CSR, fld_csr_val, 32/8); + Value* CSR_csr_val = rs_val_val; + this->gen_write_mem( + traits::CSR, + fld_csr_val, + this->builder->CreateZExtOrTrunc(CSR_csr_val,this->get_type(32))); + Value* X_rd_val = csr_val_val; + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } else { + Value* CSR_csr_val = rs_val_val; + this->gen_write_mem( + traits::CSR, + fld_csr_val, + this->builder->CreateZExtOrTrunc(CSR_csr_val,this->get_type(32))); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction CSRRS + std::tuple __csrrs(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("CSRRS"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint16_t fld_csr_val = 0 | (bit_sub<20,12>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("CSRRS x%1$d, %2$d, x%3$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_csr_val % (uint64_t)fld_rs1_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* xrd_val = this->gen_read_mem(traits::CSR, fld_csr_val, 32/8); + Value* xrs1_val = this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false); + if(fld_rd_val != 0){ + Value* X_rd_val = xrd_val; + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + if(fld_rs1_val != 0){ + Value* CSR_csr_val = this->builder->CreateOr( + xrd_val, + xrs1_val); + this->gen_write_mem( + traits::CSR, + fld_csr_val, + this->builder->CreateZExtOrTrunc(CSR_csr_val,this->get_type(32))); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction CSRRC + std::tuple __csrrc(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("CSRRC"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint16_t fld_csr_val = 0 | (bit_sub<20,12>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("CSRRC x%1$d, %2$d, x%3$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_csr_val % (uint64_t)fld_rs1_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* xrd_val = this->gen_read_mem(traits::CSR, fld_csr_val, 32/8); + Value* xrs1_val = this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false); + if(fld_rd_val != 0){ + Value* X_rd_val = xrd_val; + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + if(fld_rs1_val != 0){ + Value* CSR_csr_val = this->builder->CreateAnd( + xrd_val, + this->builder->CreateNot(xrs1_val)); + this->gen_write_mem( + traits::CSR, + fld_csr_val, + this->builder->CreateZExtOrTrunc(CSR_csr_val,this->get_type(32))); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction CSRRWI + std::tuple __csrrwi(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("CSRRWI"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_zimm_val = 0 | (bit_sub<15,5>(instr)); + uint16_t fld_csr_val = 0 | (bit_sub<20,12>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("CSRRWI x%1$d, %2$d, 0x%3$x"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_csr_val % (uint64_t)fld_zimm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* X_rd_val = this->gen_read_mem(traits::CSR, fld_csr_val, 32/8); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + Value* CSR_csr_val = this->gen_ext( + this->gen_const(32U, fld_zimm_val), + 32, + false); + this->gen_write_mem( + traits::CSR, + fld_csr_val, + this->builder->CreateZExtOrTrunc(CSR_csr_val,this->get_type(32))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction CSRRSI + std::tuple __csrrsi(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("CSRRSI"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_zimm_val = 0 | (bit_sub<15,5>(instr)); + uint16_t fld_csr_val = 0 | (bit_sub<20,12>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("CSRRSI x%1$d, %2$d, 0x%3$x"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_csr_val % (uint64_t)fld_zimm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* res_val = this->gen_read_mem(traits::CSR, fld_csr_val, 32/8); + if(fld_zimm_val != 0){ + Value* CSR_csr_val = this->builder->CreateOr( + res_val, + this->gen_ext( + this->gen_const(32U, fld_zimm_val), + 32, + false)); + this->gen_write_mem( + traits::CSR, + fld_csr_val, + this->builder->CreateZExtOrTrunc(CSR_csr_val,this->get_type(32))); + } + if(fld_rd_val != 0){ + Value* X_rd_val = res_val; + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction CSRRCI + std::tuple __csrrci(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("CSRRCI"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_zimm_val = 0 | (bit_sub<15,5>(instr)); + uint16_t fld_csr_val = 0 | (bit_sub<20,12>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("CSRRCI x%1$d, %2$d, 0x%3$x"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_csr_val % (uint64_t)fld_zimm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* res_val = this->gen_read_mem(traits::CSR, fld_csr_val, 32/8); + if(fld_rd_val != 0){ + Value* X_rd_val = res_val; + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + if(fld_zimm_val != 0){ + Value* CSR_csr_val = this->builder->CreateAnd( + res_val, + this->builder->CreateNot(this->gen_ext( + this->gen_const(32U, fld_zimm_val), + 32, + false))); + this->gen_write_mem( + traits::CSR, + fld_csr_val, + this->builder->CreateZExtOrTrunc(CSR_csr_val,this->get_type(32))); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction MUL + std::tuple __mul(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("MUL"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("MUL x%1$d, x%2$d, x%3$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* res_val = this->builder->CreateMul( + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + 64, + false), + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + 64, + false)); + Value* X_rd_val = this->gen_ext( + res_val, + 32, + false); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction MULH + std::tuple __mulh(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("MULH"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("MULH x%1$d, x%2$d, x%3$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* res_val = this->builder->CreateMul( + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + 64, + true), + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + 64, + true)); + Value* X_rd_val = this->gen_ext( + this->builder->CreateLShr( + res_val, + 32), + 32, + false); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction MULHSU + std::tuple __mulhsu(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("MULHSU"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("MULHSU x%1$d, x%2$d, x%3$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* res_val = this->builder->CreateMul( + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + 64, + true), + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + 64, + false)); + Value* X_rd_val = this->gen_ext( + this->builder->CreateLShr( + res_val, + 32), + 32, + false); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction MULHU + std::tuple __mulhu(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("MULHU"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("MULHU x%1$d, x%2$d, x%3$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* res_val = this->builder->CreateMul( + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + 64, + false), + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + 64, + false)); + Value* X_rd_val = this->gen_ext( + this->builder->CreateLShr( + res_val, + 32), + 32, + false); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction DIV + std::tuple __div(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("DIV"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("DIV x%1$d, x%2$d, x%3$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + llvm::BasicBlock* bbnext = llvm::BasicBlock::Create(this->mod->getContext(), "endif", this->func, this->leave_blk); + llvm::BasicBlock* bb_then = llvm::BasicBlock::Create(this->mod->getContext(), "thenbr", this->func, bbnext); + llvm::BasicBlock* bb_else = llvm::BasicBlock::Create(this->mod->getContext(), "elsebr", this->func, bbnext); + // this->builder->SetInsertPoint(bb); + this->gen_cond_branch(this->builder->CreateICmp( + ICmpInst::ICMP_NE, + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + this->gen_const(32U, 0)), + bb_then, + bb_else); + this->builder->SetInsertPoint(bb_then); + { + Value* X_rd_val = this->builder->CreateSDiv( + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + 32, + true), + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + 32, + true)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->builder->CreateBr(bbnext); + this->builder->SetInsertPoint(bb_else); + { + Value* X_rd_val = this->builder->CreateNeg(this->gen_const(32U, 1)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->builder->CreateBr(bbnext); + bb=bbnext; + this->builder->SetInsertPoint(bb); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction DIVU + std::tuple __divu(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("DIVU"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("DIVU x%1$d, x%2$d, x%3$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + llvm::BasicBlock* bbnext = llvm::BasicBlock::Create(this->mod->getContext(), "endif", this->func, this->leave_blk); + llvm::BasicBlock* bb_then = llvm::BasicBlock::Create(this->mod->getContext(), "thenbr", this->func, bbnext); + llvm::BasicBlock* bb_else = llvm::BasicBlock::Create(this->mod->getContext(), "elsebr", this->func, bbnext); + // this->builder->SetInsertPoint(bb); + this->gen_cond_branch(this->builder->CreateICmp( + ICmpInst::ICMP_NE, + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + this->gen_const(32U, 0)), + bb_then, + bb_else); + this->builder->SetInsertPoint(bb_then); + { + Value* X_rd_val = this->builder->CreateUDiv( + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + 32, + false), + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + 32, + false)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->builder->CreateBr(bbnext); + this->builder->SetInsertPoint(bb_else); + { + Value* X_rd_val = this->builder->CreateNeg(this->gen_const(32U, 1)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->builder->CreateBr(bbnext); + bb=bbnext; + this->builder->SetInsertPoint(bb); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction REM + std::tuple __rem(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("REM"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("REM x%1$d, x%2$d, x%3$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + llvm::BasicBlock* bbnext = llvm::BasicBlock::Create(this->mod->getContext(), "endif", this->func, this->leave_blk); + llvm::BasicBlock* bb_then = llvm::BasicBlock::Create(this->mod->getContext(), "thenbr", this->func, bbnext); + llvm::BasicBlock* bb_else = llvm::BasicBlock::Create(this->mod->getContext(), "elsebr", this->func, bbnext); + // this->builder->SetInsertPoint(bb); + this->gen_cond_branch(this->builder->CreateICmp( + ICmpInst::ICMP_NE, + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + this->gen_const(32U, 0)), + bb_then, + bb_else); + this->builder->SetInsertPoint(bb_then); + { + Value* X_rd_val = this->builder->CreateSRem( + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + 32, + true), + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + 32, + true)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->builder->CreateBr(bbnext); + this->builder->SetInsertPoint(bb_else); + { + Value* X_rd_val = this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->builder->CreateBr(bbnext); + bb=bbnext; + this->builder->SetInsertPoint(bb); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction REMU + std::tuple __remu(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("REMU"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("REMU x%1$d, x%2$d, x%3$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + llvm::BasicBlock* bbnext = llvm::BasicBlock::Create(this->mod->getContext(), "endif", this->func, this->leave_blk); + llvm::BasicBlock* bb_then = llvm::BasicBlock::Create(this->mod->getContext(), "thenbr", this->func, bbnext); + llvm::BasicBlock* bb_else = llvm::BasicBlock::Create(this->mod->getContext(), "elsebr", this->func, bbnext); + // this->builder->SetInsertPoint(bb); + this->gen_cond_branch(this->builder->CreateICmp( + ICmpInst::ICMP_NE, + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + this->gen_const(32U, 0)), + bb_then, + bb_else); + this->builder->SetInsertPoint(bb_then); + { + Value* X_rd_val = this->builder->CreateURem( + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + 32, + false), + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + 32, + false)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->builder->CreateBr(bbnext); + this->builder->SetInsertPoint(bb_else); + { + Value* X_rd_val = this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->builder->CreateBr(bbnext); + bb=bbnext; + this->builder->SetInsertPoint(bb); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction LR.W + std::tuple __lr_w(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("LR.W"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rl_val = 0 | (bit_sub<25,1>(instr)); + uint8_t fld_aq_val = 0 | (bit_sub<26,1>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("LR.W x%1$d, x%2$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + if(fld_rd_val != 0){ + Value* offs_val = this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false); + Value* X_rd_val = this->gen_ext( + this->gen_read_mem(traits::MEM, offs_val, 32/8), + 32, + true); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + Value* RES_offs_val = this->gen_ext( + this->builder->CreateNeg(this->gen_const(8U, 1)), + 32, + true); + this->gen_write_mem( + traits::RES, + offs_val, + this->builder->CreateZExtOrTrunc(RES_offs_val,this->get_type(32))); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction SC.W + std::tuple __sc_w(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("SC.W"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + uint8_t fld_rl_val = 0 | (bit_sub<25,1>(instr)); + uint8_t fld_aq_val = 0 | (bit_sub<26,1>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("SC.W x%1$d, x%2$d, x%3$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* offs_val = this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false); + Value* res1_val = this->gen_read_mem(traits::RES, offs_val, 32/8); + llvm::BasicBlock* bbnext = llvm::BasicBlock::Create(this->mod->getContext(), "endif", this->func, this->leave_blk); + llvm::BasicBlock* bb_then = llvm::BasicBlock::Create(this->mod->getContext(), "thenbr", this->func, bbnext); + // this->builder->SetInsertPoint(bb); + this->gen_cond_branch(this->builder->CreateICmp( + ICmpInst::ICMP_NE, + res1_val, + this->gen_const(32U, 0)), + bb_then, + bbnext); + this->builder->SetInsertPoint(bb_then); + { + Value* MEM_offs_val = this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false); + this->gen_write_mem( + traits::MEM, + offs_val, + this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(32))); + } + this->builder->CreateBr(bbnext); + bb=bbnext; + this->builder->SetInsertPoint(bb); + if(fld_rd_val != 0){ + Value* X_rd_val = this->gen_choose( + this->builder->CreateICmp( + ICmpInst::ICMP_NE, + res1_val, + this->gen_const(32U, 0)), + this->gen_const(32U, 0), + this->gen_const(32U, 1), + 32); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction AMOSWAP.W + std::tuple __amoswap_w(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("AMOSWAP.W"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + uint8_t fld_rl_val = 0 | (bit_sub<25,1>(instr)); + uint8_t fld_aq_val = 0 | (bit_sub<26,1>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("AMOSWAP.W x%1$d, x%2$d, x%3$d (aqu=%4$d,rel=%5$d)"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (uint64_t)fld_aq_val % (uint64_t)fld_rl_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* offs_val = this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false); + if(fld_rd_val != 0){ + Value* X_rd_val = this->gen_ext( + this->gen_read_mem(traits::MEM, offs_val, 32/8), + 32, + true); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + Value* MEM_offs_val = this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false); + this->gen_write_mem( + traits::MEM, + offs_val, + this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(32))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction AMOADD.W + std::tuple __amoadd_w(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("AMOADD.W"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + uint8_t fld_rl_val = 0 | (bit_sub<25,1>(instr)); + uint8_t fld_aq_val = 0 | (bit_sub<26,1>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("AMOADD.W x%1$d, x%2$d, x%3$d (aqu=%4$d,rel=%5$d)"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (uint64_t)fld_aq_val % (uint64_t)fld_rl_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* offs_val = this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false); + Value* res1_val = this->gen_ext( + this->gen_read_mem(traits::MEM, offs_val, 32/8), + 32, + true); + if(fld_rd_val != 0){ + Value* X_rd_val = res1_val; + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + Value* res2_val = this->builder->CreateAdd( + res1_val, + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false)); + Value* MEM_offs_val = res2_val; + this->gen_write_mem( + traits::MEM, + offs_val, + this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(32))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction AMOXOR.W + std::tuple __amoxor_w(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("AMOXOR.W"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + uint8_t fld_rl_val = 0 | (bit_sub<25,1>(instr)); + uint8_t fld_aq_val = 0 | (bit_sub<26,1>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("AMOXOR.W x%1$d, x%2$d, x%3$d (aqu=%4$d,rel=%5$d)"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (uint64_t)fld_aq_val % (uint64_t)fld_rl_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* offs_val = this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false); + Value* res1_val = this->gen_ext( + this->gen_read_mem(traits::MEM, offs_val, 32/8), + 32, + true); + if(fld_rd_val != 0){ + Value* X_rd_val = res1_val; + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + Value* res2_val = this->builder->CreateXor( + res1_val, + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false)); + Value* MEM_offs_val = res2_val; + this->gen_write_mem( + traits::MEM, + offs_val, + this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(32))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction AMOAND.W + std::tuple __amoand_w(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("AMOAND.W"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + uint8_t fld_rl_val = 0 | (bit_sub<25,1>(instr)); + uint8_t fld_aq_val = 0 | (bit_sub<26,1>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("AMOAND.W x%1$d, x%2$d, x%3$d (aqu=%4$d,rel=%5$d)"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (uint64_t)fld_aq_val % (uint64_t)fld_rl_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* offs_val = this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false); + Value* res1_val = this->gen_ext( + this->gen_read_mem(traits::MEM, offs_val, 32/8), + 32, + true); + if(fld_rd_val != 0){ + Value* X_rd_val = res1_val; + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + Value* res2_val = this->builder->CreateAnd( + res1_val, + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false)); + Value* MEM_offs_val = res2_val; + this->gen_write_mem( + traits::MEM, + offs_val, + this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(32))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction AMOOR.W + std::tuple __amoor_w(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("AMOOR.W"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + uint8_t fld_rl_val = 0 | (bit_sub<25,1>(instr)); + uint8_t fld_aq_val = 0 | (bit_sub<26,1>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("AMOOR.W x%1$d, x%2$d, x%3$d (aqu=%4$d,rel=%5$d)"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (uint64_t)fld_aq_val % (uint64_t)fld_rl_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* offs_val = this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false); + Value* res1_val = this->gen_ext( + this->gen_read_mem(traits::MEM, offs_val, 32/8), + 32, + true); + if(fld_rd_val != 0){ + Value* X_rd_val = res1_val; + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + Value* res2_val = this->builder->CreateOr( + res1_val, + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false)); + Value* MEM_offs_val = res2_val; + this->gen_write_mem( + traits::MEM, + offs_val, + this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(32))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction AMOMIN.W + std::tuple __amomin_w(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("AMOMIN.W"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + uint8_t fld_rl_val = 0 | (bit_sub<25,1>(instr)); + uint8_t fld_aq_val = 0 | (bit_sub<26,1>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("AMOMIN.W x%1$d, x%2$d, x%3$d (aqu=%4$d,rel=%5$d)"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (uint64_t)fld_aq_val % (uint64_t)fld_rl_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* offs_val = this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false); + Value* res1_val = this->gen_ext( + this->gen_read_mem(traits::MEM, offs_val, 32/8), + 32, + true); + if(fld_rd_val != 0){ + Value* X_rd_val = res1_val; + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + Value* res2_val = this->gen_choose( + this->builder->CreateICmp( + ICmpInst::ICMP_SGT, + this->gen_ext( + res1_val, + 32, true), + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + 32, true)), + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + res1_val, + 32); + Value* MEM_offs_val = res2_val; + this->gen_write_mem( + traits::MEM, + offs_val, + this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(32))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction AMOMAX.W + std::tuple __amomax_w(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("AMOMAX.W"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + uint8_t fld_rl_val = 0 | (bit_sub<25,1>(instr)); + uint8_t fld_aq_val = 0 | (bit_sub<26,1>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("AMOMAX.W x%1$d, x%2$d, x%3$d (aqu=%4$d,rel=%5$d)"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (uint64_t)fld_aq_val % (uint64_t)fld_rl_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* offs_val = this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false); + Value* res1_val = this->gen_ext( + this->gen_read_mem(traits::MEM, offs_val, 32/8), + 32, + true); + if(fld_rd_val != 0){ + Value* X_rd_val = res1_val; + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + Value* res2_val = this->gen_choose( + this->builder->CreateICmp( + ICmpInst::ICMP_SLT, + this->gen_ext( + res1_val, + 32, true), + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + 32, true)), + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + res1_val, + 32); + Value* MEM_offs_val = res2_val; + this->gen_write_mem( + traits::MEM, + offs_val, + this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(32))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction AMOMINU.W + std::tuple __amominu_w(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("AMOMINU.W"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + uint8_t fld_rl_val = 0 | (bit_sub<25,1>(instr)); + uint8_t fld_aq_val = 0 | (bit_sub<26,1>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("AMOMINU.W x%1$d, x%2$d, x%3$d (aqu=%4$d,rel=%5$d)"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (uint64_t)fld_aq_val % (uint64_t)fld_rl_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* offs_val = this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false); + Value* res1_val = this->gen_ext( + this->gen_read_mem(traits::MEM, offs_val, 32/8), + 32, + false); + if(fld_rd_val != 0){ + Value* X_rd_val = res1_val; + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + Value* res2_val = this->gen_choose( + this->builder->CreateICmp( + ICmpInst::ICMP_UGT, + res1_val, + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false)), + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + res1_val, + 32); + Value* MEM_offs_val = res2_val; + this->gen_write_mem( + traits::MEM, + offs_val, + this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(32))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction AMOMAXU.W + std::tuple __amomaxu_w(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("AMOMAXU.W"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + uint8_t fld_rs1_val = 0 | (bit_sub<15,5>(instr)); + uint8_t fld_rs2_val = 0 | (bit_sub<20,5>(instr)); + uint8_t fld_rl_val = 0 | (bit_sub<25,1>(instr)); + uint8_t fld_aq_val = 0 | (bit_sub<26,1>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("AMOMAXU.W x%1$d, x%2$d, x%3$d (aqu=%4$d,rel=%5$d)"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (uint64_t)fld_aq_val % (uint64_t)fld_rl_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+4; + + Value* offs_val = this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false); + Value* res1_val = this->gen_ext( + this->gen_read_mem(traits::MEM, offs_val, 32/8), + 32, + false); + if(fld_rd_val != 0){ + Value* X_rd_val = res1_val; + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + } + Value* res2_val = this->gen_choose( + this->builder->CreateICmp( + ICmpInst::ICMP_ULT, + this->gen_ext( + res1_val, + 32, false), + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + 32, false)), + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false), + res1_val, + 32); + Value* MEM_offs_val = res2_val; + this->gen_write_mem( + traits::MEM, + offs_val, + this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(32))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction C.ADDI4SPN + std::tuple __c_addi4spn(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.ADDI4SPN"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<2,3>(instr)); + uint16_t fld_nzuimm_val = 0 | (bit_sub<5,1>(instr) << 3) | (bit_sub<6,1>(instr) << 2) | (bit_sub<7,4>(instr) << 6) | (bit_sub<11,2>(instr) << 4); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.ADDI4SPN x%1$d, 0x%2$05x"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_nzuimm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + if(fld_nzuimm_val == 0){ + this->gen_raise_trap(0, 2); + } + uint8_t rd_idx_val = (fld_rd_val + 8); + uint8_t x2_idx_val = 2; + Value* X_rd_idx_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(x2_idx_val), false), + this->gen_const(32U, fld_nzuimm_val)); + this->builder->CreateStore(X_rd_idx_val, get_reg_ptr(rd_idx_val), false); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction C.LW + std::tuple __c_lw(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.LW"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rd_val = 0 | (bit_sub<2,3>(instr)); + uint8_t fld_uimm_val = 0 | (bit_sub<5,1>(instr) << 6) | (bit_sub<6,1>(instr) << 2) | (bit_sub<10,3>(instr) << 3); + uint8_t fld_rs1_val = 0 | (bit_sub<7,3>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.LW x(8+%1$d), x(8+%2$d), 0x%3$05x"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs1_val % (uint64_t)fld_uimm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + uint8_t rs1_idx_val = (fld_rs1_val + 8); + Value* adr_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(rs1_idx_val), false), + this->gen_const(32U, fld_uimm_val)); + uint8_t rd_idx_val = (fld_rd_val + 8); + Value* X_rd_idx_val = this->gen_read_mem(traits::MEM, adr_val, 32/8); + this->builder->CreateStore(X_rd_idx_val, get_reg_ptr(rd_idx_val), false); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction C.SW + std::tuple __c_sw(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.SW"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rs2_val = 0 | (bit_sub<2,3>(instr)); + uint8_t fld_uimm_val = 0 | (bit_sub<5,1>(instr) << 6) | (bit_sub<6,1>(instr) << 2) | (bit_sub<10,3>(instr) << 3); + uint8_t fld_rs1_val = 0 | (bit_sub<7,3>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.SW x(8+%1$d), x(8+%2$d), 0x%3$05x"); + ins_fmter % (uint64_t)fld_rs1_val % (uint64_t)fld_rs2_val % (uint64_t)fld_uimm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + uint8_t rs1_idx_val = (fld_rs1_val + 8); + Value* adr_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(rs1_idx_val), false), + this->gen_const(32U, fld_uimm_val)); + uint8_t rs2_idx_val = (fld_rs2_val + 8); + Value* MEM_adr_val = this->builder->CreateLoad(get_reg_ptr(rs2_idx_val), false); + this->gen_write_mem( + traits::MEM, + adr_val, + this->builder->CreateZExtOrTrunc(MEM_adr_val,this->get_type(32))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction C.NOP + std::tuple __c_nop(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.NOP"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + ; + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.NOP "); + ins_fmter ; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + /* TODO: describe operations for C.NOP ! */ + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction C.ADDI + std::tuple __c_addi(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.ADDI"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + int8_t fld_nzimm_val = 0 | (bit_sub<2,5>(instr)) | (signed_bit_sub<12,1>(instr) << 5); + uint8_t fld_rs1_val = 0 | (bit_sub<7,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.ADDI x%1$d, 0x%2$05x"); + ins_fmter % (uint64_t)fld_rs1_val % (int64_t)fld_nzimm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + if(fld_nzimm_val == 0){ + this->gen_raise_trap(0, 2); + } + Value* X_rs1_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->gen_const(32U, fld_nzimm_val)); + this->builder->CreateStore(X_rs1_val, get_reg_ptr(fld_rs1_val), false); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction C.JAL + std::tuple __c_jal(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.JAL"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + int16_t fld_imm_val = 0 | (bit_sub<2,1>(instr) << 5) | (bit_sub<3,3>(instr) << 1) | (bit_sub<6,1>(instr) << 7) | (bit_sub<7,1>(instr) << 6) | (bit_sub<8,1>(instr) << 10) | (bit_sub<9,2>(instr) << 8) | (bit_sub<11,1>(instr) << 4) | (signed_bit_sub<12,1>(instr) << 11); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.JAL 0x%1$05x"); + ins_fmter % (int64_t)fld_imm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + uint8_t rd_val = 1; + Value* X_rd_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, 2)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(rd_val), false); + Value* PC_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, fld_imm_val)); + this->builder->CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); + 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); + } + + // instruction C.LI + std::tuple __c_li(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.LI"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + int8_t fld_imm_val = 0 | (bit_sub<2,5>(instr)) | (signed_bit_sub<12,1>(instr) << 5); + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.LI x%1$d, 0x%2$05x"); + ins_fmter % (uint64_t)fld_rd_val % (int64_t)fld_imm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + if(fld_rd_val == 0){ + this->gen_raise_trap(0, 2); + } + Value* X_rd_val = this->gen_const(32U, fld_imm_val); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction C.LUI + std::tuple __c_lui(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.LUI"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + int32_t fld_nzimm_val = 0 | (bit_sub<2,5>(instr) << 12) | (signed_bit_sub<12,1>(instr) << 17); + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.LUI x%1$d, 0x%2$05x"); + ins_fmter % (uint64_t)fld_rd_val % (int64_t)fld_nzimm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + if(fld_rd_val == 0){ + this->gen_raise_trap(0, 2); + } + if(fld_rd_val == 2){ + this->gen_raise_trap(0, 2); + } + if(fld_nzimm_val == 0){ + this->gen_raise_trap(0, 2); + } + Value* X_rd_val = this->gen_const(32U, fld_nzimm_val); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction C.ADDI16SP + std::tuple __c_addi16sp(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.ADDI16SP"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + int16_t fld_nzimm_val = 0 | (bit_sub<2,1>(instr) << 5) | (bit_sub<3,2>(instr) << 7) | (bit_sub<5,1>(instr) << 6) | (bit_sub<6,1>(instr) << 4) | (signed_bit_sub<12,1>(instr) << 9); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.ADDI16SP 0x%1$05x"); + ins_fmter % (int64_t)fld_nzimm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + uint8_t x2_idx_val = 2; + Value* X_x2_idx_val = this->builder->CreateAdd( + this->gen_ext( + this->builder->CreateLoad(get_reg_ptr(x2_idx_val), false), + 32, true), + this->gen_const(32U, fld_nzimm_val)); + this->builder->CreateStore(X_x2_idx_val, get_reg_ptr(x2_idx_val), false); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction C.SRLI + std::tuple __c_srli(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.SRLI"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_shamt_val = 0 | (bit_sub<2,5>(instr)) | (bit_sub<12,1>(instr) << 5); + uint8_t fld_rs1_val = 0 | (bit_sub<7,3>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.SRLI x(8+%1$d), %2$d"); + ins_fmter % (uint64_t)fld_rs1_val % (uint64_t)fld_shamt_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + if(fld_shamt_val > 31){ + this->gen_raise_trap(0, 2); + } + uint8_t rs1_idx_val = (fld_rs1_val + 8); + Value* X_rs1_idx_val = this->builder->CreateLShr( + this->builder->CreateLoad(get_reg_ptr(rs1_idx_val), false), + this->gen_const(32U, fld_shamt_val)); + this->builder->CreateStore(X_rs1_idx_val, get_reg_ptr(rs1_idx_val), false); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction C.SRAI + std::tuple __c_srai(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.SRAI"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_shamt_val = 0 | (bit_sub<2,5>(instr)) | (bit_sub<12,1>(instr) << 5); + uint8_t fld_rs1_val = 0 | (bit_sub<7,3>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.SRAI x(8+%1$d), %2$d"); + ins_fmter % (uint64_t)fld_rs1_val % (uint64_t)fld_shamt_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + if(fld_shamt_val > 31){ + this->gen_raise_trap(0, 2); + } + uint8_t rs1_idx_val = (fld_rs1_val + 8); + Value* X_rs1_idx_val = this->builder->CreateAShr( + this->builder->CreateLoad(get_reg_ptr(rs1_idx_val), false), + this->gen_const(32U, fld_shamt_val)); + this->builder->CreateStore(X_rs1_idx_val, get_reg_ptr(rs1_idx_val), false); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction C.ANDI + std::tuple __c_andi(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.ANDI"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + int8_t fld_imm_val = 0 | (bit_sub<2,5>(instr)) | (signed_bit_sub<12,1>(instr) << 5); + uint8_t fld_rs1_val = 0 | (bit_sub<7,3>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.ANDI x(8+%1$d), 0x%2$05x"); + ins_fmter % (uint64_t)fld_rs1_val % (int64_t)fld_imm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + uint8_t rs1_idx_val = (fld_rs1_val + 8); + Value* X_rs1_idx_val = this->builder->CreateAnd( + this->builder->CreateLoad(get_reg_ptr(rs1_idx_val), false), + this->gen_const(32U, fld_imm_val)); + this->builder->CreateStore(X_rs1_idx_val, get_reg_ptr(rs1_idx_val), false); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction C.SUB + std::tuple __c_sub(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.SUB"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rs2_val = 0 | (bit_sub<2,3>(instr)); + uint8_t fld_rd_val = 0 | (bit_sub<7,3>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.SUB x(8+%1$d), x(8+%2$d)"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + uint8_t rd_idx_val = (fld_rd_val + 8); + uint8_t rs2_idx_val = (fld_rs2_val + 8); + Value* X_rd_idx_val = this->builder->CreateSub( + this->builder->CreateLoad(get_reg_ptr(rd_idx_val), false), + this->builder->CreateLoad(get_reg_ptr(rs2_idx_val), false)); + this->builder->CreateStore(X_rd_idx_val, get_reg_ptr(rd_idx_val), false); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction C.XOR + std::tuple __c_xor(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.XOR"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rs2_val = 0 | (bit_sub<2,3>(instr)); + uint8_t fld_rd_val = 0 | (bit_sub<7,3>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.XOR x(8+%1$d), x(8+%2$d)"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + uint8_t rd_idx_val = (fld_rd_val + 8); + uint8_t rs2_idx_val = (fld_rs2_val + 8); + Value* X_rd_idx_val = this->builder->CreateXor( + this->builder->CreateLoad(get_reg_ptr(rd_idx_val), false), + this->builder->CreateLoad(get_reg_ptr(rs2_idx_val), false)); + this->builder->CreateStore(X_rd_idx_val, get_reg_ptr(rd_idx_val), false); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction C.OR + std::tuple __c_or(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.OR"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rs2_val = 0 | (bit_sub<2,3>(instr)); + uint8_t fld_rd_val = 0 | (bit_sub<7,3>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.OR x(8+%1$d), x(8+%2$d)"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + uint8_t rd_idx_val = (fld_rd_val + 8); + uint8_t rs2_idx_val = (fld_rs2_val + 8); + Value* X_rd_idx_val = this->builder->CreateOr( + this->builder->CreateLoad(get_reg_ptr(rd_idx_val), false), + this->builder->CreateLoad(get_reg_ptr(rs2_idx_val), false)); + this->builder->CreateStore(X_rd_idx_val, get_reg_ptr(rd_idx_val), false); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction C.AND + std::tuple __c_and(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.AND"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rs2_val = 0 | (bit_sub<2,3>(instr)); + uint8_t fld_rd_val = 0 | (bit_sub<7,3>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.AND x(8+%1$d), x(8+%2$d)"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + uint8_t rd_idx_val = (fld_rd_val + 8); + uint8_t rs2_idx_val = (fld_rs2_val + 8); + Value* X_rd_idx_val = this->builder->CreateAnd( + this->builder->CreateLoad(get_reg_ptr(rd_idx_val), false), + this->builder->CreateLoad(get_reg_ptr(rs2_idx_val), false)); + this->builder->CreateStore(X_rd_idx_val, get_reg_ptr(rd_idx_val), false); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction C.J + std::tuple __c_j(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.J"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + int16_t fld_imm_val = 0 | (bit_sub<2,1>(instr) << 5) | (bit_sub<3,3>(instr) << 1) | (bit_sub<6,1>(instr) << 7) | (bit_sub<7,1>(instr) << 6) | (bit_sub<8,1>(instr) << 10) | (bit_sub<9,2>(instr) << 8) | (bit_sub<11,1>(instr) << 4) | (signed_bit_sub<12,1>(instr) << 11); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.J 0x%1$05x"); + ins_fmter % (int64_t)fld_imm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + Value* PC_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, fld_imm_val)); + this->builder->CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); + 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); + } + + // instruction C.BEQZ + std::tuple __c_beqz(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.BEQZ"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + int16_t fld_imm_val = 0 | (bit_sub<2,1>(instr) << 5) | (bit_sub<3,2>(instr) << 1) | (bit_sub<5,2>(instr) << 6) | (bit_sub<10,2>(instr) << 3) | (signed_bit_sub<12,1>(instr) << 8); + uint8_t fld_rs1d_val = 0 | (bit_sub<7,3>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.BEQZ x(8+%1$d), 0x%2$05x"); + ins_fmter % (uint64_t)fld_rs1d_val % (int64_t)fld_imm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + uint8_t rs1_val = (fld_rs1d_val + 8); + Value* PC_val = this->gen_choose( + this->builder->CreateICmp( + ICmpInst::ICMP_EQ, + this->builder->CreateLoad(get_reg_ptr(rs1_val), false), + this->gen_const(32U, 0)), + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, fld_imm_val)), + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, 2)), + 32); + this->builder->CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); + 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); + } + + // instruction C.BNEZ + std::tuple __c_bnez(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.BNEZ"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint16_t fld_imm_val = 0 | (bit_sub<2,1>(instr) << 5) | (bit_sub<3,2>(instr) << 1) | (bit_sub<5,2>(instr) << 6) | (bit_sub<10,2>(instr) << 3) | (bit_sub<12,1>(instr) << 8); + uint8_t fld_rs1d_val = 0 | (bit_sub<7,3>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.BNEZ x(8+%1$d),, 0x%2$05x"); + ins_fmter % (uint64_t)fld_rs1d_val % (uint64_t)fld_imm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + uint8_t rs1_val = (fld_rs1d_val + 8); + Value* PC_val = this->gen_choose( + this->builder->CreateICmp( + ICmpInst::ICMP_NE, + this->builder->CreateLoad(get_reg_ptr(rs1_val), false), + this->gen_const(32U, 0)), + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, fld_imm_val)), + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, 2)), + 32); + this->builder->CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); + 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); + } + + // instruction C.SLLI + std::tuple __c_slli(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.SLLI"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_shamt_val = 0 | (bit_sub<2,5>(instr)) | (bit_sub<12,1>(instr) << 5); + uint8_t fld_rs1_val = 0 | (bit_sub<7,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.SLLI x%1$d, %2$d"); + ins_fmter % (uint64_t)fld_rs1_val % (uint64_t)fld_shamt_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + if(fld_rs1_val == 0){ + this->gen_raise_trap(0, 2); + } + if(fld_shamt_val > 31){ + this->gen_raise_trap(0, 2); + } + Value* X_rs1_val = this->builder->CreateShl( + this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false), + this->gen_const(32U, fld_shamt_val)); + this->builder->CreateStore(X_rs1_val, get_reg_ptr(fld_rs1_val), false); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction C.LQSP + std::tuple __c_lqsp(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.LQSP"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint16_t fld_uimm_val = 0 | (bit_sub<2,4>(instr) << 6) | (bit_sub<6,1>(instr) << 4) | (bit_sub<12,1>(instr) << 5); + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + std::string opcode("C.LQSP"); + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % opcode; + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + /* TODO: describe operations for C.LQSP ! */ + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction C.LWSP + std::tuple __c_lwsp(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.LWSP"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_uimm_val = 0 | (bit_sub<2,2>(instr) << 6) | (bit_sub<4,3>(instr) << 2) | (bit_sub<12,1>(instr) << 5); + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.LWSP x%1$d, sp, 0x%2$05x"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_uimm_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + uint8_t x2_idx_val = 2; + Value* offs_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(x2_idx_val), false), + this->gen_const(32U, fld_uimm_val)); + Value* X_rd_val = this->gen_read_mem(traits::MEM, offs_val, 32/8); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction C.MV + std::tuple __c_mv(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.MV"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rs2_val = 0 | (bit_sub<2,5>(instr)); + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.MV x%1$d, x%2$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + Value* X_rd_val = this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction C.JR + std::tuple __c_jr(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.JR"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rs1_val = 0 | (bit_sub<7,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.JR x%1$d"); + ins_fmter % (uint64_t)fld_rs1_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + Value* PC_val = this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false); + this->builder->CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); + 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); + } + + // instruction C.EBREAK + std::tuple __c_ebreak(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.EBREAK"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + ; + if(this->disass_enabled){ + /* generate console output when executing the command */ + std::string opcode("C.EBREAK"); + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % opcode; + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + this->gen_raise_trap(0, 3); + 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); + } + + // instruction C.ADD + std::tuple __c_add(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.ADD"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rs2_val = 0 | (bit_sub<2,5>(instr)); + uint8_t fld_rd_val = 0 | (bit_sub<7,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.ADD x%1$d, x%2$d"); + ins_fmter % (uint64_t)fld_rd_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + Value* X_rd_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(fld_rd_val), false), + this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(fld_rd_val), false); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + + // instruction C.JALR + std::tuple __c_jalr(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.JALR"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rs1_val = 0 | (bit_sub<7,5>(instr)); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.JALR x%1$d"); + ins_fmter % (uint64_t)fld_rs1_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + uint8_t rd_val = 1; + Value* X_rd_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::PC), false), + this->gen_const(32U, 2)); + this->builder->CreateStore(X_rd_val, get_reg_ptr(rd_val), false); + Value* PC_val = this->builder->CreateLoad(get_reg_ptr(fld_rs1_val), false); + this->builder->CreateStore(PC_val, get_reg_ptr(traits::NEXT_PC), false); + 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); + } + + // instruction C.SWSP + std::tuple __c_swsp(virt_addr_t& pc, code_word_t instr, llvm::BasicBlock* bb){ + bb->setName("C.SWSP"); + + this->gen_set_pc(pc, traits::PC); + this->builder->CreateStore( + this->builder->CreateLoad(get_reg_ptr(traits::PENDING_TRAP), true), + get_reg_ptr(traits::TRAP_STATE), true); + this->builder->CreateStore( + this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(traits::ICOUNT), false), + this->gen_const(64U, 1)), + get_reg_ptr(traits::ICOUNT), false); + this->gen_sync(iss::PRE_SYNC); + + uint8_t fld_rs2_val = 0 | (bit_sub<2,5>(instr)); + uint8_t fld_uimm_val = 0 | (bit_sub<7,2>(instr) << 6) | (bit_sub<9,4>(instr) << 2); + if(this->disass_enabled){ + /* generate console output when executing the command */ + boost::format ins_fmter("C.SWSP x2+0x%1$05x, x%2$d"); + ins_fmter % (uint64_t)fld_uimm_val % (uint64_t)fld_rs2_val; + boost::format fmter("0x%1$016x\t\t%2$-40s\t\t%%v"); + fmter % pc.val % ins_fmter.str(); + std::vector args { + this->core_ptr, + this->builder->CreateGlobalStringPtr(fmter.str()) + }; + this->builder->CreateCall(this->mod->getFunction("print_disass"), args); + } + pc=pc+2; + + uint8_t x2_idx_val = 2; + Value* offs_val = this->builder->CreateAdd( + this->builder->CreateLoad(get_reg_ptr(x2_idx_val), false), + this->gen_const(32U, fld_uimm_val)); + Value* MEM_offs_val = this->builder->CreateLoad(get_reg_ptr(fld_rs2_val), false); + this->gen_write_mem( + traits::MEM, + offs_val, + this->builder->CreateZExtOrTrunc(MEM_offs_val,this->get_type(32))); + this->gen_set_pc(pc, traits::NEXT_PC); + this->gen_sync(iss::POST_SYNC); /* call post-sync if needed */ + bb = llvm::BasicBlock::Create(this->mod->getContext(), "entry", this->func, this->leave_blk); /* create next BasicBlock in chain */ + this->gen_trap_check(bb); + return std::make_tuple(vm::CONT, bb); + } + +/* end generated code */ + /**************************************************************************** + * end opcode definitions + ****************************************************************************/ + std::tuple 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(traits::XLEN, 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 minrv_ima + +#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_core(), 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_core(), dump);\ +} + +CREATE_FUNCS(arch::minrv_ima) + +namespace minrv_ima { + + 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(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& data, std::vector& avail) { + if(reg_no<65){ + //auto reg_size = arch::traits::reg_bit_width(static_cast::reg_e>(reg_no))/8; + data.resize(0); + vm->get_arch()->get_reg(reg_no, data); + avail.resize(data.size()); + std::fill(avail.begin(), avail.end(), 0xff); + } else { + typed_addr_t a(iss::DEBUG_READ, traits::CSR, reg_no-65); + data.resize(sizeof(typename traits::reg_t)); + avail.resize(sizeof(typename traits::reg_t)); + std::fill(avail.begin(), avail.end(), 0xff); + vm->get_arch()->read(a, data.size(), data.data()); + } + return data.size()>0?Ok:Err; + } + + template + status target_adapter::write_single_register(unsigned int reg_no, const std::vector& data) { + if(reg_no<65) + vm->get_arch()->set_reg(reg_no, data); + else { + typed_addr_t a(iss::DEBUG_WRITE, traits::CSR, reg_no-65); + vm->get_arch()->write(a, data.size(), data.data()); + } + return Ok; + } + + template + status target_adapter::read_mem(uint64_t addr, std::vector& data) { + auto a=map_addr({iss::DEBUG_READ, iss::VIRTUAL, 0, addr}); + auto f = [&]()->status { + return vm->get_arch()->read(a, data.size(), data.data()); + }; + return srv->execute_syncronized(f); + + } + + template + status target_adapter::write_mem(uint64_t addr, const std::vector& data) { + auto a=map_addr({iss::DEBUG_READ, iss::VIRTUAL, 0, addr}); + return srv->execute_syncronized(&arch_if::write, vm->get_arch(), a, data.size(), data.data()); + } + + template + status target_adapter::process_query(unsigned int& mask, const rp_thread_ref& arg, rp_thread_info& info) { + return NotSupported; + } + + template + status target_adapter::offsets_query(uint64_t& text, uint64_t& data, uint64_t& bss) { + text=0; + data=0; + bss=0; + return Ok; + } + + template + status target_adapter::crc_query(uint64_t addr, size_t len, uint32_t& val) { + return NotSupported; + } + + template + status target_adapter::raw_query(std::string in_buf, std::string& out_buf) { + return NotSupported; + } + + template + status target_adapter::threadinfo_query(int first, std::string& out_buf) { + if(first){ + std::stringstream ss; + ss<<"m"< + status target_adapter::threadextrainfo_query(const rp_thread_ref& thread, std::string& out_buf) { + char buf[20]; + memset(buf, 0, 20); + sprintf (buf, "%02x%02x%02x%02x%02x%02x%02x%02x%02x", 'R', 'u', 'n', 'n', 'a', 'b', 'l', 'e', 0); + out_buf=buf; + return Ok; + } + + template + status target_adapter::packetsize_query(std::string& out_buf) { + out_buf="PacketSize=1000"; + return Ok; + } + + template + status target_adapter::add_break(int type, uint64_t addr, unsigned int length) { + auto saddr=map_addr({iss::CODE, iss::PHYSICAL, addr}); + auto eaddr=map_addr({iss::CODE, iss::PHYSICAL, addr+length}); + target_adapter_base::bp_lut.addEntry(++target_adapter_base::bp_count, saddr.val, eaddr.val-saddr.val); + LOG(TRACE)<<"Adding breakpoint with handle "< + status target_adapter::remove_break(int type, uint64_t addr, unsigned int length) { + auto saddr=map_addr({iss::CODE, iss::PHYSICAL, addr}); + unsigned handle=target_adapter_base::bp_lut.getEntry(saddr.val); + // TODO: check length of addr range + if(handle){ + LOG(TRACE)<<"Removing breakpoint with handle "< + status target_adapter::resume_from_addr(bool step, int sig, uint64_t addr) { + unsigned reg_no = arch::traits::PC; + std::vector data(8); + *(reinterpret_cast(&data[0]))=addr; + vm->get_arch()->set_reg(reg_no, data); + return resume_from_current(step, sig); + } +} // namespace minrv_ima +} // namespace iss diff --git a/riscv/src/internal/vm_riscv.in.cpp b/riscv/src/internal/vm_riscv.in.cpp new file mode 100644 index 0000000..b2cfeb4 --- /dev/null +++ b/riscv/src/internal/vm_riscv.in.cpp @@ -0,0 +1,682 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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/arch/riscv_core.h" +#include "iss/debugger/server.h" + +#include + +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 + 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_mem(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_mem(this->core.v2p(pc+2), 2, data+2); + } + } else { + auto res = this->core.read_mem(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 vm::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(traits::XLEN, 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_core(), 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_core(), 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(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& data, std::vector& avail) { + if(reg_no<65){ + //auto reg_size = arch::traits::reg_bit_width(static_cast::reg_e>(reg_no))/8; + data.resize(0); + vm->get_arch()->get_reg(reg_no, data); + avail.resize(data.size()); + std::fill(avail.begin(), avail.end(), 0xff); + } else { + typed_addr_t a(iss::DEBUG_READ, traits::CSR, reg_no-65); + data.resize(sizeof(typename traits::reg_t)); + avail.resize(sizeof(typename traits::reg_t)); + std::fill(avail.begin(), avail.end(), 0xff); + vm->get_arch()->read_mem(a, data.size(), data.data()); + } + return data.size()>0?Ok:Err; + } + + template + status target_adapter::write_single_register(unsigned int reg_no, const std::vector& data) { + if(reg_no<65) + vm->get_arch()->set_reg(reg_no, data); + else { + typed_addr_t a(iss::DEBUG_WRITE, traits::CSR, reg_no-65); + vm->get_arch()->write_mem(a, data.size(), data.data()); + } + return Ok; + } + + template + status target_adapter::read_mem(uint64_t addr, std::vector& data) { + auto a=map_addr({iss::DEBUG_READ, iss::VIRTUAL, 0, addr}); + auto f = [&]()->status { + return vm->get_arch()->read_mem(a, data.size(), data.data()); + }; + return srv->execute_syncronized(f); + + } + + template + status target_adapter::write_mem(uint64_t addr, const std::vector& data) { + auto a=map_addr({iss::DEBUG_READ, iss::VIRTUAL, 0, addr}); + return srv->execute_syncronized(&arch_if::write_mem, vm->get_arch(), a, data.size(), data.data()); + } + + template + status target_adapter::process_query(unsigned int& mask, const rp_thread_ref& arg, rp_thread_info& info) { + return NotSupported; + } + + template + status target_adapter::offsets_query(uint64_t& text, uint64_t& data, uint64_t& bss) { + text=0; + data=0; + bss=0; + return Ok; + } + + template + status target_adapter::crc_query(uint64_t addr, size_t len, uint32_t& val) { + return NotSupported; + } + + template + status target_adapter::raw_query(std::string in_buf, std::string& out_buf) { + return NotSupported; + } + + template + status target_adapter::threadinfo_query(int first, std::string& out_buf) { + if(first){ + std::stringstream ss; + ss<<"m"< + status target_adapter::threadextrainfo_query(const rp_thread_ref& thread, std::string& out_buf) { + char buf[20]; + memset(buf, 0, 20); + sprintf (buf, "%02x%02x%02x%02x%02x%02x%02x%02x%02x", 'R', 'u', 'n', 'n', 'a', 'b', 'l', 'e', 0); + out_buf=buf; + return Ok; + } + + template + status target_adapter::packetsize_query(std::string& out_buf) { + out_buf="PacketSize=1000"; + return Ok; + } + + template + status target_adapter::add_break(int type, uint64_t addr, unsigned int length) { + auto saddr=map_addr({iss::CODE, iss::PHYSICAL, addr}); + auto eaddr=map_addr({iss::CODE, iss::PHYSICAL, addr+length}); + target_adapter_base::bp_lut.addEntry(++target_adapter_base::bp_count, saddr.val, eaddr.val-saddr.val); + LOG(TRACE)<<"Adding breakpoint with handle "< + status target_adapter::remove_break(int type, uint64_t addr, unsigned int length) { + auto saddr=map_addr({iss::CODE, iss::PHYSICAL, addr}); + unsigned handle=target_adapter_base::bp_lut.getEntry(saddr.val); + // TODO: check length of addr range + if(handle){ + LOG(TRACE)<<"Removing breakpoint with handle "< + status target_adapter::resume_from_addr(bool step, int sig, uint64_t addr) { + unsigned reg_no = arch::traits::PC; + std::vector data(8); + *(reinterpret_cast(&data[0]))=addr; + vm->get_arch()->set_reg(reg_no, data); + return resume_from_current(step, sig); + } +} // namespace CORE_DEF_NAME +} // namespace iss diff --git a/riscv/src/iss/minrv_ima.cpp b/riscv/src/iss/minrv_ima.cpp new file mode 100644 index 0000000..ca7d1e0 --- /dev/null +++ b/riscv/src/iss/minrv_ima.cpp @@ -0,0 +1,147 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "util/ities.h" +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +#include +#ifdef __cplusplus +} +#endif +#include +#include +#include + +using namespace iss::arch; + +minrv_ima::minrv_ima() { + reg.icount=0; +} + +minrv_ima::~minrv_ima(){ +} + +void minrv_ima::reset(uint64_t address) { + for(size_t i=0; i::NUM_REGS; ++i) set_reg(i, std::vector(sizeof(traits::reg_t),0)); + reg.PC=address; + reg.NEXT_PC=reg.PC; + reg.trap_state=0; + reg.machine_state=0x3; +} + +uint8_t* minrv_ima::get_regs_base_ptr(){ + return reinterpret_cast(®); +} + +void minrv_ima::get_reg(short idx, std::vector& value) { + if(idx::NUM_REGS){ + value.resize(traits::reg_byte_offset(idx+1)-traits::reg_byte_offset(idx)); + uint8_t* r_ptr= ((uint8_t*)®)+traits::reg_byte_offset(idx); + std::copy(r_ptr, r_ptr+sizeof(traits::reg_t), value.begin()); + } +} + +void minrv_ima::set_reg(short idx, const std::vector& value) { + if(idx < traits::NUM_REGS){ + uint8_t* r_ptr= ((uint8_t*)®)+traits::reg_byte_offset(idx); + std::copy(value.begin(), value.end(), r_ptr); + } +} + +bool minrv_ima::get_flag(int flag){ + return false; +} + +void minrv_ima::set_flag(int flag, bool value){ +} + +void minrv_ima::update_flags(operations op, uint64_t r0, uint64_t r1){ +} + +minrv_ima::phys_addr_t minrv_ima::v2p(const iss::addr_t& pc) { + return phys_addr_t(pc); //change logical address to physical address +} + +using namespace ELFIO; + +/* +void minrv_ima::loadFile(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 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"); + auto sec_num = reader.sections.size(); + auto seg_num = reader.segments.size(); + for ( int i = 0; i < seg_num; ++i ) { + const auto pseg = reader.segments[i]; + 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)); + } + } + } else { + fseek(fp, 0, SEEK_SET); + if(type<0) throw std::runtime_error("a memory type needs to be specified for IHEX files"); + IHexRecord irec; + while (Read_IHexRecord(&irec, fp) == IHEX_OK) { + this->write(typed_addr_t(iss::DEBUG_WRITE, type, irec.address), irec.dataLen, irec.data); + } + } + } else { + LOG(ERROR)<<"Could not open input file "< +#include +#include + +#include +#ifndef WITHOUT_LLVM +#include +#endif +#ifdef WITH_SYSTEMC +#include +#endif +#include + +namespace po= boost::program_options; + +INITIALIZE_EASYLOGGINGPP + +int main(int argc, char *argv[]) { + try{ + /** Define and parse the program options + */ + po::variables_map vm; + if(parse_cli_options(vm, argc, argv)) return ERROR_IN_COMMAND_LINE; + configure_default_logger(vm); + // configure the connection logger + configure_debugger_logger(); + + // application code comes here // + iss::init_jit(argc, argv); + if(vm.count("systemc")){ +//#ifdef WITH_SYSTEMC +// return sc_core::sc_elab_and_sim(argc, argv); +//#else + std::cerr<<"SystemC simulation is currently not supported, please rebuild with -DWITH_SYSTEMC"< cpu = vm.count("gdb-port")? + iss::create("rv32ima", vm["gdb-port"].as(), dump): + iss::create("rv32ima", dump); + if(vm.count("elf")){ + for(std::string input: vm["elf"].as >()) + cpu->get_arch()->load_file(input); + } else if(vm.count("mem")){ + cpu->get_arch()->load_file(vm["mem"].as() , iss::arch::traits::MEM); + } //else + // LOG(FATAL)<<"At least one (flash-)input file (ELF or IHEX) needs to be specified"; + + configure_disass_logger(vm); + if(vm.count("disass")){ + cpu->setDisassEnabled(true); + } + if(vm.count("reset")){ + auto str = vm["reset"].as(); + auto start_address = str.find("0x")==0? std::stoull(str, 0, 16):std::stoull(str, 0, 10); + cpu->reset(start_address); + } else { + cpu->reset(); + } + return cpu->start(vm["cycles"].as()); + } + } catch(std::exception& e){ + LOG(ERROR) << "Unhandled Exception reached the top of main: " + << e.what() << ", application will now exit" << std::endl; + return ERROR_UNHANDLED_EXCEPTION; + } +} diff --git a/riscv/src/minres_rv.core_desc b/riscv/src/minres_rv.core_desc new file mode 100644 index 0000000..b2af3aa --- /dev/null +++ b/riscv/src/minres_rv.core_desc @@ -0,0 +1,38 @@ +import "RV32IBase.core_desc" +import "RV32M.core_desc" +import "RV32A.core_desc" +import "RV32C.core_desc" +//import "RV64IBase.core_desc" +//import "RV64M.core_desc" +//import "RV64A.core_desc" + +Core MinRV_IMA provides RV32IBase,RV32M,RV32A, RV32CI { + template:"vm_riscv.in.cpp"; + constants { + XLEN:=32; + XLEN2:=64; + XLEN_BIT_MASK:=0x1f; + PCLEN:=32; + fence:=0; + fencei:=1; + fencevmal:=2; + fencevmau:=3; + // XL ZYXWVUTSRQPONMLKJIHGFEDCBA + MISA_VAL:=0b01000000000101000001000100000001; + PGSIZE := 4096; //1 << 12; + PGMASK := 4095; //PGSIZE-1 + } +} + +/* +Core RV64IMA provides RV64IBase, RV64M, RV64A { + template:"vm_riscv.in.cpp"; + constants { + XLEN:=64; + XLEN_BIT_MASK:=0x3f; + PCLEN:=64; + fence:=0; + fencei:=1; + } +} +*/ \ No newline at end of file diff --git a/sc-components b/sc-components new file mode 160000 index 0000000..872788c --- /dev/null +++ b/sc-components @@ -0,0 +1 @@ +Subproject commit 872788c447696f228a817f7cd38746d412ebb537