mirror of
https://notabug.org/litucks/torzu.git
synced 2025-04-24 09:05:13 +00:00
Stripped down more code (does not compile)
This commit is contained in:
parent
36bd6ada75
commit
927028d276
15
.gitmodules
vendored
15
.gitmodules
vendored
@ -7,30 +7,18 @@
|
||||
[submodule "cubeb"]
|
||||
path = externals/cubeb
|
||||
url = https://github.com/mozilla/cubeb.git
|
||||
[submodule "libusb"]
|
||||
path = externals/libusb/libusb
|
||||
url = https://github.com/libusb/libusb.git
|
||||
[submodule "xbyak"]
|
||||
path = externals/xbyak
|
||||
url = https://github.com/herumi/xbyak.git
|
||||
[submodule "opus"]
|
||||
path = externals/opus
|
||||
url = https://github.com/xiph/opus.git
|
||||
[submodule "SDL"]
|
||||
path = externals/SDL
|
||||
url = https://github.com/libsdl-org/SDL.git
|
||||
[submodule "cpp-httplib"]
|
||||
path = externals/cpp-httplib
|
||||
url = https://github.com/yhirose/cpp-httplib.git
|
||||
[submodule "ffmpeg"]
|
||||
path = externals/ffmpeg/ffmpeg
|
||||
url = https://github.com/FFmpeg/FFmpeg.git
|
||||
[submodule "vcpkg"]
|
||||
path = externals/vcpkg
|
||||
url = https://github.com/microsoft/vcpkg.git
|
||||
[submodule "cpp-jwt"]
|
||||
path = externals/cpp-jwt
|
||||
url = https://github.com/arun11299/cpp-jwt.git
|
||||
[submodule "libadrenotools"]
|
||||
path = externals/libadrenotools
|
||||
url = https://github.com/bylaws/libadrenotools.git
|
||||
@ -49,3 +37,6 @@
|
||||
[submodule "externals/boost-headers"]
|
||||
path = externals/boost-headers
|
||||
url = https://github.com/boostorg/headers.git
|
||||
[submodule "externals/etl"]
|
||||
path = externals/etl
|
||||
url = https://github.com/ETLCPP/etl.git
|
||||
|
@ -15,17 +15,10 @@ include(CTest)
|
||||
# Set bundled sdl2/qt as dependent options.
|
||||
# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON
|
||||
option(ENABLE_SDL2 "Enable the SDL2 frontend" ON)
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" ON "ENABLE_SDL2;MSVC" OFF)
|
||||
# On Linux system SDL2 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_USE_EXTERNAL_SDL2 "Compile external SDL2" ON "ENABLE_SDL2;NOT MSVC" OFF)
|
||||
|
||||
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "NOT ANDROID" OFF)
|
||||
|
||||
option(ENABLE_OPENGL "Enable OpenGL" ON)
|
||||
mark_as_advanced(FORCE ENABLE_OPENGL)
|
||||
|
||||
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
|
||||
|
||||
option(YUZU_USE_BUNDLED_FFMPEG "Download/Build bundled FFmpeg" "${WIN32}")
|
||||
|
||||
option(YUZU_USE_EXTERNAL_VULKAN_HEADERS "Use Vulkan-Headers from externals" ON)
|
||||
@ -46,8 +39,6 @@ option(YUZU_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON)
|
||||
|
||||
option(YUZU_DOWNLOAD_ANDROID_VVL "Download validation layer binary for android" ON)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_ROOM "Compile LDN room server" ON "NOT ANDROID" OFF)
|
||||
|
||||
CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR LINUX" OFF)
|
||||
|
||||
option(YUZU_USE_BUNDLED_VCPKG "Use vcpkg for yuzu dependencies" "${MSVC}")
|
||||
@ -135,9 +126,6 @@ if (YUZU_USE_BUNDLED_VCPKG)
|
||||
if (YUZU_TESTS)
|
||||
list(APPEND VCPKG_MANIFEST_FEATURES "yuzu-tests")
|
||||
endif()
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
list(APPEND VCPKG_MANIFEST_FEATURES "web-service")
|
||||
endif()
|
||||
if (ANDROID)
|
||||
list(APPEND VCPKG_MANIFEST_FEATURES "android")
|
||||
endif()
|
||||
@ -154,7 +142,6 @@ if (YUZU_USE_PRECOMPILED_HEADERS)
|
||||
# buildcache does not properly cache PCH files, leading to compilation errors.
|
||||
# See https://github.com/mbitsnbites/buildcache/discussions/230
|
||||
message(WARNING "buildcache does not properly support Precompiled Headers. Disabling PCH")
|
||||
set(DYNARMIC_USE_PRECOMPILED_HEADERS OFF CACHE BOOL "" FORCE)
|
||||
set(YUZU_USE_PRECOMPILED_HEADERS OFF CACHE BOOL "" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
@ -277,7 +264,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
|
||||
# =======================================================================
|
||||
|
||||
# Enforce the search mode of non-required packages for better and shorter failure messages
|
||||
find_package(enet 1.3 MODULE)
|
||||
find_package(fmt 9 REQUIRED)
|
||||
find_package(LLVM 17.0.2 MODULE COMPONENTS Demangle)
|
||||
find_package(lz4 REQUIRED)
|
||||
@ -298,10 +284,6 @@ if (NOT YUZU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES)
|
||||
find_package(VulkanUtilityLibraries REQUIRED)
|
||||
endif()
|
||||
|
||||
if (ENABLE_LIBUSB)
|
||||
find_package(libusb 1.0.24 MODULE)
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64)
|
||||
find_package(xbyak 7 CONFIG)
|
||||
endif()
|
||||
@ -310,10 +292,6 @@ if (ARCHITECTURE_arm64)
|
||||
find_package(oaknut 2.0.1 CONFIG)
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
||||
find_package(dynarmic 6.4.0 CONFIG)
|
||||
endif()
|
||||
|
||||
if (ENABLE_CUBEB)
|
||||
find_package(cubeb CONFIG)
|
||||
endif()
|
||||
@ -322,11 +300,6 @@ if (USE_DISCORD_PRESENCE)
|
||||
find_package(DiscordRPC MODULE)
|
||||
endif()
|
||||
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
find_package(cpp-jwt 1.4 CONFIG)
|
||||
find_package(httplib 0.12 MODULE COMPONENTS OpenSSL)
|
||||
endif()
|
||||
|
||||
if (YUZU_TESTS)
|
||||
find_package(Catch2 3.0.1 REQUIRED)
|
||||
endif()
|
||||
@ -359,31 +332,7 @@ endfunction(set_yuzu_qt_components)
|
||||
|
||||
# find SDL2 exports a bunch of variables that are needed, so its easier to do this outside of the yuzu_find_package
|
||||
if (ENABLE_SDL2)
|
||||
if (YUZU_USE_BUNDLED_SDL2)
|
||||
# Detect toolchain and platform
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64)
|
||||
set(SDL2_VER "SDL2-2.28.2")
|
||||
else()
|
||||
message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.")
|
||||
endif()
|
||||
|
||||
if (DEFINED SDL2_VER)
|
||||
download_bundled_external("sdl2/" ${SDL2_VER} SDL2_PREFIX)
|
||||
endif()
|
||||
|
||||
set(SDL2_FOUND YES)
|
||||
set(SDL2_INCLUDE_DIR "${SDL2_PREFIX}/include" CACHE PATH "Path to SDL2 headers")
|
||||
set(SDL2_LIBRARY "${SDL2_PREFIX}/lib/x64/SDL2.lib" CACHE PATH "Path to SDL2 library")
|
||||
set(SDL2_DLL_DIR "${SDL2_PREFIX}/lib/x64/" CACHE PATH "Path to SDL2.dll")
|
||||
|
||||
add_library(SDL2::SDL2 INTERFACE IMPORTED)
|
||||
target_link_libraries(SDL2::SDL2 INTERFACE "${SDL2_LIBRARY}")
|
||||
target_include_directories(SDL2::SDL2 INTERFACE "${SDL2_INCLUDE_DIR}")
|
||||
elseif (YUZU_USE_EXTERNAL_SDL2)
|
||||
message(STATUS "Using SDL2 from externals.")
|
||||
else()
|
||||
find_package(SDL2 2.26.4 REQUIRED)
|
||||
endif()
|
||||
find_package(SDL2 2.26.4 REQUIRED)
|
||||
endif()
|
||||
|
||||
# List of all FFmpeg components required
|
||||
|
71
externals/CMakeLists.txt
vendored
71
externals/CMakeLists.txt
vendored
@ -1,10 +1,6 @@
|
||||
# SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
# Dynarmic has cmake_minimum_required(3.12) and we may want to override
|
||||
# some of its variables, which is only possible in 3.13+
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
|
||||
|
||||
# Disable tests in all externals supporting the standard option name
|
||||
set(BUILD_TESTING OFF)
|
||||
|
||||
@ -24,30 +20,14 @@ if (ARCHITECTURE_arm64 AND NOT TARGET merry::oaknut)
|
||||
add_subdirectory(oaknut)
|
||||
endif()
|
||||
|
||||
# Dynarmic
|
||||
if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) AND NOT TARGET dynarmic::dynarmic)
|
||||
set(DYNARMIC_IGNORE_ASSERTS ON)
|
||||
add_subdirectory(dynarmic)
|
||||
add_library(dynarmic::dynarmic ALIAS dynarmic)
|
||||
endif()
|
||||
# Boost headers
|
||||
add_subdirectory(boost-headers)
|
||||
|
||||
# getopt
|
||||
if (MSVC)
|
||||
add_subdirectory(getopt)
|
||||
endif()
|
||||
|
||||
# Glad
|
||||
add_subdirectory(glad)
|
||||
|
||||
# mbedtls
|
||||
add_subdirectory(mbedtls)
|
||||
target_include_directories(mbedtls PUBLIC ./mbedtls/include)
|
||||
if (NOT MSVC)
|
||||
target_compile_options(mbedcrypto PRIVATE
|
||||
-Wno-unused-but-set-variable
|
||||
-Wno-string-concatenation)
|
||||
endif()
|
||||
|
||||
# MicroProfile
|
||||
add_library(microprofile INTERFACE)
|
||||
target_include_directories(microprofile INTERFACE ./microprofile)
|
||||
@ -57,35 +37,6 @@ if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12" AND CMAKE_CXX_COMPILER
|
||||
target_compile_options(microprofile INTERFACE "-Wno-array-bounds")
|
||||
endif()
|
||||
|
||||
# libusb
|
||||
if (ENABLE_LIBUSB AND NOT TARGET libusb::usb)
|
||||
add_subdirectory(libusb)
|
||||
endif()
|
||||
|
||||
# SDL2
|
||||
if (YUZU_USE_EXTERNAL_SDL2)
|
||||
if (NOT WIN32)
|
||||
# Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers
|
||||
# Since 2.0.18 Atomic+Threads required for HIDAPI/libusb (see https://github.com/libsdl-org/SDL/issues/5095)
|
||||
# Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
|
||||
# CPUinfo also required for SDL Audio, at least until 2.28.0 (see https://github.com/libsdl-org/SDL/issues/7809)
|
||||
set(SDL_UNUSED_SUBSYSTEMS
|
||||
File Filesystem
|
||||
Locale Power Render)
|
||||
foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
|
||||
string(TOUPPER ${_SUB} _OPT)
|
||||
set(SDL_${_OPT} OFF)
|
||||
endforeach()
|
||||
|
||||
set(HIDAPI ON)
|
||||
endif()
|
||||
if (APPLE)
|
||||
set(SDL_FILE ON)
|
||||
endif()
|
||||
|
||||
add_subdirectory(SDL)
|
||||
endif()
|
||||
|
||||
# ENet
|
||||
if (NOT TARGET enet::enet)
|
||||
add_subdirectory(enet)
|
||||
@ -118,20 +69,6 @@ endif()
|
||||
# Sirit
|
||||
add_subdirectory(sirit)
|
||||
|
||||
# httplib
|
||||
if (ENABLE_WEB_SERVICE AND NOT TARGET httplib::httplib)
|
||||
set(HTTPLIB_REQUIRE_OPENSSL ON)
|
||||
add_subdirectory(cpp-httplib)
|
||||
endif()
|
||||
|
||||
# cpp-jwt
|
||||
if (ENABLE_WEB_SERVICE AND NOT TARGET cpp-jwt::cpp-jwt)
|
||||
set(CPP_JWT_BUILD_EXAMPLES OFF)
|
||||
set(CPP_JWT_BUILD_TESTS OFF)
|
||||
set(CPP_JWT_USE_VENDORED_NLOHMANN_JSON OFF)
|
||||
add_subdirectory(cpp-jwt)
|
||||
endif()
|
||||
|
||||
# Opus
|
||||
if (NOT TARGET Opus::opus)
|
||||
set(OPUS_BUILD_TESTING OFF)
|
||||
@ -150,8 +87,8 @@ if (YUZU_USE_BUNDLED_FFMPEG)
|
||||
set(FFmpeg_INCLUDE_DIR "${FFmpeg_INCLUDE_DIR}" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
# Boost headers
|
||||
add_subdirectory(boost-headers)
|
||||
# Embedded template library
|
||||
add_subdirectory(etl)
|
||||
|
||||
# TZDB (Time Zone Database)
|
||||
add_subdirectory(nx_tzdb)
|
||||
|
1
externals/SDL
vendored
1
externals/SDL
vendored
@ -1 +0,0 @@
|
||||
Subproject commit cc016b0046d563287f0aa9f09b958b5e70d43696
|
1
externals/cpp-httplib
vendored
1
externals/cpp-httplib
vendored
@ -1 +0,0 @@
|
||||
Subproject commit a609330e4c6374f741d3b369269f7848255e1954
|
1
externals/cpp-jwt
vendored
1
externals/cpp-jwt
vendored
@ -1 +0,0 @@
|
||||
Subproject commit 10ef5735d842b31025f1257ae78899f50a40fb14
|
215
externals/dynarmic/.clang-format
vendored
215
externals/dynarmic/.clang-format
vendored
@ -1,215 +0,0 @@
|
||||
---
|
||||
Language: Cpp
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveMacros: None
|
||||
AlignConsecutiveAssignments: None
|
||||
AlignConsecutiveBitFields: None
|
||||
AlignConsecutiveDeclarations: None
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: AlignAfterOperator
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
AttributeMacros:
|
||||
- __capability
|
||||
BinPackArguments: true
|
||||
BinPackParameters: false
|
||||
BitFieldColonSpacing: Both
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: false
|
||||
BreakBeforeBinaryOperators: All
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeConceptDeclarations: true
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakConstructorInitializersBeforeComma: true
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakInheritanceList: BeforeComma
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 0
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 8
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
# EmptyLineAfterAccessModifier: Leave
|
||||
EmptyLineBeforeAccessModifier: Always
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '^<mach/'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '^<windows.h>'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '(^<signal.h>)|(^<sys/ucontext.h>)|(^<ucontext.h>)'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '^<([^\.])*>$'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '^<.*\.'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '.*'
|
||||
Priority: 4
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
# IndentAccessModifiers: false
|
||||
IndentCaseBlocks: false
|
||||
IndentCaseLabels: false
|
||||
IndentExternBlock: NoIndent
|
||||
IndentGotoLabels: false
|
||||
IndentPPDirectives: AfterHash
|
||||
IndentRequires: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
# InsertTrailingCommas: None
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
NamespaceMacros:
|
||||
ObjCBinPackProtocolList: Never
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCBreakBeforeNestedBlockParam: true
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 1
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 200
|
||||
PenaltyIndentedWhitespace: 0
|
||||
PointerAlignment: Left
|
||||
RawStringFormats:
|
||||
- Language: Cpp
|
||||
Delimiters:
|
||||
- cc
|
||||
- CC
|
||||
- cpp
|
||||
- Cpp
|
||||
- CPP
|
||||
- 'c++'
|
||||
- 'C++'
|
||||
CanonicalDelimiter: ''
|
||||
BasedOnStyle: google
|
||||
- Language: TextProto
|
||||
Delimiters:
|
||||
- pb
|
||||
- PB
|
||||
- proto
|
||||
- PROTO
|
||||
EnclosingFunctions:
|
||||
- EqualsProto
|
||||
- EquivToProto
|
||||
- PARSE_PARTIAL_TEXT_PROTO
|
||||
- PARSE_TEST_PROTO
|
||||
- PARSE_TEXT_PROTO
|
||||
- ParseTextOrDie
|
||||
- ParseTextProtoOrDie
|
||||
- ParseTestProto
|
||||
- ParsePartialTestProto
|
||||
CanonicalDelimiter: ''
|
||||
BasedOnStyle: google
|
||||
ReflowComments: true
|
||||
# ShortNamespaceLines: 5
|
||||
SortIncludes: true
|
||||
SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceBeforeSquareBrackets: false
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 2
|
||||
SpacesInAngles: false
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: false
|
||||
# SpacesInLineCommentPrefix: -1
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Latest
|
||||
StatementAttributeLikeMacros:
|
||||
- Q_EMIT
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 4
|
||||
TypenameMacros:
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
WhitespaceSensitiveMacros:
|
||||
- STRINGIZE
|
||||
- PP_STRINGIZE
|
||||
- BOOST_PP_STRINGIZE
|
||||
- NS_SWIFT_NAME
|
||||
- CF_SWIFT_NAME
|
||||
- FCODE
|
||||
- ICODE
|
||||
...
|
||||
|
158
externals/dynarmic/.github/workflows/aarch64.yml
vendored
158
externals/dynarmic/.github/workflows/aarch64.yml
vendored
@ -1,158 +0,0 @@
|
||||
name: AArch64
|
||||
|
||||
on: [ push, pull_request ]
|
||||
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
|
||||
jobs:
|
||||
build_linux:
|
||||
strategy:
|
||||
matrix:
|
||||
platform: [ linux, android ]
|
||||
fail-fast: false
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
- name: Install build dependencies
|
||||
run: >
|
||||
sudo apt-get update &&
|
||||
sudo apt-get install
|
||||
gcc-10-aarch64-linux-gnu
|
||||
g++-10-aarch64-linux-gnu
|
||||
ninja-build
|
||||
qemu-user
|
||||
|
||||
- name: Checkout dynarmic repo
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Ccache
|
||||
if: matrix.platform == 'linux'
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
|
||||
- name: Checkout ext-boost repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: MerryMage/ext-boost
|
||||
path: externals/ext-boost
|
||||
|
||||
- name: Configure CMake for AArch64 (Linux)
|
||||
if: matrix.platform == 'linux'
|
||||
env:
|
||||
CC: aarch64-linux-gnu-gcc-10
|
||||
CXX: aarch64-linux-gnu-g++-10
|
||||
run: >
|
||||
cmake
|
||||
-B ${{github.workspace}}/build-arm64
|
||||
-DBOOST_INCLUDEDIR=${{github.workspace}}/externals/ext-boost
|
||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||
-DDYNARMIC_TESTS_USE_UNICORN=0
|
||||
-DDYNARMIC_USE_LLVM=0
|
||||
-G Ninja
|
||||
|
||||
- name: Configure CMake for AArch64 (Android)
|
||||
if: matrix.platform == 'android'
|
||||
run: >
|
||||
cmake
|
||||
-B ${{github.workspace}}/build-arm64
|
||||
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake
|
||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||
-DANDROID_ABI=arm64-v8a
|
||||
-DANDROID_PLATFORM=29
|
||||
-DBoost_INCLUDE_DIR=${{github.workspace}}/externals/ext-boost
|
||||
-DDYNARMIC_TESTS_USE_UNICORN=0
|
||||
-DDYNARMIC_USE_LLVM=0
|
||||
-G Ninja
|
||||
|
||||
- name: Build AArch64
|
||||
working-directory: ${{github.workspace}}/build-arm64
|
||||
run: cmake --build . --config Release
|
||||
|
||||
- name: Configure CMake for x86_64
|
||||
if: matrix.platform == 'linux'
|
||||
env:
|
||||
CC: gcc-10
|
||||
CXX: g++-10
|
||||
run: >
|
||||
cmake
|
||||
-B ${{github.workspace}}/build-x64
|
||||
-DBOOST_INCLUDEDIR=${{github.workspace}}/externals/ext-boost
|
||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||
-DDYNARMIC_TESTS_USE_UNICORN=0
|
||||
-DDYNARMIC_USE_LLVM=0
|
||||
-G Ninja
|
||||
|
||||
- name: Build x86_64
|
||||
if: matrix.platform == 'linux'
|
||||
working-directory: ${{github.workspace}}/build-x64
|
||||
run: cmake --build . --config Release
|
||||
|
||||
- name: Basic tests
|
||||
if: matrix.platform == 'linux'
|
||||
working-directory: ${{github.workspace}}
|
||||
run: qemu-aarch64 -L /usr/aarch64-linux-gnu ./build-arm64/tests/dynarmic_tests -d yes
|
||||
|
||||
- name: Test against x86_64 implementation (A32, thumb)
|
||||
if: matrix.platform == 'linux'
|
||||
working-directory: ${{github.workspace}}
|
||||
run: |
|
||||
diff <(qemu-aarch64 -L /usr/aarch64-linux-gnu ./build-arm64/tests/dynarmic_test_generator thumb 42 1 100000) <(./build-x64/tests/dynarmic_test_generator thumb 42 1 100000)
|
||||
diff <(qemu-aarch64 -L /usr/aarch64-linux-gnu ./build-arm64/tests/dynarmic_test_generator thumb 42 10 10000) <(./build-x64/tests/dynarmic_test_generator thumb 42 10 10000)
|
||||
diff <(qemu-aarch64 -L /usr/aarch64-linux-gnu ./build-arm64/tests/dynarmic_test_generator thumb 42 100 1000) <(./build-x64/tests/dynarmic_test_generator thumb 42 100 1000)
|
||||
|
||||
- name: Test against x86_64 implementation (A32, arm)
|
||||
if: matrix.platform == 'linux'
|
||||
working-directory: ${{github.workspace}}
|
||||
run: |
|
||||
diff <(qemu-aarch64 -L /usr/aarch64-linux-gnu ./build-arm64/tests/dynarmic_test_generator arm 42 1 100000) <(./build-x64/tests/dynarmic_test_generator arm 42 1 100000)
|
||||
diff <(qemu-aarch64 -L /usr/aarch64-linux-gnu ./build-arm64/tests/dynarmic_test_generator arm 42 10 10000) <(./build-x64/tests/dynarmic_test_generator arm 42 10 10000)
|
||||
diff <(qemu-aarch64 -L /usr/aarch64-linux-gnu ./build-arm64/tests/dynarmic_test_generator arm 42 100 1000) <(./build-x64/tests/dynarmic_test_generator arm 42 100 1000)
|
||||
|
||||
- name: Test against x86_64 implementation (A64)
|
||||
if: matrix.platform == 'linux'
|
||||
working-directory: ${{github.workspace}}
|
||||
run: |
|
||||
diff <(qemu-aarch64 -L /usr/aarch64-linux-gnu ./build-arm64/tests/dynarmic_test_generator a64 42 1 100000) <(./build-x64/tests/dynarmic_test_generator a64 42 1 100000)
|
||||
diff <(qemu-aarch64 -L /usr/aarch64-linux-gnu ./build-arm64/tests/dynarmic_test_generator a64 42 10 10000) <(./build-x64/tests/dynarmic_test_generator a64 42 10 10000)
|
||||
diff <(qemu-aarch64 -L /usr/aarch64-linux-gnu ./build-arm64/tests/dynarmic_test_generator a64 42 100 1000) <(./build-x64/tests/dynarmic_test_generator a64 42 100 1000)
|
||||
|
||||
build_windows:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
|
||||
- name: Checkout dynarmic repo
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Checkout ext-boost repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: MerryMage/ext-boost
|
||||
path: externals/ext-boost
|
||||
|
||||
- name: Setup msvc-arm64 environment
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
arch: amd64_arm64
|
||||
|
||||
- name: Configure CMake for AArch64 (Windows)
|
||||
run: >
|
||||
cmake
|
||||
-B ${{github.workspace}}/build-arm64
|
||||
-DBOOST_INCLUDEDIR=${{github.workspace}}/externals/ext-boost
|
||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||
-DDYNARMIC_WARNINGS_AS_ERRORS=0
|
||||
-DDYNARMIC_TESTS_USE_UNICORN=0
|
||||
-DDYNARMIC_USE_LLVM=0
|
||||
-G Ninja
|
||||
|
||||
- name: Build AArch64
|
||||
working-directory: ${{github.workspace}}/build-arm64
|
||||
run: cmake --build . --config Release
|
@ -1,18 +0,0 @@
|
||||
name: clang-format
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
clang-format:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
- name: Checkout dynarmic repo
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- uses: DoozyX/clang-format-lint-action@v0.15
|
||||
with:
|
||||
source: 'src tests'
|
||||
clangFormatVersion: 15
|
@ -1,46 +0,0 @@
|
||||
name: multiarch
|
||||
|
||||
on: [ push, pull_request ]
|
||||
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
brew install ninja
|
||||
echo "/usr/local/opt/llvm/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Checkout dynarmic repo
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Checkout ext-boost repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: MerryMage/ext-boost
|
||||
path: externals/ext-boost
|
||||
|
||||
- name: Configure CMake
|
||||
run: >
|
||||
cmake
|
||||
-B ${{github.workspace}}/build
|
||||
-DBOOST_INCLUDEDIR=${{github.workspace}}/externals/ext-boost
|
||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||
-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
|
||||
-G Ninja
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: cmake --build . --config Release
|
||||
|
||||
- name: Test
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: ctest --extra-verbose -C ${{env.BUILD_TYPE}}
|
63
externals/dynarmic/.github/workflows/riscv64.yml
vendored
63
externals/dynarmic/.github/workflows/riscv64.yml
vendored
@ -1,63 +0,0 @@
|
||||
name: RISCV64
|
||||
|
||||
on: [ push, pull_request ]
|
||||
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
|
||||
jobs:
|
||||
build_linux:
|
||||
strategy:
|
||||
matrix:
|
||||
platform: [ linux ]
|
||||
fail-fast: false
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
- name: Install build dependencies
|
||||
run: >
|
||||
sudo apt-get update &&
|
||||
sudo apt-get install
|
||||
gcc-10-riscv64-linux-gnu
|
||||
g++-10-riscv64-linux-gnu
|
||||
ninja-build
|
||||
qemu-user
|
||||
|
||||
- name: Checkout dynarmic repo
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Ccache
|
||||
if: matrix.platform == 'linux'
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
|
||||
- name: Checkout ext-boost repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: MerryMage/ext-boost
|
||||
path: externals/ext-boost
|
||||
|
||||
- name: Configure CMake for RISCV64 (Linux)
|
||||
if: matrix.platform == 'linux'
|
||||
env:
|
||||
CC: riscv64-linux-gnu-gcc-10
|
||||
CXX: riscv64-linux-gnu-g++-10
|
||||
run: >
|
||||
cmake
|
||||
-B ${{github.workspace}}/build-riscv64
|
||||
-DBOOST_INCLUDEDIR=${{github.workspace}}/externals/ext-boost
|
||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||
-DDYNARMIC_TESTS_USE_UNICORN=0
|
||||
-DDYNARMIC_USE_LLVM=0
|
||||
-DDYNARMIC_FRONTENDS=A32
|
||||
-G Ninja
|
||||
|
||||
- name: Build RISCV64
|
||||
working-directory: ${{github.workspace}}/build-riscv64
|
||||
run: cmake --build . --config Release
|
||||
|
||||
# - name: Basic tests
|
||||
# if: matrix.platform == 'linux'
|
||||
# working-directory: ${{github.workspace}}
|
||||
# run: qemu-riscv64 -L /usr/riscv64-linux-gnu ./build-riscv64/tests/dynarmic_tests -d yes
|
102
externals/dynarmic/.github/workflows/x86-64.yml
vendored
102
externals/dynarmic/.github/workflows/x86-64.yml
vendored
@ -1,102 +0,0 @@
|
||||
name: x86-64
|
||||
|
||||
on: [ push, pull_request ]
|
||||
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ windows-latest, ubuntu-latest, macos-latest ]
|
||||
cpu_detection: [ 0, 1 ]
|
||||
fail-fast: false
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
|
||||
- name: Install build dependencies
|
||||
if: ${{matrix.os == 'ubuntu-latest'}}
|
||||
run: sudo apt-get install llvm ninja-build
|
||||
|
||||
- name: Install build dependencies
|
||||
if: ${{matrix.os == 'macos-latest'}}
|
||||
run: |
|
||||
brew install llvm ninja
|
||||
echo "/usr/local/opt/llvm/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Checkout dynarmic repo
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Checkout ext-boost repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: MerryMage/ext-boost
|
||||
path: externals/ext-boost
|
||||
|
||||
- name: Checkout unicorn repo
|
||||
if: ${{matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest'}}
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: MerryMage/unicorn
|
||||
path: externals/unicorn
|
||||
|
||||
- name: Build unicorn
|
||||
if: ${{matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest'}}
|
||||
working-directory: externals/unicorn
|
||||
run: UNICORN_ARCHS=aarch64,arm ./make.sh
|
||||
|
||||
- name: Configure CMake
|
||||
if: ${{matrix.os == 'ubuntu-latest'}}
|
||||
env:
|
||||
CC: gcc-10
|
||||
CXX: g++-10
|
||||
CXXFLAGS: -Wp,-D_GLIBCXX_ASSERTIONS
|
||||
run: >
|
||||
cmake
|
||||
-B ${{github.workspace}}/build
|
||||
-DBOOST_INCLUDEDIR=${{github.workspace}}/externals/ext-boost
|
||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||
-DDYNARMIC_ENABLE_CPU_FEATURE_DETECTION=${{matrix.cpu_detection}}
|
||||
-DDYNARMIC_TESTS_USE_UNICORN=1
|
||||
-DDYNARMIC_USE_LLVM=1
|
||||
-DLIBUNICORN_INCLUDE_DIR=${{github.workspace}}/externals/unicorn/include
|
||||
-DLIBUNICORN_LIBRARY=${{github.workspace}}/externals/unicorn/libunicorn.a
|
||||
-G Ninja
|
||||
|
||||
- name: Configure CMake
|
||||
if: ${{matrix.os == 'macos-latest'}}
|
||||
run: >
|
||||
cmake
|
||||
-B ${{github.workspace}}/build
|
||||
-DBOOST_INCLUDEDIR=${{github.workspace}}/externals/ext-boost
|
||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||
-DDYNARMIC_ENABLE_CPU_FEATURE_DETECTION=${{matrix.cpu_detection}}
|
||||
-DDYNARMIC_TESTS_USE_UNICORN=1
|
||||
-DDYNARMIC_USE_LLVM=1
|
||||
-DLIBUNICORN_INCLUDE_DIR=${{github.workspace}}/externals/unicorn/include
|
||||
-DLIBUNICORN_LIBRARY=${{github.workspace}}/externals/unicorn/libunicorn.a
|
||||
-G Ninja
|
||||
|
||||
- name: Configure CMake
|
||||
if: ${{matrix.os == 'windows-latest'}}
|
||||
run: >
|
||||
cmake
|
||||
-B ${{github.workspace}}/build
|
||||
-DBOOST_INCLUDEDIR=${{github.workspace}}/externals/ext-boost
|
||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||
-DDYNARMIC_ENABLE_CPU_FEATURE_DETECTION=${{matrix.cpu_detection}}
|
||||
-G "Visual Studio 17 2022"
|
||||
-A x64
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: cmake --build . --config Release
|
||||
|
||||
- name: Test
|
||||
env:
|
||||
DYLD_FALLBACK_LIBRARY_PATH: ${{github.workspace}}/externals/unicorn
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: ctest --extra-verbose -C ${{env.BUILD_TYPE}}
|
12
externals/dynarmic/.gitignore
vendored
12
externals/dynarmic/.gitignore
vendored
@ -1,12 +0,0 @@
|
||||
# Built files
|
||||
build/
|
||||
build-*/
|
||||
cmake-build-*/
|
||||
.idea/
|
||||
docs/Doxygen/
|
||||
# Generated files
|
||||
src/dynarmic/backend/arm64/mig/
|
||||
src/dynarmic/backend/x64/mig/
|
||||
# System files
|
||||
.DS_Store
|
||||
.vscode
|
207
externals/dynarmic/CMakeLists.txt
vendored
207
externals/dynarmic/CMakeLists.txt
vendored
@ -1,207 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
project(dynarmic LANGUAGES C CXX ASM VERSION 6.7.0)
|
||||
|
||||
# Determine if we're built as a subproject (using add_subdirectory)
|
||||
# or if this is the master project.
|
||||
set(MASTER_PROJECT OFF)
|
||||
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
set(MASTER_PROJECT ON)
|
||||
endif()
|
||||
|
||||
if (MASTER_PROJECT)
|
||||
include(CTest)
|
||||
endif()
|
||||
|
||||
# Dynarmic project options
|
||||
option(DYNARMIC_ENABLE_CPU_FEATURE_DETECTION "Turning this off causes dynarmic to assume the host CPU doesn't support anything later than SSE3" ON)
|
||||
option(DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT "Enables support for systems that require W^X" OFF)
|
||||
option(DYNARMIC_FATAL_ERRORS "Errors are fatal" OFF)
|
||||
option(DYNARMIC_IGNORE_ASSERTS "Ignore asserts" OFF)
|
||||
option(DYNARMIC_TESTS "Build tests" ${BUILD_TESTING})
|
||||
option(DYNARMIC_TESTS_USE_UNICORN "Enable fuzzing tests against unicorn" OFF)
|
||||
option(DYNARMIC_USE_LLVM "Support disassembly of jitted x86_64 code using LLVM" OFF)
|
||||
option(DYNARMIC_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON)
|
||||
option(DYNARMIC_USE_BUNDLED_EXTERNALS "Use all bundled externals (useful when e.g. cross-compiling)" OFF)
|
||||
option(DYNARMIC_WARNINGS_AS_ERRORS "Warnings as errors" ${MASTER_PROJECT})
|
||||
if (NOT DEFINED DYNARMIC_FRONTENDS)
|
||||
set(DYNARMIC_FRONTENDS "A32;A64" CACHE STRING "Selects which frontends to enable")
|
||||
endif()
|
||||
|
||||
# Default to a Release build
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
|
||||
message(STATUS "Defaulting to a Release build")
|
||||
endif()
|
||||
|
||||
# Set hard requirements for C++
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
# Disable in-source builds
|
||||
set(CMAKE_DISABLE_SOURCE_CHANGES ON)
|
||||
set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
|
||||
if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
|
||||
message(SEND_ERROR "In-source builds are not allowed.")
|
||||
endif()
|
||||
|
||||
# Add the module directory to the list of paths
|
||||
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules")
|
||||
|
||||
# Compiler flags
|
||||
if (MSVC)
|
||||
set(DYNARMIC_CXX_FLAGS
|
||||
/experimental:external
|
||||
/external:W0
|
||||
/external:anglebrackets
|
||||
/W4
|
||||
/w44263 # Non-virtual member function hides base class virtual function
|
||||
/w44265 # Class has virtual functions, but destructor is not virtual
|
||||
/w44456 # Declaration of 'var' hides previous local declaration
|
||||
/w44457 # Declaration of 'var' hides function parameter
|
||||
/w44458 # Declaration of 'var' hides class member
|
||||
/w44459 # Declaration of 'var' hides global definition
|
||||
/w44946 # Reinterpret-cast between related types
|
||||
/wd4592 # Symbol will be dynamically initialized (implementation limitation)
|
||||
/permissive- # Stricter C++ standards conformance
|
||||
/MP
|
||||
/Zi
|
||||
/Zo
|
||||
/EHsc
|
||||
/Zc:externConstexpr # Allows external linkage for variables declared "extern constexpr", as the standard permits.
|
||||
/Zc:inline # Omits inline functions from object-file output.
|
||||
/Zc:throwingNew # Assumes new (without std::nothrow) never returns null.
|
||||
/volatile:iso # Use strict standard-abiding volatile semantics
|
||||
/bigobj # Increase number of sections in .obj files
|
||||
/DNOMINMAX)
|
||||
|
||||
if (DYNARMIC_WARNINGS_AS_ERRORS)
|
||||
list(APPEND DYNARMIC_CXX_FLAGS
|
||||
/WX)
|
||||
endif()
|
||||
|
||||
if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
|
||||
list(APPEND DYNARMIC_CXX_FLAGS
|
||||
-Qunused-arguments
|
||||
-Wno-missing-braces)
|
||||
endif()
|
||||
else()
|
||||
set(DYNARMIC_CXX_FLAGS
|
||||
-Wall
|
||||
-Wextra
|
||||
-Wcast-qual
|
||||
-pedantic
|
||||
-Wno-missing-braces)
|
||||
|
||||
if (DYNARMIC_WARNINGS_AS_ERRORS)
|
||||
list(APPEND DYNARMIC_CXX_FLAGS
|
||||
-pedantic-errors
|
||||
-Werror)
|
||||
endif()
|
||||
|
||||
if (DYNARMIC_FATAL_ERRORS)
|
||||
list(APPEND DYNARMIC_CXX_FLAGS
|
||||
-Wfatal-errors)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
# GCC produces bogus -Warray-bounds warnings from xbyak headers for code paths that are not
|
||||
# actually reachable. Specifically, it happens in cases where some code casts an Operand&
|
||||
# to Address& after first checking isMEM(), and that code is inlined in a situation where
|
||||
# GCC knows that the variable is actually a Reg64. isMEM() will never return true for a
|
||||
# Reg64, but GCC doesn't know that.
|
||||
list(APPEND DYNARMIC_CXX_FLAGS -Wno-array-bounds)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang")
|
||||
# Bracket depth determines maximum size of a fold expression in Clang since 9c9974c3ccb6.
|
||||
# And this in turns limits the size of a std::array.
|
||||
list(APPEND DYNARMIC_CXX_FLAGS -fbracket-depth=1024)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Arch detection
|
||||
include(DetectArchitecture)
|
||||
if (NOT DEFINED ARCHITECTURE)
|
||||
message(FATAL_ERROR "Unsupported architecture encountered. Ending CMake generation.")
|
||||
endif()
|
||||
message(STATUS "Target architecture: ${ARCHITECTURE}")
|
||||
|
||||
# Forced use of individual bundled libraries for non-REQUIRED library is possible with e.g. cmake -DCMAKE_DISABLE_FIND_PACKAGE_fmt=ON ...
|
||||
|
||||
if (DYNARMIC_USE_BUNDLED_EXTERNALS)
|
||||
set(CMAKE_DISABLE_FIND_PACKAGE_biscuit ON)
|
||||
set(CMAKE_DISABLE_FIND_PACKAGE_Catch2 ON)
|
||||
set(CMAKE_DISABLE_FIND_PACKAGE_fmt ON)
|
||||
set(CMAKE_DISABLE_FIND_PACKAGE_mcl ON)
|
||||
set(CMAKE_DISABLE_FIND_PACKAGE_oaknut ON)
|
||||
set(CMAKE_DISABLE_FIND_PACKAGE_tsl-robin-map ON)
|
||||
set(CMAKE_DISABLE_FIND_PACKAGE_xbyak ON)
|
||||
set(CMAKE_DISABLE_FIND_PACKAGE_Zydis ON)
|
||||
endif()
|
||||
|
||||
find_package(Boost 1.57 REQUIRED)
|
||||
find_package(fmt 9 CONFIG)
|
||||
find_package(mcl 0.1.12 EXACT CONFIG)
|
||||
find_package(tsl-robin-map CONFIG)
|
||||
|
||||
if ("arm64" IN_LIST ARCHITECTURE OR DYNARMIC_TESTS)
|
||||
find_package(oaknut 2.0.1 CONFIG)
|
||||
endif()
|
||||
|
||||
if ("riscv" IN_LIST ARCHITECTURE)
|
||||
find_package(biscuit 0.9.1 QUIET)
|
||||
endif()
|
||||
|
||||
if ("x86_64" IN_LIST ARCHITECTURE)
|
||||
find_package(xbyak 7 CONFIG)
|
||||
find_package(Zydis 4 CONFIG)
|
||||
endif()
|
||||
|
||||
if (DYNARMIC_USE_LLVM)
|
||||
find_package(LLVM REQUIRED)
|
||||
separate_arguments(LLVM_DEFINITIONS)
|
||||
endif()
|
||||
|
||||
if (DYNARMIC_TESTS)
|
||||
find_package(Catch2 3 CONFIG)
|
||||
if (DYNARMIC_TESTS_USE_UNICORN)
|
||||
find_package(Unicorn REQUIRED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Pull in externals CMakeLists for libs where available
|
||||
add_subdirectory(externals)
|
||||
|
||||
# Dynarmic project files
|
||||
add_subdirectory(src/dynarmic)
|
||||
if (DYNARMIC_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Install
|
||||
#
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
install(TARGETS dynarmic EXPORT dynarmicTargets)
|
||||
install(EXPORT dynarmicTargets
|
||||
NAMESPACE dynarmic::
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/dynarmic"
|
||||
)
|
||||
|
||||
configure_package_config_file(CMakeModules/dynarmicConfig.cmake.in
|
||||
dynarmicConfig.cmake
|
||||
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/dynarmic"
|
||||
)
|
||||
write_basic_package_version_file(dynarmicConfigVersion.cmake
|
||||
COMPATIBILITY SameMajorVersion
|
||||
)
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/dynarmicConfig.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/dynarmicConfigVersion.cmake"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/dynarmic"
|
||||
)
|
||||
|
||||
install(DIRECTORY src/dynarmic TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
|
@ -1,17 +0,0 @@
|
||||
# This function should be passed a name of an existing target. It will automatically generate
|
||||
# file groups following the directory hierarchy, so that the layout of the files in IDEs matches the
|
||||
# one in the filesystem.
|
||||
function(create_target_directory_groups target_name)
|
||||
# Place any files that aren't in the source list in a separate group so that they don't get in
|
||||
# the way.
|
||||
source_group("Other Files" REGULAR_EXPRESSION ".")
|
||||
|
||||
get_target_property(target_sources "${target_name}" SOURCES)
|
||||
|
||||
foreach(file_name IN LISTS target_sources)
|
||||
get_filename_component(dir_name "${file_name}" PATH)
|
||||
# Group names use '\' as a separator even though the entire rest of CMake uses '/'...
|
||||
string(REPLACE "/" "\\" group_name "${dir_name}")
|
||||
source_group("${group_name}" FILES "${file_name}")
|
||||
endforeach()
|
||||
endfunction()
|
@ -1,62 +0,0 @@
|
||||
include(CheckSymbolExists)
|
||||
|
||||
if (CMAKE_OSX_ARCHITECTURES)
|
||||
set(DYNARMIC_MULTIARCH_BUILD 1)
|
||||
set(ARCHITECTURE "${CMAKE_OSX_ARCHITECTURES}")
|
||||
return()
|
||||
endif()
|
||||
|
||||
function(detect_architecture symbol arch)
|
||||
if (NOT DEFINED ARCHITECTURE)
|
||||
set(CMAKE_REQUIRED_QUIET YES)
|
||||
check_symbol_exists("${symbol}" "" DETECT_ARCHITECTURE_${arch})
|
||||
unset(CMAKE_REQUIRED_QUIET)
|
||||
|
||||
if (DETECT_ARCHITECTURE_${arch})
|
||||
set(ARCHITECTURE "${arch}" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
unset(DETECT_ARCHITECTURE_${arch} CACHE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
detect_architecture("__ARM64__" arm64)
|
||||
detect_architecture("__aarch64__" arm64)
|
||||
detect_architecture("_M_ARM64" arm64)
|
||||
|
||||
detect_architecture("__arm__" arm)
|
||||
detect_architecture("__TARGET_ARCH_ARM" arm)
|
||||
detect_architecture("_M_ARM" arm)
|
||||
|
||||
detect_architecture("__x86_64" x86_64)
|
||||
detect_architecture("__x86_64__" x86_64)
|
||||
detect_architecture("__amd64" x86_64)
|
||||
detect_architecture("_M_X64" x86_64)
|
||||
|
||||
detect_architecture("__i386" x86)
|
||||
detect_architecture("__i386__" x86)
|
||||
detect_architecture("_M_IX86" x86)
|
||||
|
||||
detect_architecture("__ia64" ia64)
|
||||
detect_architecture("__ia64__" ia64)
|
||||
detect_architecture("_M_IA64" ia64)
|
||||
|
||||
detect_architecture("__mips" mips)
|
||||
detect_architecture("__mips__" mips)
|
||||
detect_architecture("_M_MRX000" mips)
|
||||
|
||||
detect_architecture("__ppc64__" ppc64)
|
||||
detect_architecture("__powerpc64__" ppc64)
|
||||
|
||||
detect_architecture("__ppc__" ppc)
|
||||
detect_architecture("__ppc" ppc)
|
||||
detect_architecture("__powerpc__" ppc)
|
||||
detect_architecture("_ARCH_COM" ppc)
|
||||
detect_architecture("_ARCH_PWR" ppc)
|
||||
detect_architecture("_ARCH_PPC" ppc)
|
||||
detect_architecture("_M_MPPC" ppc)
|
||||
detect_architecture("_M_PPC" ppc)
|
||||
|
||||
detect_architecture("__riscv" riscv)
|
||||
|
||||
detect_architecture("__EMSCRIPTEN__" wasm)
|
@ -1,37 +0,0 @@
|
||||
# Exports:
|
||||
#
|
||||
# Variables:
|
||||
# LIBUNICORN_FOUND
|
||||
# LIBUNICORN_INCLUDE_DIR
|
||||
# LIBUNICORN_LIBRARY
|
||||
#
|
||||
# Target:
|
||||
# Unicorn::Unicorn
|
||||
#
|
||||
|
||||
find_path(LIBUNICORN_INCLUDE_DIR
|
||||
unicorn/unicorn.h
|
||||
HINTS $ENV{UNICORNDIR}
|
||||
PATH_SUFFIXES include)
|
||||
|
||||
find_library(LIBUNICORN_LIBRARY
|
||||
NAMES unicorn
|
||||
HINTS $ENV{UNICORNDIR})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Unicorn DEFAULT_MSG LIBUNICORN_LIBRARY LIBUNICORN_INCLUDE_DIR)
|
||||
|
||||
if (UNICORN_FOUND)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
unset(THREADS_PREFER_PTHREAD_FLAG)
|
||||
|
||||
add_library(Unicorn::Unicorn UNKNOWN IMPORTED)
|
||||
set_target_properties(Unicorn::Unicorn PROPERTIES
|
||||
IMPORTED_LOCATION ${LIBUNICORN_LIBRARY}
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${LIBUNICORN_INCLUDE_DIR}
|
||||
INTERFACE_LINK_LIBRARIES Threads::Threads
|
||||
)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(LIBUNICORN_INCLUDE_DIR LIBUNICORN_LIBRARY)
|
@ -1,26 +0,0 @@
|
||||
function(target_architecture_specific_sources project arch)
|
||||
if (NOT DYNARMIC_MULTIARCH_BUILD)
|
||||
target_sources("${project}" PRIVATE ${ARGN})
|
||||
return()
|
||||
endif()
|
||||
|
||||
foreach(input_file IN LISTS ARGN)
|
||||
if(input_file MATCHES ".cpp$")
|
||||
if(NOT IS_ABSOLUTE ${input_file})
|
||||
set(input_file "${CMAKE_CURRENT_SOURCE_DIR}/${input_file}")
|
||||
endif()
|
||||
|
||||
set(output_file "${CMAKE_CURRENT_BINARY_DIR}/arch_gen/${input_file}")
|
||||
add_custom_command(
|
||||
OUTPUT "${output_file}"
|
||||
COMMAND ${CMAKE_COMMAND} "-Darch=${arch}"
|
||||
"-Dinput_file=${input_file}"
|
||||
"-Doutput_file=${output_file}"
|
||||
-P "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/impl/TargetArchitectureSpecificSourcesWrapFile.cmake"
|
||||
DEPENDS "${input_file}"
|
||||
VERBATIM
|
||||
)
|
||||
target_sources(${project} PRIVATE "${output_file}")
|
||||
endif()
|
||||
endforeach()
|
||||
endfunction()
|
@ -1,33 +0,0 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
set(ARCHITECTURE "@ARCHITECTURE@")
|
||||
|
||||
if (NOT @BUILD_SHARED_LIBS@)
|
||||
find_dependency(Boost 1.57)
|
||||
find_dependency(fmt 9)
|
||||
find_dependency(mcl 0.1.12 EXACT)
|
||||
find_dependency(tsl-robin-map)
|
||||
|
||||
if ("arm64" IN_LIST ARCHITECTURE)
|
||||
find_dependency(oaknut 2.0.1)
|
||||
endif()
|
||||
|
||||
if ("riscv" IN_LIST ARCHITECTURE)
|
||||
find_dependency(biscuit 0.9.1)
|
||||
endif()
|
||||
|
||||
if ("x86_64" IN_LIST ARCHITECTURE)
|
||||
find_dependency(xbyak 7)
|
||||
find_dependency(Zydis 4)
|
||||
endif()
|
||||
|
||||
if (@DYNARMIC_USE_LLVM@)
|
||||
find_dependency(LLVM)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
|
||||
|
||||
check_required_components(@PROJECT_NAME@)
|
@ -1,3 +0,0 @@
|
||||
string(TOUPPER "${arch}" arch)
|
||||
file(READ "${input_file}" f_contents)
|
||||
file(WRITE "${output_file}" "#include <mcl/macro/architecture.hpp>\n#if defined(MCL_ARCHITECTURE_${arch})\n${f_contents}\n#endif\n")
|
12
externals/dynarmic/LICENSE.txt
vendored
12
externals/dynarmic/LICENSE.txt
vendored
@ -1,12 +0,0 @@
|
||||
Copyright (C) 2017 merryhime <git@mary.rs>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for
|
||||
any purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
||||
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
420
externals/dynarmic/README.md
vendored
420
externals/dynarmic/README.md
vendored
@ -1,420 +0,0 @@
|
||||
Dynarmic
|
||||
========
|
||||
|
||||
[](https://github.com/MerryMage/dynarmic/actions/workflows/x86-64.yml) [](https://github.com/MerryMage/dynarmic/actions/workflows/AArch64.yml)
|
||||
|
||||
A dynamic recompiler for ARM.
|
||||
|
||||
Highlight features:
|
||||
|
||||
- Fast dynamic binary translation via Just-in-Time compilation
|
||||
- Clean API
|
||||
- Implemented in modern C++20
|
||||
- Hooks exposed for easy code instrumentation
|
||||
- Code injection support for very fine-grained instrumentation
|
||||
- Support for unusual address space setups (bring-your-own memory system)
|
||||
- Native support for most popular operating systems (Windows, macOS, Linux, FreeBSD, OpenBSD, NetBSD, Android)
|
||||
|
||||
*Please note that an adversarial guest program [can determine if it is being run under dynarmic](#disadvantages-of-dynarmic). Preventing this is not a goal of this project.*
|
||||
|
||||
### Supported guest architectures
|
||||
|
||||
* v3
|
||||
* v4
|
||||
* v4T
|
||||
* v5TE
|
||||
* v6K
|
||||
* v6T2
|
||||
* v7A
|
||||
* 32-bit v8
|
||||
* 64-bit v8
|
||||
|
||||
You can specify the specific guest version using [ArchVersion](src/dynarmic/interface/A32/arch_version.h).
|
||||
|
||||
There are no plans to support v1 or v2.
|
||||
|
||||
### Supported host architectures
|
||||
|
||||
* x86-64
|
||||
* AArch64
|
||||
|
||||
There are no plans to support any 32-bit architecture.
|
||||
|
||||
Important API Changes in v6.x Series
|
||||
------------------------------------
|
||||
|
||||
* **v6.7.0**
|
||||
* To support use cases where one wants to have the guest to have the same address space as the host, `nullptr` is now a valid value for `fastmem_pointer`.
|
||||
**This change is not backwards-compatible.** If you were previously using `nullptr` to represent an invalid fastmem arena, you will now have to use `std::nullopt`.
|
||||
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
Design documentation can be found at [docs/Design.md](docs/Design.md).
|
||||
|
||||
|
||||
Usage Example
|
||||
-------------
|
||||
|
||||
The below is a minimal example. Bring-your-own memory system.
|
||||
|
||||
```cpp
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <exception>
|
||||
|
||||
#include "dynarmic/interface/A32/a32.h"
|
||||
#include "dynarmic/interface/A32/config.h"
|
||||
|
||||
using u8 = std::uint8_t;
|
||||
using u16 = std::uint16_t;
|
||||
using u32 = std::uint32_t;
|
||||
using u64 = std::uint64_t;
|
||||
|
||||
class MyEnvironment final : public Dynarmic::A32::UserCallbacks {
|
||||
public:
|
||||
u64 ticks_left = 0;
|
||||
std::array<u8, 2048> memory{};
|
||||
|
||||
u8 MemoryRead8(u32 vaddr) override {
|
||||
if (vaddr >= memory.size()) {
|
||||
return 0;
|
||||
}
|
||||
return memory[vaddr];
|
||||
}
|
||||
|
||||
u16 MemoryRead16(u32 vaddr) override {
|
||||
return u16(MemoryRead8(vaddr)) | u16(MemoryRead8(vaddr + 1)) << 8;
|
||||
}
|
||||
|
||||
u32 MemoryRead32(u32 vaddr) override {
|
||||
return u32(MemoryRead16(vaddr)) | u32(MemoryRead16(vaddr + 2)) << 16;
|
||||
}
|
||||
|
||||
u64 MemoryRead64(u32 vaddr) override {
|
||||
return u64(MemoryRead32(vaddr)) | u64(MemoryRead32(vaddr + 4)) << 32;
|
||||
}
|
||||
|
||||
void MemoryWrite8(u32 vaddr, u8 value) override {
|
||||
if (vaddr >= memory.size()) {
|
||||
return;
|
||||
}
|
||||
memory[vaddr] = value;
|
||||
}
|
||||
|
||||
void MemoryWrite16(u32 vaddr, u16 value) override {
|
||||
MemoryWrite8(vaddr, u8(value));
|
||||
MemoryWrite8(vaddr + 1, u8(value >> 8));
|
||||
}
|
||||
|
||||
void MemoryWrite32(u32 vaddr, u32 value) override {
|
||||
MemoryWrite16(vaddr, u16(value));
|
||||
MemoryWrite16(vaddr + 2, u16(value >> 16));
|
||||
}
|
||||
|
||||
void MemoryWrite64(u32 vaddr, u64 value) override {
|
||||
MemoryWrite32(vaddr, u32(value));
|
||||
MemoryWrite32(vaddr + 4, u32(value >> 32));
|
||||
}
|
||||
|
||||
void InterpreterFallback(u32 pc, size_t num_instructions) override {
|
||||
// This is never called in practice.
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
void CallSVC(u32 swi) override {
|
||||
// Do something.
|
||||
}
|
||||
|
||||
void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override {
|
||||
// Do something.
|
||||
}
|
||||
|
||||
void AddTicks(u64 ticks) override {
|
||||
if (ticks > ticks_left) {
|
||||
ticks_left = 0;
|
||||
return;
|
||||
}
|
||||
ticks_left -= ticks;
|
||||
}
|
||||
|
||||
u64 GetTicksRemaining() override {
|
||||
return ticks_left;
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
MyEnvironment env;
|
||||
Dynarmic::A32::UserConfig user_config;
|
||||
user_config.callbacks = &env;
|
||||
Dynarmic::A32::Jit cpu{user_config};
|
||||
|
||||
// Execute at least 1 instruction.
|
||||
// (Note: More than one instruction may be executed.)
|
||||
env.ticks_left = 1;
|
||||
|
||||
// Write some code to memory.
|
||||
env.MemoryWrite16(0, 0x0088); // lsls r0, r1, #2
|
||||
env.MemoryWrite16(2, 0xE7FE); // b +#0 (infinite loop)
|
||||
|
||||
// Setup registers.
|
||||
cpu.Regs()[0] = 1;
|
||||
cpu.Regs()[1] = 2;
|
||||
cpu.Regs()[15] = 0; // PC = 0
|
||||
cpu.SetCpsr(0x00000030); // Thumb mode
|
||||
|
||||
// Execute!
|
||||
cpu.Run();
|
||||
|
||||
// Here we would expect cpu.Regs()[0] == 8
|
||||
printf("R0: %u\n", cpu.Regs()[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Alternatives to Dynarmic
|
||||
------------------------
|
||||
|
||||
Here are some projects with the same goals as dynarmic:
|
||||
|
||||
* [Unicorn](https://www.unicorn-engine.org/) - Recompiling multi-architecture CPU emulator, based on QEMU
|
||||
* [SkyEye](http://skyeye.sourceforge.net) - Cached interpreter for ARM
|
||||
|
||||
More general alternatives:
|
||||
|
||||
* [tARMac](https://davidsharp.com/tarmac/) - Tarmac's use of armlets was initial inspiration for us to use an intermediate representation
|
||||
* [QEMU](https://www.qemu.org/) - Recompiling multi-architecture system emulator
|
||||
* [VisUAL](https://salmanarif.bitbucket.io/visual/index.html) - Visual ARM UAL emulator intended for education
|
||||
* A wide variety of other recompilers, interpreters and emulators can be found embedded in other projects, here are some we would recommend looking at:
|
||||
* [firebird's recompiler](https://github.com/nspire-emus/firebird) - Takes more of a call-threaded approach to recompilation
|
||||
* [higan's arm7tdmi emulator](https://github.com/higan-emu/higan/tree/master/higan/component/processor/arm7tdmi) - Very clean code-style
|
||||
* [arm-js by ozaki-r](https://github.com/ozaki-r/arm-js) - Emulates ARMv7A and some peripherals of Versatile Express, in the browser
|
||||
|
||||
Disadvantages of Dynarmic
|
||||
-------------------------
|
||||
|
||||
In the pursuit of speed, some behavior not commonly depended upon is elided. Therefore this emulator does not match spec.
|
||||
Please note that this would mean that a guest application can easily determine if it is being run under instrumentation.
|
||||
|
||||
Known examples:
|
||||
|
||||
* Only user-mode is emulated, there is no emulation of any other privilege levels.
|
||||
* FPSR state is approximate.
|
||||
* Misaligned loads/stores are not appropriately trapped in certain cases.
|
||||
* Exclusive monitor behavior may not match any known physical processor.
|
||||
|
||||
No formal verification has been done, and no security assessment has been made.
|
||||
Use this code base at your own risk.
|
||||
|
||||
Legal
|
||||
-----
|
||||
|
||||
dynarmic is under a 0BSD license. See LICENSE.txt for more details.
|
||||
|
||||
dynarmic uses several other libraries, whose licenses are included below:
|
||||
|
||||
### biscuit
|
||||
|
||||
```
|
||||
Copyright 2021 Lioncash/Lioncache
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
```
|
||||
|
||||
### catch
|
||||
|
||||
```
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
```
|
||||
|
||||
### fmt
|
||||
|
||||
```
|
||||
Copyright (c) 2012 - 2016, Victor Zverovich
|
||||
|
||||
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.
|
||||
|
||||
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 OWNER 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.
|
||||
```
|
||||
|
||||
### mcl & oaknut
|
||||
|
||||
```
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 merryhime <https://mary.rs>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
|
||||
### robin-map
|
||||
|
||||
```
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Thibaut Goetghebuer-Planchon <tessil@gmx.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
|
||||
### xbyak
|
||||
|
||||
```
|
||||
Copyright (c) 2007 MITSUNARI Shigeo
|
||||
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 owner 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 OWNER 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.
|
||||
-----------------------------------------------------------------------------
|
||||
ソースコード形式かバイナリ形式か、変更するかしないかを問わず、以下の条件を満た
|
||||
す場合に限り、再頒布および使用が許可されます。
|
||||
|
||||
ソースコードを再頒布する場合、上記の著作権表示、本条件一覧、および下記免責条項
|
||||
を含めること。
|
||||
バイナリ形式で再頒布する場合、頒布物に付属のドキュメント等の資料に、上記の著作
|
||||
権表示、本条件一覧、および下記免責条項を含めること。
|
||||
書面による特別の許可なしに、本ソフトウェアから派生した製品の宣伝または販売促進
|
||||
に、著作権者の名前またはコントリビューターの名前を使用してはならない。
|
||||
本ソフトウェアは、著作権者およびコントリビューターによって「現状のまま」提供さ
|
||||
れており、明示黙示を問わず、商業的な使用可能性、および特定の目的に対する適合性
|
||||
に関する暗黙の保証も含め、またそれに限定されない、いかなる保証もありません。
|
||||
著作権者もコントリビューターも、事由のいかんを問わず、 損害発生の原因いかんを
|
||||
問わず、かつ責任の根拠が契約であるか厳格責任であるか(過失その他の)不法行為で
|
||||
あるかを問わず、仮にそのような損害が発生する可能性を知らされていたとしても、
|
||||
本ソフトウェアの使用によって発生した(代替品または代用サービスの調達、使用の
|
||||
喪失、データの喪失、利益の喪失、業務の中断も含め、またそれに限定されない)直接
|
||||
損害、間接損害、偶発的な損害、特別損害、懲罰的損害、または結果損害について、
|
||||
一切責任を負わないものとします。
|
||||
```
|
||||
|
||||
### zydis
|
||||
|
||||
```
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2020 Florian Bernd
|
||||
Copyright (c) 2014-2020 Joel Höner
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
324
externals/dynarmic/docs/Design.md
vendored
324
externals/dynarmic/docs/Design.md
vendored
@ -1,324 +0,0 @@
|
||||
# Dynarmic Design Documentation
|
||||
|
||||
Dynarmic is a dynamic recompiler for the ARMv6K architecture. Future plans for dynarmic include
|
||||
support for other versions of the ARM architecture, having a interpreter mode, and adding support
|
||||
for other architectures.
|
||||
|
||||
Users of this library interact with it primarily through the interface provided in
|
||||
[`src/dynarmic/interface`](../src/dynarmic/interface). Users specify how dynarmic's CPU core interacts with
|
||||
the rest of their system providing an implementation of the relevant `UserCallbacks` interface.
|
||||
Users setup the CPU state using member functions of `Jit`, then call `Jit::Execute` to start CPU
|
||||
execution. The callbacks defined on `UserCallbacks` may be called from dynamically generated code,
|
||||
so users of the library should not depend on the stack being in a walkable state for unwinding.
|
||||
|
||||
* A32: [`Jit`](../src/dynarmic/interface/A32/a32.h), [`UserCallbacks`](../src/dynarmic/interface/A32/config.h)
|
||||
* A64: [`Jit`](../src/dynarmic/interface/A64/a64.h), [`UserCallbacks`](../src/dynarmic/interface/A64/config.h)
|
||||
|
||||
Dynarmic reads instructions from memory by calling `UserCallbacks::MemoryReadCode`. These
|
||||
instructions then pass through several stages:
|
||||
|
||||
1. Decoding (Identifying what type of instruction it is and breaking it up into fields)
|
||||
2. Translation (Generation of high-level IR from the instruction)
|
||||
3. Optimization (Eliminiation of redundant microinstructions, other speed improvements)
|
||||
4. Emission (Generation of host-executable code into memory)
|
||||
5. Execution (Host CPU jumps to the start of emitted code and runs it)
|
||||
|
||||
Using the A32 frontend with the x64 backend as an example:
|
||||
|
||||
* Decoding is done by [double dispatch](https://en.wikipedia.org/wiki/Visitor_pattern) in
|
||||
[`src/frontend/A32/decoder/{arm.h,thumb16.h,thumb32.h}`](../src/dynarmic/frontend/A32/decoder/).
|
||||
* Translation is done by the visitors in [`src/dynarmic/frontend/A32/translate/translate_{arm,thumb}.cpp`](../src/dynarmic/frontend/A32/translate/).
|
||||
The function [`Translate`](../src/dynarmic/frontend/A32/translate/translate.h) takes a starting memory location,
|
||||
some CPU state, and memory reader callback and returns a basic block of IR.
|
||||
* The IR can be found under [`src/frontend/ir/`](../src/dynarmic/ir/).
|
||||
* Optimizations can be found under [`src/ir_opt/`](../src/dynarmic/ir/opt/).
|
||||
* Emission is done by `EmitX64` which can be found in [`src/dynarmic/backend/x64/emit_x64.{h,cpp}`](../src/dynarmic/backend/x64/).
|
||||
* Execution is performed by calling `BlockOfCode::RunCode` in [`src/dynarmic/backend/x64/block_of_code.{h,cpp}`](../src/dynarmic/backend/x64/).
|
||||
|
||||
## Decoder
|
||||
|
||||
The decoder is a double dispatch decoder. Each instruction is represented by a line in the relevant
|
||||
instruction table. Here is an example line from [`arm.h`](../src/dynarmic/frontend/A32/decoder/arm.h):
|
||||
|
||||
INST(&V::arm_ADC_imm, "ADC (imm)", "cccc0010101Snnnnddddrrrrvvvvvvvv")
|
||||
|
||||
(Details on this instruction can be found in section A8.8.1 of the ARMv7-A manual. This is encoding A1.)
|
||||
|
||||
The first argument to INST is the member function to call on the visitor. The second argument is a user-readable
|
||||
instruction name. The third argument is a bit-representation of the instruction.
|
||||
|
||||
### Instruction Bit-Representation
|
||||
|
||||
Each character in the bitstring represents a bit. A `0` means that that bitposition **must** contain a zero. A `1`
|
||||
means that that bitposition **must** contain a one. A `-` means we don't care about the value at that bitposition.
|
||||
A string of the same character represents a field. In the above example, the first four bits `cccc` represent the
|
||||
four-bit-long cond field of the ARM Add with Carry (immediate) instruction.
|
||||
|
||||
The visitor would have to have a function named `arm_ADC_imm` with 6 arguments, one for each field (`cccc`, `S`,
|
||||
`nnnn`, `dddd`, `rrrr`, `vvvvvvvv`). If there is a mismatch of field number with argument number, a compile-time
|
||||
error results.
|
||||
|
||||
## Translator
|
||||
|
||||
The translator is a visitor that uses the decoder to decode instructions. The translator generates IR code with the
|
||||
help of the [`IREmitter` class](../src/dynarmic/ir/ir_emitter.h). An example of a translation function follows:
|
||||
|
||||
bool ArmTranslatorVisitor::arm_ADC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 imm8) {
|
||||
u32 imm32 = ArmExpandImm(rotate, imm8);
|
||||
|
||||
// ADC{S}<c> <Rd>, <Rn>, #<imm>
|
||||
|
||||
if (ConditionPassed(cond)) {
|
||||
auto result = ir.AddWithCarry(ir.GetRegister(n), ir.Imm32(imm32), ir.GetCFlag());
|
||||
|
||||
if (d == Reg::PC) {
|
||||
ASSERT(!S);
|
||||
ir.ALUWritePC(result.result);
|
||||
ir.SetTerm(IR::Term::ReturnToDispatch{});
|
||||
return false;
|
||||
}
|
||||
|
||||
ir.SetRegister(d, result.result);
|
||||
if (S) {
|
||||
ir.SetNFlag(ir.MostSignificantBit(result.result));
|
||||
ir.SetZFlag(ir.IsZero(result.result));
|
||||
ir.SetCFlag(result.carry);
|
||||
ir.SetVFlag(result.overflow);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
where `ir` is an instance of the `IRBuilder` class. Each member function of the `IRBuilder` class constructs
|
||||
an IR microinstruction.
|
||||
|
||||
## Intermediate Representation
|
||||
|
||||
Dynarmic uses an ordered SSA intermediate representation. It is very vaguely similar to those found in other
|
||||
similar projects like redream, nucleus, and xenia. Major differences are: (1) the abundance of context
|
||||
microinstructions whereas those projects generally only have two (`load_context`/`store_context`), (2) the
|
||||
explicit handling of flags as their own values, and (3) very different basic block edge handling.
|
||||
|
||||
The intention of the context microinstructions and explicit flag handling is to allow for future optimizations. The
|
||||
differences in the way edges are handled are a quirk of the current implementation and dynarmic will likely add a
|
||||
function analyser in the medium-term future.
|
||||
|
||||
Dynarmic's intermediate representation is typed. Each microinstruction may take zero or more arguments and may
|
||||
return zero or more arguments. A subset of the microinstructions available is documented below.
|
||||
|
||||
A complete list of microinstructions can be found in [src/dynarmic/ir/opcodes.inc](../src/dynarmic/ir/opcodes.inc).
|
||||
|
||||
The below lists some commonly used microinstructions.
|
||||
|
||||
### Immediate: Imm{U1,U8,U32,RegRef}
|
||||
|
||||
<u1> ImmU1(u1 value)
|
||||
<u8> ImmU8(u8 value)
|
||||
<u32> ImmU32(u32 value)
|
||||
<RegRef> ImmRegRef(Arm::Reg gpr)
|
||||
|
||||
These instructions take a `bool`, `u8` or `u32` value and wraps it up in an IR node so that they can be used
|
||||
by the IR.
|
||||
|
||||
### Context: {Get,Set}Register
|
||||
|
||||
<u32> GetRegister(<RegRef> reg)
|
||||
<void> SetRegister(<RegRef> reg, <u32> value)
|
||||
|
||||
Gets and sets `JitState::Reg[reg]`. Note that `SetRegister(Arm::Reg::R15, _)` is disallowed by IRBuilder.
|
||||
Use `{ALU,BX}WritePC` instead.
|
||||
|
||||
Note that sequences like `SetRegister(R4, _)` followed by `GetRegister(R4)` are
|
||||
optimized away.
|
||||
|
||||
### Context: {Get,Set}{N,Z,C,V}Flag
|
||||
|
||||
<u1> GetNFlag()
|
||||
<void> SetNFlag(<u1> value)
|
||||
<u1> GetZFlag()
|
||||
<void> SetZFlag(<u1> value)
|
||||
<u1> GetCFlag()
|
||||
<void> SetCFlag(<u1> value)
|
||||
<u1> GetVFlag()
|
||||
<void> SetVFlag(<u1> value)
|
||||
|
||||
Gets and sets bits in `JitState::Cpsr`. Similarly to registers redundant get/sets are optimized away.
|
||||
|
||||
### Context: BXWritePC
|
||||
|
||||
<void> BXWritePC(<u32> value)
|
||||
|
||||
This should probably be the last instruction in a translation block unless you're doing something fancy.
|
||||
|
||||
This microinstruction sets R15 and CPSR.T as appropriate.
|
||||
|
||||
### Callback: CallSupervisor
|
||||
|
||||
<void> CallSupervisor(<u32> svc_imm32)
|
||||
|
||||
This should probably be the last instruction in a translation block unless you're doing something fancy.
|
||||
|
||||
### Calculation: LastSignificant{Half,Byte}
|
||||
|
||||
<u16> LeastSignificantHalf(<u32> value)
|
||||
<u8> LeastSignificantByte(<u32> value)
|
||||
|
||||
Extract a u16 and u8 respectively from a u32.
|
||||
|
||||
### Calculation: MostSignificantBit, IsZero
|
||||
|
||||
<u1> MostSignificantBit(<u32> value)
|
||||
<u1> IsZero(<u32> value)
|
||||
|
||||
These are used to implement ARM flags N and Z. These can often be optimized away by the backend into a host flag read.
|
||||
|
||||
### Calculation: LogicalShiftLeft
|
||||
|
||||
(<u32> result, <u1> carry_out) LogicalShiftLeft(<u32> operand, <u8> shift_amount, <u1> carry_in)
|
||||
|
||||
Pseudocode:
|
||||
|
||||
if shift_amount == 0:
|
||||
return (operand, carry_in)
|
||||
|
||||
x = operand * (2 ** shift_amount)
|
||||
result = Bits<31,0>(x)
|
||||
carry_out = Bit<32>(x)
|
||||
|
||||
return (result, carry_out)
|
||||
|
||||
This follows ARM semantics. Note `shift_amount` is not masked to 5 bits (like `SHL` does on x64).
|
||||
|
||||
### Calculation: LogicalShiftRight
|
||||
|
||||
(<u32> result, <u1> carry_out) LogicalShiftLeft(<u32> operand, <u8> shift_amount, <u1> carry_in)
|
||||
|
||||
Pseudocode:
|
||||
|
||||
if shift_amount == 0:
|
||||
return (operand, carry_in)
|
||||
|
||||
x = ZeroExtend(operand, from_size: 32, to_size: shift_amount+32)
|
||||
result = Bits<shift_amount+31,shift_amount>(x)
|
||||
carry_out = Bit<shift_amount-1>(x)
|
||||
|
||||
return (result, carry_out)
|
||||
|
||||
This follows ARM semantics. Note `shift_amount` is not masked to 5 bits (like `SHR` does on x64).
|
||||
|
||||
### Calculation: ArithmeticShiftRight
|
||||
|
||||
(<u32> result, <u1> carry_out) ArithmeticShiftRight(<u32> operand, <u8> shift_amount, <u1> carry_in)
|
||||
|
||||
Pseudocode:
|
||||
|
||||
if shift_amount == 0:
|
||||
return (operand, carry_in)
|
||||
|
||||
x = SignExtend(operand, from_size: 32, to_size: shift_amount+32)
|
||||
result = Bits<shift_amount+31,shift_amount>(x)
|
||||
carry_out = Bit<shift_amount-1>(x)
|
||||
|
||||
return (result, carry_out)
|
||||
|
||||
This follows ARM semantics. Note `shift_amount` is not masked to 5 bits (like `SAR` does on x64).
|
||||
|
||||
### Calcuation: RotateRight
|
||||
|
||||
(<u32> result, <u1> carry_out) RotateRight(<u32> operand, <u8> shift_amount, <u1> carry_in)
|
||||
|
||||
Pseudocode:
|
||||
|
||||
if shift_amount == 0:
|
||||
return (operand, carry_in)
|
||||
|
||||
shift_amount %= 32
|
||||
result = (operand << shift_amount) | (operand >> (32 - shift_amount))
|
||||
carry_out = Bit<31>(result)
|
||||
|
||||
return (result, carry_out)
|
||||
|
||||
### Calculation: AddWithCarry
|
||||
|
||||
(<u32> result, <u1> carry_out, <u1> overflow) AddWithCarry(<u32> a, <u32> b, <u1> carry_in)
|
||||
|
||||
a + b + carry_in
|
||||
|
||||
### Calculation: SubWithCarry
|
||||
|
||||
(<u32> result, <u1> carry_out, <u1> overflow) SubWithCarry(<u32> a, <u32> b, <u1> carry_in)
|
||||
|
||||
This has equivalent semantics to `AddWithCarry(a, Not(b), carry_in)`.
|
||||
|
||||
a - b - !carry_in
|
||||
|
||||
### Calculation: And
|
||||
|
||||
<u32> And(<u32> a, <u32> b)
|
||||
|
||||
### Calculation: Eor
|
||||
|
||||
<u32> Eor(<u32> a, <u32> b)
|
||||
|
||||
Exclusive OR (i.e.: XOR)
|
||||
|
||||
### Calculation: Or
|
||||
|
||||
<u32> Or(<u32> a, <u32> b)
|
||||
|
||||
### Calculation: Not
|
||||
|
||||
<u32> Not(<u32> value)
|
||||
|
||||
### Callback: {Read,Write}Memory{8,16,32,64}
|
||||
|
||||
<u8> ReadMemory8(<u32> vaddr)
|
||||
<u8> ReadMemory16(<u32> vaddr)
|
||||
<u8> ReadMemory32(<u32> vaddr)
|
||||
<u8> ReadMemory64(<u32> vaddr)
|
||||
<void> WriteMemory8(<u32> vaddr, <u8> value_to_store)
|
||||
<void> WriteMemory16(<u32> vaddr, <u16> value_to_store)
|
||||
<void> WriteMemory32(<u32> vaddr, <u32> value_to_store)
|
||||
<void> WriteMemory64(<u32> vaddr, <u64> value_to_store)
|
||||
|
||||
Memory access.
|
||||
|
||||
### Terminal: Interpret
|
||||
|
||||
SetTerm(IR::Term::Interpret{next})
|
||||
|
||||
This terminal instruction calls the interpreter, starting at `next`.
|
||||
The interpreter must interpret exactly one instruction.
|
||||
|
||||
### Terminal: ReturnToDispatch
|
||||
|
||||
SetTerm(IR::Term::ReturnToDispatch{})
|
||||
|
||||
This terminal instruction returns control to the dispatcher.
|
||||
The dispatcher will use the value in R15 to determine what comes next.
|
||||
|
||||
### Terminal: LinkBlock
|
||||
|
||||
SetTerm(IR::Term::LinkBlock{next})
|
||||
|
||||
This terminal instruction jumps to the basic block described by `next` if we have enough
|
||||
cycles remaining. If we do not have enough cycles remaining, we return to the
|
||||
dispatcher, which will return control to the host.
|
||||
|
||||
### Terminal: PopRSBHint
|
||||
|
||||
SetTerm(IR::Term::PopRSBHint{})
|
||||
|
||||
This terminal instruction checks the top of the Return Stack Buffer against R15.
|
||||
If RSB lookup fails, control is returned to the dispatcher.
|
||||
This is an optimization for faster function calls. A backend that doesn't support
|
||||
this optimization or doesn't have a RSB may choose to implement this exactly as
|
||||
ReturnToDispatch.
|
||||
|
||||
### Terminal: If
|
||||
|
||||
SetTerm(IR::Term::If{cond, term_then, term_else})
|
||||
|
||||
This terminal instruction conditionally executes one terminal or another depending
|
||||
on the run-time state of the ARM flags.
|
2474
externals/dynarmic/docs/Doxyfile
vendored
2474
externals/dynarmic/docs/Doxyfile
vendored
File diff suppressed because it is too large
Load Diff
76
externals/dynarmic/docs/RegisterAllocator.md
vendored
76
externals/dynarmic/docs/RegisterAllocator.md
vendored
@ -1,76 +0,0 @@
|
||||
# Register Allocation (x64 Backend)
|
||||
|
||||
`HostLoc`s contain values. A `HostLoc` ("host value location") is either a host CPU register or a host spill location.
|
||||
|
||||
Values once set cannot be changed. Values can however be moved by the register allocator between `HostLoc`s. This is
|
||||
handled by the register allocator itself and code that uses the register allocator need not and should not move values
|
||||
between registers.
|
||||
|
||||
The register allocator is based on three concepts: `Use`, `Def` and `Scratch`.
|
||||
|
||||
* `Use`: The use of a value.
|
||||
* `Define`: The definition of a value, this is the only time when a value is set.
|
||||
* `Scratch`: Allocate a register that can be freely modified as one wishes.
|
||||
|
||||
Note that `Use`ing a value decrements its `use_count` by one. When the `use_count` reaches zero the value is discarded and no longer exists.
|
||||
|
||||
The member functions on `RegAlloc` are just a combination of the above concepts.
|
||||
|
||||
### `Scratch`
|
||||
|
||||
Xbyak::Reg64 ScratchGpr(HostLocList desired_locations = any_gpr)
|
||||
Xbyak::Xmm ScratchXmm(HostLocList desired_locations = any_xmm)
|
||||
|
||||
At runtime, allocate one of the registers in `desired_locations`. You are free to modify the register. The register is discarded at the end of the allocation scope.
|
||||
|
||||
### Pure `Use`
|
||||
|
||||
Xbyak::Reg64 UseGpr(Argument& arg);
|
||||
Xbyak::Xmm UseXmm(Argument& arg);
|
||||
OpArg UseOpArg(Argument& arg);
|
||||
void Use(Argument& arg, HostLoc host_loc);
|
||||
|
||||
At runtime, the value corresponding to `arg` will be placed a register. The actual register is determined by
|
||||
which one of the above functions is called. `UseGpr` places it in an unused GPR, `UseXmm` places it
|
||||
in an unused XMM register, `UseOpArg` might be in a register or might be a memory location, and `Use` allows
|
||||
you to specify a specific register (GPR or XMM) to use.
|
||||
|
||||
This register **must not** have it's value changed.
|
||||
|
||||
### `UseScratch`
|
||||
|
||||
Xbyak::Reg64 UseScratchGpr(Argument& arg);
|
||||
Xbyak::Xmm UseScratchXmm(Argument& arg);
|
||||
void UseScratch(Argument& arg, HostLoc host_loc);
|
||||
|
||||
At runtime, the value corresponding to `arg` will be placed a register. The actual register is determined by
|
||||
which one of the above functions is called. `UseScratchGpr` places it in an unused GPR, `UseScratchXmm` places it
|
||||
in an unused XMM register, and `UseScratch` allows you to specify a specific register (GPR or XMM) to use.
|
||||
|
||||
The return value is the register allocated to you.
|
||||
|
||||
You are free to modify the value in the register. The register is discarded at the end of the allocation scope.
|
||||
|
||||
### `Define` as register
|
||||
|
||||
A `Define` is the defintion of a value. This is the only time when a value may be set.
|
||||
|
||||
void DefineValue(IR::Inst* inst, const Xbyak::Reg& reg);
|
||||
|
||||
By calling `DefineValue`, you are stating that you wish to define the value for `inst`, and you have written the
|
||||
value to the specified register `reg`.
|
||||
|
||||
### `Define`ing as an alias of a different value
|
||||
|
||||
Adding a `Define` to an existing value.
|
||||
|
||||
void DefineValue(IR::Inst* inst, Argument& arg);
|
||||
|
||||
You are declaring that the value for `inst` is the same as the value for `arg`. No host machine instructions are
|
||||
emitted.
|
||||
|
||||
## When to use each?
|
||||
|
||||
* Prefer `Use` to `UseScratch` where possible.
|
||||
* Prefer the `OpArg` variants where possible.
|
||||
* Prefer to **not** use the specific `HostLoc` variants where possible.
|
@ -1,145 +0,0 @@
|
||||
# Return Stack Buffer Optimization (x64 Backend)
|
||||
|
||||
One of the optimizations that dynarmic does is block-linking. Block-linking is done when
|
||||
the destination address of a jump is available at JIT-time. Instead of returning to the
|
||||
dispatcher at the end of a block we can perform block-linking: just jump directly to the
|
||||
next block. This is beneficial because returning to the dispatcher can often be quite
|
||||
expensive.
|
||||
|
||||
What should we do in cases when we can't predict the destination address? The eponymous
|
||||
example is when executing a return statement at the end of a function; the return address
|
||||
is not statically known at compile time.
|
||||
|
||||
We deal with this by using a return stack buffer: When we execute a call instruction,
|
||||
we push our prediction onto the RSB. When we execute a return instruction, we pop a
|
||||
prediction off the RSB. If the prediction is a hit, we immediately jump to the relevant
|
||||
compiled block. Otherwise, we return to the dispatcher.
|
||||
|
||||
This is the essential idea behind this optimization.
|
||||
|
||||
## `UniqueHash`
|
||||
|
||||
One complication dynarmic has is that a compiled block is not uniquely identifiable by
|
||||
the PC alone, but bits in the FPSCR and CPSR are also relevant. We resolve this by
|
||||
computing a 64-bit `UniqueHash` that is guaranteed to uniquely identify a block.
|
||||
|
||||
u64 LocationDescriptor::UniqueHash() const {
|
||||
// This value MUST BE UNIQUE.
|
||||
// This calculation has to match up with EmitX64::EmitTerminalPopRSBHint
|
||||
u64 pc_u64 = u64(arm_pc) << 32;
|
||||
u64 fpscr_u64 = u64(fpscr.Value());
|
||||
u64 t_u64 = cpsr.T() ? 1 : 0;
|
||||
u64 e_u64 = cpsr.E() ? 2 : 0;
|
||||
return pc_u64 | fpscr_u64 | t_u64 | e_u64;
|
||||
}
|
||||
|
||||
## Our implementation isn't actually a stack
|
||||
|
||||
Dynarmic's RSB isn't actually a stack. It was implemented as a ring buffer because
|
||||
that showed better performance in tests.
|
||||
|
||||
### RSB Structure
|
||||
|
||||
The RSB is implemented as a ring buffer. `rsb_ptr` is the index of the insertion
|
||||
point. Each element in `rsb_location_descriptors` is a `UniqueHash` and they
|
||||
each correspond to an element in `rsb_codeptrs`. `rsb_codeptrs` contains the
|
||||
host addresses for the corresponding the compiled blocks.
|
||||
|
||||
`RSBSize` was chosen by performance testing. Note that this is bigger than the
|
||||
size of the real RSB in hardware (which has 3 entries). Larger RSBs than 8
|
||||
showed degraded performance.
|
||||
|
||||
struct JitState {
|
||||
// ...
|
||||
|
||||
static constexpr size_t RSBSize = 8; // MUST be a power of 2.
|
||||
u32 rsb_ptr = 0;
|
||||
std::array<u64, RSBSize> rsb_location_descriptors;
|
||||
std::array<u64, RSBSize> rsb_codeptrs;
|
||||
void ResetRSB();
|
||||
|
||||
// ...
|
||||
};
|
||||
|
||||
### RSB Push
|
||||
|
||||
We insert our prediction at the insertion point iff the RSB doesn't already
|
||||
contain a prediction with the same `UniqueHash`.
|
||||
|
||||
void EmitX64::EmitPushRSB(IR::Block&, IR::Inst* inst) {
|
||||
using namespace Xbyak::util;
|
||||
|
||||
ASSERT(inst->GetArg(0).IsImmediate());
|
||||
u64 imm64 = inst->GetArg(0).GetU64();
|
||||
|
||||
Xbyak::Reg64 code_ptr_reg = reg_alloc.ScratchGpr({HostLoc::RCX});
|
||||
Xbyak::Reg64 loc_desc_reg = reg_alloc.ScratchGpr();
|
||||
Xbyak::Reg32 index_reg = reg_alloc.ScratchGpr().cvt32();
|
||||
u64 code_ptr = unique_hash_to_code_ptr.find(imm64) != unique_hash_to_code_ptr.end()
|
||||
? u64(unique_hash_to_code_ptr[imm64])
|
||||
: u64(code->GetReturnFromRunCodeAddress());
|
||||
|
||||
code->mov(index_reg, dword[r15 + offsetof(JitState, rsb_ptr)]);
|
||||
code->add(index_reg, 1);
|
||||
code->and_(index_reg, u32(JitState::RSBSize - 1));
|
||||
|
||||
code->mov(loc_desc_reg, u64(imm64));
|
||||
CodePtr patch_location = code->getCurr<CodePtr>();
|
||||
patch_unique_hash_locations[imm64].emplace_back(patch_location);
|
||||
code->mov(code_ptr_reg, u64(code_ptr)); // This line has to match up with EmitX64::Patch.
|
||||
code->EnsurePatchLocationSize(patch_location, 10);
|
||||
|
||||
Xbyak::Label label;
|
||||
for (size_t i = 0; i < JitState::RSBSize; ++i) {
|
||||
code->cmp(loc_desc_reg, qword[r15 + offsetof(JitState, rsb_location_descriptors) + i * sizeof(u64)]);
|
||||
code->je(label, code->T_SHORT);
|
||||
}
|
||||
|
||||
code->mov(dword[r15 + offsetof(JitState, rsb_ptr)], index_reg);
|
||||
code->mov(qword[r15 + index_reg.cvt64() * 8 + offsetof(JitState, rsb_location_descriptors)], loc_desc_reg);
|
||||
code->mov(qword[r15 + index_reg.cvt64() * 8 + offsetof(JitState, rsb_codeptrs)], code_ptr_reg);
|
||||
code->L(label);
|
||||
}
|
||||
|
||||
In pseudocode:
|
||||
|
||||
for (i := 0 .. RSBSize-1)
|
||||
if (rsb_location_descriptors[i] == imm64)
|
||||
goto label;
|
||||
rsb_ptr++;
|
||||
rsb_ptr %= RSBSize;
|
||||
rsb_location_desciptors[rsb_ptr] = imm64; //< The UniqueHash
|
||||
rsb_codeptr[rsb_ptr] = /* codeptr corresponding to the UniqueHash */;
|
||||
label:
|
||||
|
||||
## RSB Pop
|
||||
|
||||
To check if a predicition is in the RSB, we linearly scan the RSB.
|
||||
|
||||
void EmitX64::EmitTerminalPopRSBHint(IR::Term::PopRSBHint, IR::LocationDescriptor initial_location) {
|
||||
using namespace Xbyak::util;
|
||||
|
||||
// This calculation has to match up with IREmitter::PushRSB
|
||||
code->mov(ecx, MJitStateReg(Arm::Reg::PC));
|
||||
code->shl(rcx, 32);
|
||||
code->mov(ebx, dword[r15 + offsetof(JitState, FPSCR_mode)]);
|
||||
code->or_(ebx, dword[r15 + offsetof(JitState, CPSR_et)]);
|
||||
code->or_(rbx, rcx);
|
||||
|
||||
code->mov(rax, u64(code->GetReturnFromRunCodeAddress()));
|
||||
for (size_t i = 0; i < JitState::RSBSize; ++i) {
|
||||
code->cmp(rbx, qword[r15 + offsetof(JitState, rsb_location_descriptors) + i * sizeof(u64)]);
|
||||
code->cmove(rax, qword[r15 + offsetof(JitState, rsb_codeptrs) + i * sizeof(u64)]);
|
||||
}
|
||||
|
||||
code->jmp(rax);
|
||||
}
|
||||
|
||||
In pseudocode:
|
||||
|
||||
rbx := ComputeUniqueHash()
|
||||
rax := ReturnToDispatch
|
||||
for (i := 0 .. RSBSize-1)
|
||||
if (rbx == rsb_location_descriptors[i])
|
||||
rax = rsb_codeptrs[i]
|
||||
goto rax
|
85
externals/dynarmic/externals/CMakeLists.txt
vendored
85
externals/dynarmic/externals/CMakeLists.txt
vendored
@ -1,85 +0,0 @@
|
||||
# Always build externals as static libraries, even when dynarmic is built as shared
|
||||
if (BUILD_SHARED_LIBS)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(DIRECTORY PROPERTY EXCLUDE_FROM_ALL ON)
|
||||
endif()
|
||||
|
||||
# Allow options shadowing with normal variables when subproject use old cmake policy
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
|
||||
|
||||
# Disable tests in all externals supporting the standard option name
|
||||
set(BUILD_TESTING OFF)
|
||||
|
||||
# For libraries that already come with a CMakeLists file,
|
||||
# simply add the directory to that file as a subdirectory
|
||||
# to have CMake automatically recognize them.
|
||||
|
||||
# biscuit
|
||||
|
||||
if (NOT TARGET biscuit::biscuit)
|
||||
if ("riscv" IN_LIST ARCHITECTURE)
|
||||
add_subdirectory(biscuit)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# catch
|
||||
|
||||
if (NOT TARGET Catch2::Catch2WithMain)
|
||||
if (DYNARMIC_TESTS)
|
||||
add_subdirectory(catch EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# fmt
|
||||
|
||||
if (NOT TARGET fmt::fmt)
|
||||
# fmtlib formatting library
|
||||
set(FMT_INSTALL ON)
|
||||
add_subdirectory(fmt)
|
||||
endif()
|
||||
|
||||
# mcl
|
||||
|
||||
if (NOT TARGET merry::mcl)
|
||||
set(MCL_INSTALL ON)
|
||||
add_subdirectory(mcl)
|
||||
endif()
|
||||
|
||||
# oaknut
|
||||
|
||||
if (NOT TARGET merry::oaknut)
|
||||
if ("arm64" IN_LIST ARCHITECTURE)
|
||||
add_subdirectory(oaknut)
|
||||
elseif (DYNARMIC_TESTS)
|
||||
add_subdirectory(oaknut EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# robin-map
|
||||
|
||||
if (NOT TARGET tsl::robin_map)
|
||||
add_subdirectory(robin-map)
|
||||
endif()
|
||||
|
||||
# xbyak
|
||||
|
||||
if (NOT TARGET xbyak::xbyak)
|
||||
if ("x86_64" IN_LIST ARCHITECTURE)
|
||||
add_subdirectory(xbyak)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# zydis
|
||||
|
||||
if (NOT TARGET Zydis::Zydis)
|
||||
if ("x86_64" IN_LIST ARCHITECTURE)
|
||||
set(ZYDIS_BUILD_TOOLS OFF)
|
||||
set(ZYDIS_BUILD_EXAMPLES OFF)
|
||||
set(ZYDIS_BUILD_DOXYGEN OFF)
|
||||
set(ZYAN_ZYCORE_PATH "${CMAKE_CURRENT_LIST_DIR}/zycore" CACHE PATH "")
|
||||
set(CMAKE_DISABLE_FIND_PACKAGE_Doxygen ON)
|
||||
add_subdirectory(zydis)
|
||||
add_library(Zydis::Zydis ALIAS Zydis)
|
||||
endif()
|
||||
endif()
|
40
externals/dynarmic/externals/README.md
vendored
40
externals/dynarmic/externals/README.md
vendored
@ -1,40 +0,0 @@
|
||||
This repository uses subtrees to manage some of its externals.
|
||||
|
||||
## Initial setup
|
||||
|
||||
```
|
||||
git remote add externals-biscuit https://github.com/lioncash/biscuit.git --no-tags
|
||||
git remote add externals-catch https://github.com/catchorg/Catch2.git --no-tags
|
||||
git remote add externals-fmt https://github.com/fmtlib/fmt.git --no-tags
|
||||
git remote add externals-mcl https://github.com/merryhime/mcl.git --no-tags
|
||||
git remote add externals-oaknut https://github.com/merryhime/oaknut.git --no-tags
|
||||
git remote add externals-robin-map https://github.com/Tessil/robin-map.git --no-tags
|
||||
git remote add externals-xbyak https://github.com/herumi/xbyak.git --no-tags
|
||||
git remote add externals-zycore https://github.com/zyantific/zycore-c.git --no-tags
|
||||
git remote add externals-zydis https://github.com/zyantific/zydis.git --no-tags
|
||||
```
|
||||
|
||||
## Updating
|
||||
|
||||
Change `<ref>` to refer to the appropriate git reference.
|
||||
|
||||
```
|
||||
git fetch externals-biscuit
|
||||
git fetch externals-catch
|
||||
git fetch externals-fmt
|
||||
git fetch externals-mcl
|
||||
git fetch externals-oaknut
|
||||
git fetch externals-robin-map
|
||||
git fetch externals-xbyak
|
||||
git fetch externals-zycore
|
||||
git fetch externals-zydis
|
||||
git subtree pull --squash --prefix=externals/biscuit externals-biscuit <ref>
|
||||
git subtree pull --squash --prefix=externals/catch externals-catch <ref>
|
||||
git subtree pull --squash --prefix=externals/fmt externals-fmt <ref>
|
||||
git subtree pull --squash --prefix=externals/mcl externals-mcl <ref>
|
||||
git subtree pull --squash --prefix=externals/oaknut externals-oaknut <ref>
|
||||
git subtree pull --squash --prefix=externals/robin-map externals-robin-map <ref>
|
||||
git subtree pull --squash --prefix=externals/xbyak externals-xbyak <ref>
|
||||
git subtree pull --squash --prefix=externals/zycore externals-zycore <ref>
|
||||
git subtree pull --squash --prefix=externals/zydis externals-zydis <ref>
|
||||
```
|
@ -1,45 +0,0 @@
|
||||
name: Build and Test
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
cpu_detection: [0, 1]
|
||||
fail-fast: false
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
|
||||
- name: Install build dependencies
|
||||
if: ${{matrix.os == 'ubuntu-latest'}}
|
||||
run: sudo apt-get install llvm ninja-build
|
||||
|
||||
- name: Install build dependencies
|
||||
if: ${{matrix.os == 'macos-latest'}}
|
||||
run: |
|
||||
brew install llvm ninja
|
||||
echo "/usr/local/opt/llvm/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Checkout biscuit repo
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Configure CMake
|
||||
run: >
|
||||
cmake
|
||||
-B ${{github.workspace}}/build
|
||||
-G Ninja
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: ninja
|
||||
|
||||
- name: Test
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: ctest --extra-verbose -C ${{env.BUILD_TYPE}}
|
@ -1,3 +0,0 @@
|
||||
# Built files
|
||||
build/
|
||||
build-*/
|
@ -1,17 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
project(biscuit VERSION 0.14.0)
|
||||
|
||||
include(CTest)
|
||||
|
||||
option(BISCUIT_CODE_BUFFER_MMAP "Use mmap for handling code buffers instead of new" OFF)
|
||||
|
||||
# Source directories
|
||||
add_subdirectory(src)
|
||||
|
||||
if (BUILD_TESTING)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
if (BUILD_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
12
externals/dynarmic/externals/biscuit/LICENSE.md
vendored
12
externals/dynarmic/externals/biscuit/LICENSE.md
vendored
@ -1,12 +0,0 @@
|
||||
Copyright 2021 Lioncash/Lioncache
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
157
externals/dynarmic/externals/biscuit/README.md
vendored
157
externals/dynarmic/externals/biscuit/README.md
vendored
@ -1,157 +0,0 @@
|
||||
# Biscuit: RISC-V Runtime Code Generation Library
|
||||
|
||||
*RISC it for the biscuit*
|
||||
|
||||
## About
|
||||
|
||||
An experimental runtime code generator for RISC-V.
|
||||
|
||||
This allows for runtime code generation of RISC-V instructions. Similar
|
||||
to how [Xbyak](https://github.com/herumi/xbyak) allows for runtime code generation of x86 instructions.
|
||||
|
||||
|
||||
## Implemented ISA Features
|
||||
|
||||
Includes both 32-bit and 64-bit instructions in the following:
|
||||
|
||||
| Feature | Version |
|
||||
|:----------|:-------:|
|
||||
| A | 2.1 |
|
||||
| B | 1.0 |
|
||||
| C | 2.0 |
|
||||
| D | 2.2 |
|
||||
| F | 2.2 |
|
||||
| H | 1.0 |
|
||||
| K | 1.0.1 |
|
||||
| M | 2.0 |
|
||||
| N | 1.1 |
|
||||
| Q | 2.2 |
|
||||
| RV32I | 2.1 |
|
||||
| RV64I | 2.1 |
|
||||
| S | 1.12 |
|
||||
| V | 1.0 |
|
||||
| Sstc | 0.5.4 |
|
||||
| Zacas | 1.0 |
|
||||
| Zawrs | 1.01 |
|
||||
| Zcb | 1.0.4 |
|
||||
| Zcmp | 1.0.4 |
|
||||
| Zcmt | 1.0.4 |
|
||||
| Zfa | 1.0 |
|
||||
| Zfbfmin | 1.0 rc2 |
|
||||
| Zfh | 1.0 |
|
||||
| Zfhmin | 1.0 |
|
||||
| Zicbom | 1.0 |
|
||||
| Zicbop | 1.0 |
|
||||
| Zicboz | 1.0 |
|
||||
| Zicond | 1.0.1 |
|
||||
| Zicsr | 2.0 |
|
||||
| Zifencei | 2.0 |
|
||||
| Zihintntl | 1.0 |
|
||||
| Zvbb | 1.0 |
|
||||
| Zvbc | 1.0 |
|
||||
| Zvfbfmin | 1.0 rc2 |
|
||||
| Zvfbfwma | 1.0 rc2 |
|
||||
| Zvkn | 1.0 |
|
||||
|
||||
Note that usually only extensions considered ratified will be implemented
|
||||
as non-ratified documents are considerably more likely to have
|
||||
large changes made to them, which makes maintaining instruction
|
||||
APIs a little annoying.
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
Biscuit requires no external dependencies for its library other than the C++ standard library.
|
||||
The tests, however, use the Catch2 testing library. This is included in tree so there's no need
|
||||
to worry about installing it yourself if you wish to run said tests.
|
||||
|
||||
|
||||
## Building Biscuit
|
||||
|
||||
1. Generate the build files for the project with CMake
|
||||
2. Hit the build button in your IDE of choice, or run the relevant console command to build for the CMake generator you've chosen.
|
||||
3. Done.
|
||||
|
||||
|
||||
## Running Tests
|
||||
|
||||
1. Generate the build files for the project with CMake
|
||||
2. Build the tests
|
||||
3. Run the test executable directly, or enter `ctest` into your terminal.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
The library is licensed under the MIT license.
|
||||
|
||||
While it's not a requirement whatsoever, it'd be pretty neat if you told me that you found the library useful :-)
|
||||
|
||||
|
||||
## Example
|
||||
|
||||
The following is an adapted equivalent of the `strlen` implementation within the RISC-V bit manipulation extension specification.
|
||||
For brevity, it has been condensed to only handle little-endian platforms.
|
||||
|
||||
```cpp
|
||||
// We prepare some contiguous buffer and give the pointer to the beginning
|
||||
// of the data and the total size of the buffer in bytes to the assembler.
|
||||
|
||||
void strlen_example(uint8_t* buffer, size_t buffer_size) {
|
||||
using namespace biscuit;
|
||||
|
||||
constexpr int ptrlog = 3;
|
||||
constexpr int szreg = 8;
|
||||
|
||||
Assembler as(buffer, buffer_size);
|
||||
Label done;
|
||||
Label loop;
|
||||
|
||||
as.ANDI(a3, a0, szreg - 1); // Offset
|
||||
as.ANDI(a1, a0, 0xFF8); // Align pointer
|
||||
|
||||
as.LI(a4, szreg);
|
||||
as.SUB(a4, a4, a3); // XLEN - offset
|
||||
as.SLLI(a3, a3, ptrlog); // offset * 8
|
||||
as.LD(a2, 0, a1); // Chunk
|
||||
|
||||
//
|
||||
// Shift the partial/unaligned chunk we loaded to remove the bytes
|
||||
// from before the start of the string, adding NUL bytes at the end.
|
||||
//
|
||||
as.SRL(a2, a2, a3); // chunk >> (offset * 8)
|
||||
as.ORCB(a2, a2);
|
||||
as.NOT(a2, a2);
|
||||
|
||||
// Non-NUL bytes in the string have been expanded to 0x00, while
|
||||
// NUL bytes have become 0xff. Search for the first set bit
|
||||
// (corresponding to a NUL byte in the original chunk).
|
||||
as.CTZ(a2, a2);
|
||||
|
||||
// The first chunk is special: compare against the number of valid
|
||||
// bytes in this chunk.
|
||||
as.SRLI(a0, a2, 3);
|
||||
as.BGTU(a4, a0, &done);
|
||||
as.ADDI(a3, a1, szreg);
|
||||
as.LI(a4, -1);
|
||||
|
||||
// Our critical loop is 4 instructions and processes data in 4 byte
|
||||
// or 8 byte chunks.
|
||||
as.Bind(&loop);
|
||||
|
||||
as.LD(a2, szreg, a1);
|
||||
as.ADDI(a1, a1, szreg);
|
||||
as.ORCB(a2, a2);
|
||||
as.BEQ(a2, a4, &loop);
|
||||
|
||||
as.NOT(a2, a2);
|
||||
as.CTZ(a2, a2);
|
||||
as.SUB(a1, a1, a3);
|
||||
as.ADD(a0, a0, a1);
|
||||
as.SRLI(a2, a2, 3);
|
||||
as.ADD(a0, a0, a2);
|
||||
|
||||
as.Bind(&done);
|
||||
|
||||
as.RET();
|
||||
}
|
||||
```
|
@ -1,88 +0,0 @@
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlinesLeft: false
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
ColumnLimit: 100
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
|
||||
IncludeCategories:
|
||||
- Regex: '^\<[^Q][^/.>]*\>'
|
||||
Priority: -2
|
||||
- Regex: '^\<'
|
||||
Priority: -1
|
||||
- Regex: '^\"'
|
||||
Priority: 0
|
||||
IndentCaseLabels: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 150
|
||||
PointerAlignment: Left
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
...
|
@ -1,5 +0,0 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake")
|
||||
|
||||
check_required_components(@PROJECT_NAME@)
|
@ -1 +0,0 @@
|
||||
add_subdirectory(cpuinfo)
|
@ -1,3 +0,0 @@
|
||||
add_executable(cpuinfo cpuinfo.cpp)
|
||||
target_link_libraries(cpuinfo biscuit)
|
||||
set_property(TARGET cpuinfo PROPERTY CXX_STANDARD 20)
|
@ -1,31 +0,0 @@
|
||||
// Copyright (c), 2022, KNS Group LLC (YADRO)
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://opensource.org/licenses/MIT.
|
||||
|
||||
#include <biscuit/assembler.hpp>
|
||||
#include <biscuit/cpuinfo.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace biscuit;
|
||||
|
||||
int main()
|
||||
{
|
||||
CPUInfo cpu;
|
||||
|
||||
std::cout << "Has I:" << cpu.Has(RISCVExtension::I) << std::endl;
|
||||
std::cout << "Has M:" << cpu.Has(RISCVExtension::M) << std::endl;
|
||||
std::cout << "Has A:" << cpu.Has(RISCVExtension::A) << std::endl;
|
||||
std::cout << "Has F:" << cpu.Has(RISCVExtension::F) << std::endl;
|
||||
std::cout << "Has D:" << cpu.Has(RISCVExtension::D) << std::endl;
|
||||
std::cout << "Has C:" << cpu.Has(RISCVExtension::C) << std::endl;
|
||||
std::cout << "Has V:" << cpu.Has(RISCVExtension::V) << std::endl;
|
||||
|
||||
if (cpu.Has(RISCVExtension::V)) {
|
||||
std::cout << "VLENB:" << cpu.GetVlenb() << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
#define BISCUIT_ASSERT(condition) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
std::printf("Assertion failed (%s)\nin %s, function %s line %i\n", \
|
||||
#condition, \
|
||||
__FILE__, __func__, __LINE__); \
|
||||
std::abort(); \
|
||||
} \
|
||||
} while (false)
|
@ -1,211 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
|
||||
#include <biscuit/assert.hpp>
|
||||
|
||||
namespace biscuit {
|
||||
|
||||
/**
|
||||
* An arbitrarily sized buffer that code is written into.
|
||||
*
|
||||
* Also contains other member functions for manipulating
|
||||
* the data within the code buffer.
|
||||
*/
|
||||
class CodeBuffer {
|
||||
public:
|
||||
// Default capacity of 4KB.
|
||||
static constexpr size_t default_capacity = 4096;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param capacity The initial capacity of the code buffer in bytes.
|
||||
*/
|
||||
explicit CodeBuffer(size_t capacity = default_capacity);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param buffer A non-null pointer to an allocated buffer of size `capacity`.
|
||||
* @param capacity The capacity of the memory pointed to by `buffer`.
|
||||
*
|
||||
* @pre The given memory buffer must not be null.
|
||||
* @pre The given memory buffer must be at minimum `capacity` bytes in size.
|
||||
*
|
||||
* @note The caller is responsible for managing the lifetime of the given memory.
|
||||
* CodeBuffer will *not* free the memory once it goes out of scope.
|
||||
*/
|
||||
explicit CodeBuffer(uint8_t* buffer, size_t capacity);
|
||||
|
||||
// Copy constructor and assignment is deleted in order to prevent unintentional memory leaks.
|
||||
CodeBuffer(const CodeBuffer&) = delete;
|
||||
CodeBuffer& operator=(const CodeBuffer&) = delete;
|
||||
|
||||
// Move constructing or moving the buffer in general is allowed, as it's a transfer of control.
|
||||
CodeBuffer(CodeBuffer&& other) noexcept;
|
||||
CodeBuffer& operator=(CodeBuffer&& other) noexcept;
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*
|
||||
* If a custom memory buffer is not given to the code buffer,
|
||||
* then the code buffer will automatically free any memory
|
||||
* it had allocated in order to be able to emit code.
|
||||
*/
|
||||
~CodeBuffer() noexcept;
|
||||
|
||||
/// Returns whether or not the memory is managed by the code buffer.
|
||||
[[nodiscard]] bool IsManaged() const noexcept { return m_is_managed; }
|
||||
|
||||
/// Retrieves the current cursor position within the buffer.
|
||||
[[nodiscard]] ptrdiff_t GetCursorOffset() const noexcept {
|
||||
return m_cursor - m_buffer;
|
||||
}
|
||||
|
||||
/// Retrieves the current address of the cursor within the buffer.
|
||||
[[nodiscard]] uintptr_t GetCursorAddress() const noexcept {
|
||||
return GetOffsetAddress(GetCursorOffset());
|
||||
}
|
||||
|
||||
/// Retrieves the cursor pointer
|
||||
[[nodiscard]] uint8_t* GetCursorPointer() noexcept {
|
||||
return GetOffsetPointer(GetCursorOffset());
|
||||
}
|
||||
|
||||
/// Retrieves the cursor pointer
|
||||
[[nodiscard]] const uint8_t* GetCursorPointer() const noexcept {
|
||||
return GetOffsetPointer(GetCursorOffset());
|
||||
}
|
||||
|
||||
/// Retrieves the address of an arbitrary offset within the buffer.
|
||||
[[nodiscard]] uintptr_t GetOffsetAddress(ptrdiff_t offset) const noexcept {
|
||||
return reinterpret_cast<uintptr_t>(GetOffsetPointer(offset));
|
||||
}
|
||||
|
||||
/// Retrieves the pointer to an arbitrary location within the buffer.
|
||||
[[nodiscard]] uint8_t* GetOffsetPointer(ptrdiff_t offset) noexcept {
|
||||
BISCUIT_ASSERT(offset >= 0 && offset <= GetCursorOffset());
|
||||
return m_buffer + offset;
|
||||
}
|
||||
|
||||
/// Retrieves the pointer to an arbitrary location within the buffer.
|
||||
[[nodiscard]] const uint8_t* GetOffsetPointer(ptrdiff_t offset) const noexcept {
|
||||
BISCUIT_ASSERT(offset >= 0 && offset <= GetCursorOffset());
|
||||
return m_buffer + offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows rewinding of the code buffer cursor.
|
||||
*
|
||||
* @param offset The offset to rewind the cursor by.
|
||||
*
|
||||
* @note If no offset is provided, then this function rewinds the
|
||||
* cursor to the beginning of the buffer.
|
||||
*
|
||||
* @note The offset may not be larger than the current cursor offset
|
||||
* and may not be less than the current buffer starting address.
|
||||
*/
|
||||
void RewindCursor(ptrdiff_t offset = 0) noexcept {
|
||||
auto* rewound = m_buffer + offset;
|
||||
BISCUIT_ASSERT(m_buffer <= rewound && rewound <= m_cursor);
|
||||
m_cursor = rewound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the underlying buffer has enough room for the
|
||||
* given number of bytes.
|
||||
*
|
||||
* @param num_bytes The number of bytes to store in the buffer.
|
||||
*/
|
||||
[[nodiscard]] bool HasSpaceFor(size_t num_bytes) const noexcept {
|
||||
return GetRemainingBytes() >= num_bytes;
|
||||
}
|
||||
|
||||
/// Returns the size of the data written to the buffer in bytes.
|
||||
[[nodiscard]] size_t GetSizeInBytes() const noexcept {
|
||||
EnsureBufferRange();
|
||||
return static_cast<size_t>(m_cursor - m_buffer);
|
||||
}
|
||||
|
||||
/// Returns the total number of remaining bytes in the buffer.
|
||||
[[nodiscard]] size_t GetRemainingBytes() const noexcept {
|
||||
EnsureBufferRange();
|
||||
return static_cast<size_t>((m_buffer + m_capacity) - m_cursor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Grows the underlying memory of the code buffer
|
||||
*
|
||||
* @param new_capacity The new capacity of the code buffer in bytes.
|
||||
*
|
||||
* @pre The underlying memory of the code buffer *must* be managed
|
||||
* by the code buffer itself. Attempts to grow the buffer
|
||||
* with memory that is not managed by it will result in
|
||||
* an assertion being hit.
|
||||
*
|
||||
* @note Calling this with a new capacity that is less than or equal
|
||||
* to the current capacity of the buffer will result in
|
||||
* this function doing nothing.
|
||||
*/
|
||||
void Grow(size_t new_capacity);
|
||||
|
||||
/**
|
||||
* Emits a given value into the code buffer.
|
||||
*
|
||||
* @param value The value to emit into the code buffer.
|
||||
* @tparam T A trivially-copyable type.
|
||||
*/
|
||||
template <typename T>
|
||||
void Emit(T value) noexcept {
|
||||
static_assert(std::is_trivially_copyable_v<T>,
|
||||
"It's undefined behavior to memcpy a non-trivially-copyable type.");
|
||||
BISCUIT_ASSERT(HasSpaceFor(sizeof(T)));
|
||||
|
||||
std::memcpy(m_cursor, &value, sizeof(T));
|
||||
m_cursor += sizeof(T);
|
||||
}
|
||||
|
||||
/// Emits a 16-bit value into the code buffer.
|
||||
void Emit16(uint32_t value) noexcept {
|
||||
Emit(static_cast<uint16_t>(value));
|
||||
}
|
||||
|
||||
/// Emits a 32-bit value into the code buffer.
|
||||
void Emit32(uint32_t value) noexcept {
|
||||
Emit(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the internal code buffer to be executable.
|
||||
*
|
||||
* @note This will make the contained region of memory non-writable
|
||||
* to satisfy operating under W^X contexts. To make the
|
||||
* region writable again, use SetWritable().
|
||||
*/
|
||||
void SetExecutable();
|
||||
|
||||
/**
|
||||
* Sets the internal code buffer to be writable
|
||||
*
|
||||
* @note This will make the contained region of memory non-executable
|
||||
* to satisfy operating under W^X contexts. To make the region
|
||||
* executable again, use SetExecutable().
|
||||
*/
|
||||
void SetWritable();
|
||||
|
||||
private:
|
||||
void EnsureBufferRange() const noexcept {
|
||||
BISCUIT_ASSERT(m_cursor >= m_buffer && m_cursor <= m_buffer + m_capacity);
|
||||
}
|
||||
|
||||
uint8_t* m_buffer = nullptr;
|
||||
uint8_t* m_cursor = nullptr;
|
||||
size_t m_capacity = 0;
|
||||
bool m_is_managed = false;
|
||||
};
|
||||
|
||||
} // namespace biscuit
|
@ -1,101 +0,0 @@
|
||||
// Copyright (c), 2022, KNS Group LLC (YADRO)
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://opensource.org/licenses/MIT.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <biscuit/assembler.hpp>
|
||||
#include <biscuit/registers.hpp>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#if defined(__linux__) && defined(__riscv)
|
||||
#include <sys/auxv.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <asm/hwcap.h>
|
||||
#endif
|
||||
|
||||
namespace biscuit {
|
||||
|
||||
#ifndef COMPAT_HWCAP_ISA_I
|
||||
#define COMPAT_HWCAP_ISA_I (1U << ('I' - 'A'))
|
||||
#endif
|
||||
|
||||
#ifndef COMPAT_HWCAP_ISA_M
|
||||
#define COMPAT_HWCAP_ISA_M (1U << ('M' - 'A'))
|
||||
#endif
|
||||
|
||||
#ifndef COMPAT_HWCAP_ISA_A
|
||||
#define COMPAT_HWCAP_ISA_A (1U << ('A' - 'A'))
|
||||
#endif
|
||||
|
||||
#ifndef COMPAT_HWCAP_ISA_F
|
||||
#define COMPAT_HWCAP_ISA_F (1U << ('F' - 'A'))
|
||||
#endif
|
||||
|
||||
#ifndef COMPAT_HWCAP_ISA_D
|
||||
#define COMPAT_HWCAP_ISA_D (1U << ('D' - 'A'))
|
||||
#endif
|
||||
|
||||
#ifndef COMPAT_HWCAP_ISA_C
|
||||
#define COMPAT_HWCAP_ISA_C (1U << ('C' - 'A'))
|
||||
#endif
|
||||
|
||||
#ifndef COMPAT_HWCAP_ISA_V
|
||||
#define COMPAT_HWCAP_ISA_V (1U << ('V' - 'A'))
|
||||
#endif
|
||||
|
||||
enum class RISCVExtension : uint64_t {
|
||||
I = COMPAT_HWCAP_ISA_I,
|
||||
M = COMPAT_HWCAP_ISA_M,
|
||||
A = COMPAT_HWCAP_ISA_A,
|
||||
F = COMPAT_HWCAP_ISA_F,
|
||||
D = COMPAT_HWCAP_ISA_D,
|
||||
C = COMPAT_HWCAP_ISA_C,
|
||||
V = COMPAT_HWCAP_ISA_V
|
||||
};
|
||||
|
||||
template <CSR csr>
|
||||
struct CSRReader : public biscuit::Assembler {
|
||||
// Buffer capacity exactly for 2 instructions.
|
||||
static constexpr size_t capacity = 8;
|
||||
|
||||
CSRReader() : biscuit::Assembler{CSRReader::capacity} {
|
||||
CSRR(a0, csr);
|
||||
RET();
|
||||
}
|
||||
|
||||
// Copy constructor and assignment.
|
||||
CSRReader(const CSRReader&) = delete;
|
||||
CSRReader& operator=(const CSRReader&) = delete;
|
||||
|
||||
// Move constructor and assignment.
|
||||
CSRReader(CSRReader&&) = default;
|
||||
CSRReader& operator=(CSRReader&&) = default;
|
||||
|
||||
template <typename CSRReaderFunc>
|
||||
CSRReaderFunc GetCode() {
|
||||
this->GetCodeBuffer().SetExecutable();
|
||||
return reinterpret_cast<CSRReaderFunc>(this->GetBufferPointer(0));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Class that detects information about a RISC-V CPU.
|
||||
*/
|
||||
class CPUInfo {
|
||||
public:
|
||||
/**
|
||||
* Checks if a particular RISC-V extension is available.
|
||||
*
|
||||
* @param extension The extension to check.
|
||||
*/
|
||||
bool Has(RISCVExtension extension) const;
|
||||
|
||||
/// Returns the vector register length in bytes.
|
||||
uint32_t GetVlenb() const;
|
||||
};
|
||||
|
||||
} // namespace biscuit
|
@ -1,443 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace biscuit {
|
||||
|
||||
// Control and Status Register
|
||||
enum class CSR : uint32_t {
|
||||
// clang-format off
|
||||
|
||||
// User-level CSRs
|
||||
|
||||
UStatus = 0x000, // User status register
|
||||
UIE = 0x004, // User interrupt-enable register
|
||||
UTVEC = 0x005, // User trap handler base address
|
||||
UScratch = 0x040, // Scratch register for user trap handlers
|
||||
UEPC = 0x041, // User exception program counter
|
||||
UCause = 0x042, // User trap cause
|
||||
UTVal = 0x043, // User bad address or instruction
|
||||
UIP = 0x044, // User interrupt pending
|
||||
|
||||
FFlags = 0x001, // Floating-point Accrued Exceptions
|
||||
FRM = 0x002, // Floating-point Dynamic Rounding Mode
|
||||
FCSR = 0x003, // Floating-point Control and Status Register (frm + fflags)
|
||||
|
||||
JVT = 0x017, // Table jump base vector and control register
|
||||
|
||||
Cycle = 0xC00, // Cycle counter for RDCYCLE instruction.
|
||||
Time = 0xC01, // Timer for RDTIME instruction.
|
||||
InstRet = 0xC02, // Instructions retired counter for RDINSTRET instruction.
|
||||
HPMCounter3 = 0xC03, // Performance-monitoring counter.
|
||||
HPMCounter4 = 0xC04, // Performance-monitoring counter.
|
||||
HPMCounter5 = 0xC05, // Performance-monitoring counter.
|
||||
HPMCounter6 = 0xC06, // Performance-monitoring counter.
|
||||
HPMCounter7 = 0xC07, // Performance-monitoring counter.
|
||||
HPMCounter8 = 0xC08, // Performance-monitoring counter.
|
||||
HPMCounter9 = 0xC09, // Performance-monitoring counter.
|
||||
HPMCounter10 = 0xC0A, // Performance-monitoring counter.
|
||||
HPMCounter11 = 0xC0B, // Performance-monitoring counter.
|
||||
HPMCounter12 = 0xC0C, // Performance-monitoring counter.
|
||||
HPMCounter13 = 0xC0D, // Performance-monitoring counter.
|
||||
HPMCounter14 = 0xC0E, // Performance-monitoring counter.
|
||||
HPMCounter15 = 0xC0F, // Performance-monitoring counter.
|
||||
HPMCounter16 = 0xC10, // Performance-monitoring counter.
|
||||
HPMCounter17 = 0xC11, // Performance-monitoring counter.
|
||||
HPMCounter18 = 0xC12, // Performance-monitoring counter.
|
||||
HPMCounter19 = 0xC13, // Performance-monitoring counter.
|
||||
HPMCounter20 = 0xC14, // Performance-monitoring counter.
|
||||
HPMCounter21 = 0xC15, // Performance-monitoring counter.
|
||||
HPMCounter22 = 0xC16, // Performance-monitoring counter.
|
||||
HPMCounter23 = 0xC17, // Performance-monitoring counter.
|
||||
HPMCounter24 = 0xC18, // Performance-monitoring counter.
|
||||
HPMCounter25 = 0xC19, // Performance-monitoring counter.
|
||||
HPMCounter26 = 0xC1A, // Performance-monitoring counter.
|
||||
HPMCounter27 = 0xC1B, // Performance-monitoring counter.
|
||||
HPMCounter28 = 0xC1C, // Performance-monitoring counter.
|
||||
HPMCounter29 = 0xC1D, // Performance-monitoring counter.
|
||||
HPMCounter30 = 0xC1E, // Performance-monitoring counter.
|
||||
HPMCounter31 = 0xC1F, // Performance-monitoring counter.
|
||||
CycleH = 0xC80, // Upper 32 bits of cycle, RV32I only.
|
||||
TimeH = 0xC81, // Upper 32 bits of time, RV32I only.
|
||||
InstRetH = 0xC82, // Upper 32 bits of instret, RV32I only.
|
||||
HPMCounter3H = 0xC83, // Upper 32 bits of HPMCounter3, RV32I only.
|
||||
HPMCounter4H = 0xC84, // Upper 32 bits of HPMCounter4, RV32I only.
|
||||
HPMCounter5H = 0xC85, // Upper 32 bits of HPMCounter5, RV32I only.
|
||||
HPMCounter6H = 0xC86, // Upper 32 bits of HPMCounter6, RV32I only.
|
||||
HPMCounter7H = 0xC87, // Upper 32 bits of HPMCounter7, RV32I only.
|
||||
HPMCounter8H = 0xC88, // Upper 32 bits of HPMCounter8, RV32I only.
|
||||
HPMCounter9H = 0xC89, // Upper 32 bits of HPMCounter9, RV32I only.
|
||||
HPMCounter10H = 0xC8A, // Upper 32 bits of HPMCounter10, RV32I only.
|
||||
HPMCounter11H = 0xC8B, // Upper 32 bits of HPMCounter11, RV32I only.
|
||||
HPMCounter12H = 0xC8C, // Upper 32 bits of HPMCounter12, RV32I only.
|
||||
HPMCounter13H = 0xC8D, // Upper 32 bits of HPMCounter13, RV32I only.
|
||||
HPMCounter14H = 0xC8E, // Upper 32 bits of HPMCounter14, RV32I only.
|
||||
HPMCounter15H = 0xC8F, // Upper 32 bits of HPMCounter15, RV32I only.
|
||||
HPMCounter16H = 0xC90, // Upper 32 bits of HPMCounter16, RV32I only.
|
||||
HPMCounter17H = 0xC91, // Upper 32 bits of HPMCounter17, RV32I only.
|
||||
HPMCounter18H = 0xC92, // Upper 32 bits of HPMCounter18, RV32I only.
|
||||
HPMCounter19H = 0xC93, // Upper 32 bits of HPMCounter19, RV32I only.
|
||||
HPMCounter20H = 0xC94, // Upper 32 bits of HPMCounter20, RV32I only.
|
||||
HPMCounter21H = 0xC95, // Upper 32 bits of HPMCounter21, RV32I only.
|
||||
HPMCounter22H = 0xC96, // Upper 32 bits of HPMCounter22, RV32I only.
|
||||
HPMCounter23H = 0xC97, // Upper 32 bits of HPMCounter23, RV32I only.
|
||||
HPMCounter24H = 0xC98, // Upper 32 bits of HPMCounter24, RV32I only.
|
||||
HPMCounter25H = 0xC99, // Upper 32 bits of HPMCounter25, RV32I only.
|
||||
HPMCounter26H = 0xC9A, // Upper 32 bits of HPMCounter26, RV32I only.
|
||||
HPMCounter27H = 0xC9B, // Upper 32 bits of HPMCounter27, RV32I only.
|
||||
HPMCounter28H = 0xC9C, // Upper 32 bits of HPMCounter28, RV32I only.
|
||||
HPMCounter29H = 0xC9D, // Upper 32 bits of HPMCounter29, RV32I only.
|
||||
HPMCounter30H = 0xC9E, // Upper 32 bits of HPMCounter30, RV32I only.
|
||||
HPMCounter31H = 0xC9F, // Upper 32 bits of HPMCounter31, RV32I only.
|
||||
|
||||
// Supervisor-level CSRs
|
||||
|
||||
SStatus = 0x100, // Supervisor status register
|
||||
SEDeleg = 0x102, // Supervisor exception delegation register
|
||||
SIDeleg = 0x103, // Supervisor interrupt delegation register
|
||||
SIE = 0x104, // Supervisor interrupt-enable register
|
||||
STVec = 0x105, // Supervisor trap handler base address
|
||||
SCounterEn = 0x106, // Supervisor counter enable
|
||||
|
||||
SEnvCfg = 0x10A, // Supervisor environment configuration register
|
||||
|
||||
SScratch = 0x140, // Scratch register for supervisor trap handlers
|
||||
SEPC = 0x141, // Supervisor exception program counter
|
||||
SCause = 0x142, // Supervisor trap cause
|
||||
STVal = 0x143, // Supervisor bad address or instruction
|
||||
SIP = 0x144, // Supervisor interrupt pending.
|
||||
|
||||
SISelect = 0x150, // Supervisor indirect register select
|
||||
SIReg = 0x151, // Supervisor indirect register alias
|
||||
|
||||
StopEI = 0x15C, // Supervisor top external interrupt (only with an IMSIC)
|
||||
StopI = 0xDB0, // Supervisor top interrupt
|
||||
|
||||
SIEH = 0x114, // Upper 32 bits of sie
|
||||
SIPH = 0x154, // Upper 32 bits of sip
|
||||
|
||||
STimeCmp = 0x14D, // Supervisor timer register
|
||||
STimeCmpH = 0x15D, // Supervisor timer register, RV32 only
|
||||
|
||||
SATP = 0x180, // Supervisor address translation and protection
|
||||
|
||||
SContext = 0x5A8, // Supervisor-mode context register
|
||||
|
||||
// Hypervisor-level CSRs
|
||||
|
||||
HStatus = 0x600, // Hypervisor status register
|
||||
HEDeleg = 0x602, // Hypervisor exception delegation register
|
||||
HIDeleg = 0x603, // Hypervisor interrupt delegation register
|
||||
HIE = 0x604, // Hypervisor interrupt-enable register
|
||||
HCounterEn = 0x606, // Hypervisor counter enable
|
||||
HGEIE = 0x607, // Hypervisor guest external interrupt-enable register
|
||||
HVIEN = 0x608, // Hypervisor virtual interrupt enables
|
||||
HVICTL = 0x609, // Hypervisor virtual interrupt control
|
||||
|
||||
HIDelegH = 0x613, // Upper 32 bits of hideleg
|
||||
HVIENH = 0x618, // Upper 32 bits of hvien
|
||||
HVIPH = 0x655, // Upper 32 bits of hvip
|
||||
HVIPrio1H = 0x656, // Upper 32 bits of hviprio1
|
||||
HVIPrio2H = 0x657, // Upper 32 bits of hviprio2
|
||||
VSIEH = 0x214, // Upper 32 bits of vsie
|
||||
VSIPH = 0x254, // Upper 32 bits of vsiph
|
||||
|
||||
HTVal = 0x643, // Hypervisor bad guest physical address
|
||||
HIP = 0x644, // Hypervisor interrupt pending
|
||||
HVIP = 0x645, // Hypervisor virtual interrupt pending
|
||||
HVIPrio1 = 0x646, // Hypervisor VS-level interrupt priorities
|
||||
HVIPrio2 = 0x647, // Hypervisor VS-level interrupt priorities
|
||||
HTInst = 0x64A, // Hypervisor trap instruction (transformed)
|
||||
HGEIP = 0xE12, // Hypervisor guest external interrupt pending
|
||||
|
||||
HEnvCfg = 0x60A, // Hypervisor environment configuration register
|
||||
HEnvCfgH = 0x61A, // Additional hypervisor environment configuration register, RV32 only
|
||||
|
||||
HGATP = 0x680, // Hypervisor guest address translation and protection
|
||||
|
||||
HContext = 0x6A8, // Hypervisor-mode context register
|
||||
|
||||
HTimeDelta = 0x605, // Delta for VS/VU-mode timer
|
||||
HTimeDeltaH = 0x615, // Upper 32 bits of HTimeDelta, HSXLEN=32 only
|
||||
|
||||
VSStatus = 0x200, // Virtual supervisor status register
|
||||
VSIE = 0x204, // Virtual supervisor interrupt-enable register
|
||||
VSTVec = 0x205, // Virtual supervisor trap handler base address
|
||||
VSScratch = 0x240, // Virtual supervisor scratch register
|
||||
VSEPC = 0x241, // Virtual supervisor exception program register
|
||||
VSCause = 0x242, // Virtual supervisor trap cause
|
||||
VSTVal = 0x243, // Virtual supervisor bad address or instruction
|
||||
VSIP = 0x244, // Virtual supervisor interrupt pending
|
||||
|
||||
VSISelect = 0x250, // Virtual supervisor indirect register select
|
||||
VSIReg = 0x251, // Virtual supervisor indirect register alias
|
||||
|
||||
VStopEI = 0x25C, // Virtual supervisor top external interrupt (only with an IMSIC)
|
||||
VStopI = 0xEB0, // Virtual supervisor top interrupt
|
||||
|
||||
VSTimeCmp = 0x24D, // Virtual supervisor timer register
|
||||
VSTimeCmpH = 0x25D, // Virtual supervisor timer register, RV32 only
|
||||
|
||||
VSATP = 0x280, // Virtual supervisor address translation and protection
|
||||
|
||||
// Machine-level CSRs
|
||||
|
||||
MVendorID = 0xF11, // Vendor ID
|
||||
MArchID = 0xF12, // Architecture ID
|
||||
MImpID = 0xF13, // Implementation ID
|
||||
MHartID = 0xF14, // Hardware Thread ID
|
||||
MConfigPtr = 0xF15, // Pointer to configuration data structure
|
||||
|
||||
MStatus = 0x300, // Machine status register
|
||||
MISA = 0x301, // ISA and extensions
|
||||
MEDeleg = 0x302, // Machine exception delegation register
|
||||
MIDeleg = 0x303, // Machine interrupt delegation register
|
||||
MIE = 0x304, // Machine interrupt-enable register
|
||||
MRVec = 0x305, // Machine trap-handler base address
|
||||
MCounterEn = 0x306, // Machine counter enable
|
||||
MVIEN = 0x308, // Machine virtual interrupt enables
|
||||
MVIP = 0x309, // Machine virtual interrupt-pending bits
|
||||
MStatusH = 0x310, // Additional machine status register, RV32 only
|
||||
|
||||
MIDelegH = 0x313, // Upper 32 bits of of mideleg (only with S-mode)
|
||||
MIEH = 0x314, // Upper 32 bits of mie
|
||||
MVIENH = 0x318, // Upper 32 bits of mvien (only with S-mode)
|
||||
MVIPH = 0x319, // Upper 32 bits of mvip (only with S-mode)
|
||||
MIPH = 0x354, // Upper 32 bits of mip
|
||||
|
||||
MScratch = 0x340, // Scratch register for machine trap handlers
|
||||
MEPC = 0x341, // Machine exception program counter
|
||||
MCause = 0x342, // Machine trap cause
|
||||
MTVal = 0x343, // Machine bad address or instruction
|
||||
MIP = 0x344, // Machine interrupt pending
|
||||
MTInst = 0x34A, // Machine trap instruction (transformed)
|
||||
MTVal2 = 0x34B, // Machine bad guest physical address
|
||||
|
||||
MISelect = 0x350, // Machine indirect register select
|
||||
MIReg = 0x351, // Machine indirect register alias
|
||||
|
||||
MTopEI = 0x35C, // Machine top external interrupt (only with an IMSIC)
|
||||
MTopI = 0xFB0, // Machine top interrupt
|
||||
|
||||
MEnvCfg = 0x30A, // Machine environment configuration register
|
||||
MEnvCfgH = 0x31A, // Additional machine environment configuration register, RV32 only
|
||||
MSecCfg = 0x747, // Machine security configuration register
|
||||
MSecCfgH = 0x757, // Additional machine security configuration register, RV32 only
|
||||
|
||||
PMPCfg0 = 0x3A0, // Physical memory protection configuration
|
||||
PMPCfg1 = 0x3A1, // Physical memory protection configuration, RV32 only
|
||||
PMPCfg2 = 0x3A2, // Physical memory protection configuration
|
||||
PMPCfg3 = 0x3A3, // Physical memory protection configuration, RV32 only
|
||||
PMPCfg4 = 0x3A4, // Physical memory protection configuration
|
||||
PMPCfg5 = 0x3A5, // Physical memory protection configuration, RV32 only
|
||||
PMPCfg6 = 0x3A6, // Physical memory protection configuration
|
||||
PMPCfg7 = 0x3A7, // Physical memory protection configuration, RV32 only
|
||||
PMPCfg8 = 0x3A8, // Physical memory protection configuration
|
||||
PMPCfg9 = 0x3A9, // Physical memory protection configuration, RV32 only
|
||||
PMPCfg10 = 0x3AA, // Physical memory protection configuration
|
||||
PMPCfg11 = 0x3AB, // Physical memory protection configuration, RV32 only
|
||||
PMPCfg12 = 0x3AC, // Physical memory protection configuration
|
||||
PMPCfg13 = 0x3AD, // Physical memory protection configuration, RV32 only
|
||||
PMPCfg14 = 0x3AE, // Physical memory protection configuration
|
||||
PMPCfg15 = 0x3AF, // Physical memory protection configuration, RV32 only
|
||||
PMPAddr0 = 0x3B0, // Physical memory protection address register
|
||||
PMPAddr1 = 0x3B1, // Physical memory protection address register
|
||||
PMPAddr2 = 0x3B2, // Physical memory protection address register
|
||||
PMPAddr3 = 0x3B3, // Physical memory protection address register
|
||||
PMPAddr4 = 0x3B4, // Physical memory protection address register
|
||||
PMPAddr5 = 0x3B5, // Physical memory protection address register
|
||||
PMPAddr6 = 0x3B6, // Physical memory protection address register
|
||||
PMPAddr7 = 0x3B7, // Physical memory protection address register
|
||||
PMPAddr8 = 0x3B8, // Physical memory protection address register
|
||||
PMPAddr9 = 0x3B9, // Physical memory protection address register
|
||||
PMPAddr10 = 0x3BA, // Physical memory protection address register
|
||||
PMPAddr11 = 0x3BB, // Physical memory protection address register
|
||||
PMPAddr12 = 0x3BC, // Physical memory protection address register
|
||||
PMPAddr13 = 0x3BD, // Physical memory protection address register
|
||||
PMPAddr14 = 0x3BE, // Physical memory protection address register
|
||||
PMPAddr15 = 0x3BF, // Physical memory protection address register
|
||||
PMPAddr16 = 0x3C0, // Physical memory protection address register
|
||||
PMPAddr17 = 0x3C1, // Physical memory protection address register
|
||||
PMPAddr18 = 0x3C2, // Physical memory protection address register
|
||||
PMPAddr19 = 0x3C3, // Physical memory protection address register
|
||||
PMPAddr20 = 0x3C4, // Physical memory protection address register
|
||||
PMPAddr21 = 0x3C5, // Physical memory protection address register
|
||||
PMPAddr22 = 0x3C6, // Physical memory protection address register
|
||||
PMPAddr23 = 0x3C7, // Physical memory protection address register
|
||||
PMPAddr24 = 0x3C8, // Physical memory protection address register
|
||||
PMPAddr25 = 0x3C9, // Physical memory protection address register
|
||||
PMPAddr26 = 0x3CA, // Physical memory protection address register
|
||||
PMPAddr27 = 0x3CB, // Physical memory protection address register
|
||||
PMPAddr28 = 0x3CC, // Physical memory protection address register
|
||||
PMPAddr29 = 0x3CD, // Physical memory protection address register
|
||||
PMPAddr30 = 0x3CE, // Physical memory protection address register
|
||||
PMPAddr31 = 0x3CF, // Physical memory protection address register
|
||||
PMPAddr32 = 0x3D0, // Physical memory protection address register
|
||||
PMPAddr33 = 0x3D1, // Physical memory protection address register
|
||||
PMPAddr34 = 0x3D2, // Physical memory protection address register
|
||||
PMPAddr35 = 0x3D3, // Physical memory protection address register
|
||||
PMPAddr36 = 0x3D4, // Physical memory protection address register
|
||||
PMPAddr37 = 0x3D5, // Physical memory protection address register
|
||||
PMPAddr38 = 0x3D6, // Physical memory protection address register
|
||||
PMPAddr39 = 0x3D7, // Physical memory protection address register
|
||||
PMPAddr40 = 0x3D8, // Physical memory protection address register
|
||||
PMPAddr41 = 0x3D9, // Physical memory protection address register
|
||||
PMPAddr42 = 0x3DA, // Physical memory protection address register
|
||||
PMPAddr43 = 0x3DB, // Physical memory protection address register
|
||||
PMPAddr44 = 0x3DC, // Physical memory protection address register
|
||||
PMPAddr45 = 0x3DD, // Physical memory protection address register
|
||||
PMPAddr46 = 0x3DE, // Physical memory protection address register
|
||||
PMPAddr47 = 0x3DF, // Physical memory protection address register
|
||||
PMPAddr48 = 0x3E0, // Physical memory protection address register
|
||||
PMPAddr49 = 0x3E1, // Physical memory protection address register
|
||||
PMPAddr50 = 0x3E2, // Physical memory protection address register
|
||||
PMPAddr51 = 0x3E3, // Physical memory protection address register
|
||||
PMPAddr52 = 0x3E4, // Physical memory protection address register
|
||||
PMPAddr53 = 0x3E5, // Physical memory protection address register
|
||||
PMPAddr54 = 0x3E6, // Physical memory protection address register
|
||||
PMPAddr55 = 0x3E7, // Physical memory protection address register
|
||||
PMPAddr56 = 0x3E8, // Physical memory protection address register
|
||||
PMPAddr57 = 0x3E9, // Physical memory protection address register
|
||||
PMPAddr58 = 0x3EA, // Physical memory protection address register
|
||||
PMPAddr59 = 0x3EB, // Physical memory protection address register
|
||||
PMPAddr60 = 0x3EC, // Physical memory protection address register
|
||||
PMPAddr61 = 0x3ED, // Physical memory protection address register
|
||||
PMPAddr62 = 0x3EE, // Physical memory protection address register
|
||||
PMPAddr63 = 0x3EF, // Physical memory protection address register
|
||||
|
||||
MNScratch = 0x740, // Resumable NMI scratch register
|
||||
MNEPC = 0x741, // Resumable NMI program counter
|
||||
MNCause = 0x742, // Resumable NMI cause
|
||||
MNStatus = 0x744, // Resumable NMI status
|
||||
|
||||
MCycle = 0xB00, // Machine cycle counter
|
||||
MInstRet = 0xB02, // Machine instructions-retired counter
|
||||
MHPMCounter3 = 0xB03, // Machine performance-monitoring counter
|
||||
MHPMCounter4 = 0xB04, // Machine performance-monitoring counter
|
||||
MHPMCounter5 = 0xB05, // Machine performance-monitoring counter
|
||||
MHPMCounter6 = 0xB06, // Machine performance-monitoring counter
|
||||
MHPMCounter7 = 0xB07, // Machine performance-monitoring counter
|
||||
MHPMCounter8 = 0xB08, // Machine performance-monitoring counter
|
||||
MHPMCounter9 = 0xB09, // Machine performance-monitoring counter
|
||||
MHPMCounter10 = 0xB0A, // Machine performance-monitoring counter
|
||||
MHPMCounter11 = 0xB0B, // Machine performance-monitoring counter
|
||||
MHPMCounter12 = 0xB0C, // Machine performance-monitoring counter
|
||||
MHPMCounter13 = 0xB0D, // Machine performance-monitoring counter
|
||||
MHPMCounter14 = 0xB0E, // Machine performance-monitoring counter
|
||||
MHPMCounter15 = 0xB0F, // Machine performance-monitoring counter
|
||||
MHPMCounter16 = 0xB10, // Machine performance-monitoring counter
|
||||
MHPMCounter17 = 0xB11, // Machine performance-monitoring counter
|
||||
MHPMCounter18 = 0xB12, // Machine performance-monitoring counter
|
||||
MHPMCounter19 = 0xB13, // Machine performance-monitoring counter
|
||||
MHPMCounter20 = 0xB14, // Machine performance-monitoring counter
|
||||
MHPMCounter21 = 0xB15, // Machine performance-monitoring counter
|
||||
MHPMCounter22 = 0xB16, // Machine performance-monitoring counter
|
||||
MHPMCounter23 = 0xB17, // Machine performance-monitoring counter
|
||||
MHPMCounter24 = 0xB18, // Machine performance-monitoring counter
|
||||
MHPMCounter25 = 0xB19, // Machine performance-monitoring counter
|
||||
MHPMCounter26 = 0xB1A, // Machine performance-monitoring counter
|
||||
MHPMCounter27 = 0xB1B, // Machine performance-monitoring counter
|
||||
MHPMCounter28 = 0xB1C, // Machine performance-monitoring counter
|
||||
MHPMCounter29 = 0xB1D, // Machine performance-monitoring counter
|
||||
MHPMCounter30 = 0xB1E, // Machine performance-monitoring counter
|
||||
MHPMCounter31 = 0xB1F, // Machine performance-monitoring counter
|
||||
|
||||
MCycleH = 0xB80, // Upper 32 bits ofmcycle, RV32I only
|
||||
MInstRetH = 0xB82, // Upper 32 bits ofminstret, RV32I only
|
||||
|
||||
MHPMCounter3H = 0xB83, // Upper 32 bits of MHPMCounter3, RV32I only
|
||||
MHPMCounter4H = 0xB84, // Upper 32 bits of MHPMCounter4, RV32I only
|
||||
MHPMCounter5H = 0xB85, // Upper 32 bits of MHPMCounter5, RV32I only
|
||||
MHPMCounter6H = 0xB86, // Upper 32 bits of MHPMCounter6, RV32I only
|
||||
MHPMCounter7H = 0xB87, // Upper 32 bits of MHPMCounter7, RV32I only
|
||||
MHPMCounter8H = 0xB88, // Upper 32 bits of MHPMCounter8, RV32I only
|
||||
MHPMCounter9H = 0xB89, // Upper 32 bits of MHPMCounter9, RV32I only
|
||||
MHPMCounter10H = 0xB8A, // Upper 32 bits of MHPMCounter10, RV32I only
|
||||
MHPMCounter11H = 0xB8B, // Upper 32 bits of MHPMCounter11, RV32I only
|
||||
MHPMCounter12H = 0xB8C, // Upper 32 bits of MHPMCounter12, RV32I only
|
||||
MHPMCounter13H = 0xB8D, // Upper 32 bits of MHPMCounter13, RV32I only
|
||||
MHPMCounter14H = 0xB8E, // Upper 32 bits of MHPMCounter14, RV32I only
|
||||
MHPMCounter15H = 0xB8F, // Upper 32 bits of MHPMCounter15, RV32I only
|
||||
MHPMCounter16H = 0xB90, // Upper 32 bits of MHPMCounter16, RV32I only
|
||||
MHPMCounter17H = 0xB91, // Upper 32 bits of MHPMCounter17, RV32I only
|
||||
MHPMCounter18H = 0xB92, // Upper 32 bits of MHPMCounter18, RV32I only
|
||||
MHPMCounter19H = 0xB93, // Upper 32 bits of MHPMCounter19, RV32I only
|
||||
MHPMCounter20H = 0xB94, // Upper 32 bits of MHPMCounter20, RV32I only
|
||||
MHPMCounter21H = 0xB95, // Upper 32 bits of MHPMCounter21, RV32I only
|
||||
MHPMCounter22H = 0xB96, // Upper 32 bits of MHPMCounter22, RV32I only
|
||||
MHPMCounter23H = 0xB97, // Upper 32 bits of MHPMCounter23, RV32I only
|
||||
MHPMCounter24H = 0xB98, // Upper 32 bits of MHPMCounter24, RV32I only
|
||||
MHPMCounter25H = 0xB99, // Upper 32 bits of MHPMCounter25, RV32I only
|
||||
MHPMCounter26H = 0xB9A, // Upper 32 bits of MHPMCounter26, RV32I only
|
||||
MHPMCounter27H = 0xB9B, // Upper 32 bits of MHPMCounter27, RV32I only
|
||||
MHPMCounter28H = 0xB9C, // Upper 32 bits of MHPMCounter28, RV32I only
|
||||
MHPMCounter29H = 0xB9D, // Upper 32 bits of MHPMCounter29, RV32I only
|
||||
MHPMCounter30H = 0xB9E, // Upper 32 bits of MHPMCounter30, RV32I only
|
||||
MHPMCounter31H = 0xB9F, // Upper 32 bits of MHPMCounter31, RV32I only
|
||||
|
||||
MCountInhibit = 0x320, // Machine counter-inhibit register
|
||||
|
||||
MCycleCfg = 0x321, // Privilege mode filtering for cycle counter
|
||||
MCycleCfgH = 0x721, // Privilege mode filtering for cycle counter (RV32)
|
||||
MInstRetCfg = 0x322, // Privilege mode filtering for instret counters
|
||||
MInstRetCfgH = 0x722, // Privilege mode filtering for instret counters (RV32)
|
||||
|
||||
MHPMEvent3 = 0x323, // Machine performance-monitoring event selector
|
||||
MHPMEvent4 = 0x324, // Machine performance-monitoring event selector
|
||||
MHPMEvent5 = 0x325, // Machine performance-monitoring event selector
|
||||
MHPMEvent6 = 0x326, // Machine performance-monitoring event selector
|
||||
MHPMEvent7 = 0x327, // Machine performance-monitoring event selector
|
||||
MHPMEvent8 = 0x328, // Machine performance-monitoring event selector
|
||||
MHPMEvent9 = 0x329, // Machine performance-monitoring event selector
|
||||
MHPMEvent10 = 0x32A, // Machine performance-monitoring event selector
|
||||
MHPMEvent11 = 0x32B, // Machine performance-monitoring event selector
|
||||
MHPMEvent12 = 0x32C, // Machine performance-monitoring event selector
|
||||
MHPMEvent13 = 0x32D, // Machine performance-monitoring event selector
|
||||
MHPMEvent14 = 0x32E, // Machine performance-monitoring event selector
|
||||
MHPMEvent15 = 0x32F, // Machine performance-monitoring event selector
|
||||
MHPMEvent16 = 0x330, // Machine performance-monitoring event selector
|
||||
MHPMEvent17 = 0x331, // Machine performance-monitoring event selector
|
||||
MHPMEvent18 = 0x332, // Machine performance-monitoring event selector
|
||||
MHPMEvent19 = 0x333, // Machine performance-monitoring event selector
|
||||
MHPMEvent20 = 0x334, // Machine performance-monitoring event selector
|
||||
MHPMEvent21 = 0x335, // Machine performance-monitoring event selector
|
||||
MHPMEvent22 = 0x336, // Machine performance-monitoring event selector
|
||||
MHPMEvent23 = 0x337, // Machine performance-monitoring event selector
|
||||
MHPMEvent24 = 0x338, // Machine performance-monitoring event selector
|
||||
MHPMEvent25 = 0x339, // Machine performance-monitoring event selector
|
||||
MHPMEvent26 = 0x33A, // Machine performance-monitoring event selector
|
||||
MHPMEvent27 = 0x33B, // Machine performance-monitoring event selector
|
||||
MHPMEvent28 = 0x33C, // Machine performance-monitoring event selector
|
||||
MHPMEvent29 = 0x33D, // Machine performance-monitoring event selector
|
||||
MHPMEvent30 = 0x33E, // Machine performance-monitoring event selector
|
||||
MHPMEvent31 = 0x33F, // Machine performance-monitoring event selector
|
||||
|
||||
TSelect = 0x7A0, // Debug/Trace trigger register select
|
||||
TData1 = 0x7A1, // First Debug/Trace trigger data register
|
||||
TData2 = 0x7A2, // Second Debug/Trace trigger data register
|
||||
TData3 = 0x7A3, // Third Debug/Trace trigger data register
|
||||
MContext = 0x7A8, // Machine-mode context register
|
||||
|
||||
DCSR = 0x7B0, // Debug control and status register
|
||||
DPC = 0x7B1, // Debug PC
|
||||
DScratch0 = 0x7B2, // Debug scratch register 0
|
||||
DScratch1 = 0x7B3, // Debug scratch register 1
|
||||
|
||||
// Scalar Cryptography Entropy Source Extension CSRs
|
||||
|
||||
Seed = 0x015, // Entropy bit provider (up to 16 bits)
|
||||
|
||||
// Vector Extension CSRs
|
||||
|
||||
VStart = 0x008, // Vector start position
|
||||
VXSat = 0x009, // Fixed-Point Saturate Flag
|
||||
VXRM = 0x00A, // Fixed-Point Rounding Mode
|
||||
VCSR = 0x00F, // Vector control and status register
|
||||
VL = 0xC20, // Vector length
|
||||
VType = 0xC21, // Vector data type register
|
||||
VLenb = 0xC22, // Vector register length in bytes
|
||||
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
} // namespace biscuit
|
@ -1,49 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// Source file for general values and data structures
|
||||
// that don't fit a particular criteria related to the ISA.
|
||||
|
||||
namespace biscuit {
|
||||
|
||||
enum class FenceOrder : uint32_t {
|
||||
W = 1, // Write
|
||||
R = 2, // Read
|
||||
O = 4, // Device Output
|
||||
I = 8, // Device Input
|
||||
|
||||
RW = R | W,
|
||||
|
||||
IO = I | O,
|
||||
IR = I | R,
|
||||
IW = I | W,
|
||||
IRW = I | R | W,
|
||||
|
||||
OI = O | I,
|
||||
OR = O | R,
|
||||
OW = O | W,
|
||||
ORW = O | R | W,
|
||||
|
||||
IORW = I | O | R | W,
|
||||
};
|
||||
|
||||
// Atomic ordering
|
||||
enum class Ordering : uint32_t {
|
||||
None = 0, // None
|
||||
RL = 1, // Release
|
||||
AQ = 2, // Acquire
|
||||
AQRL = AQ | RL, // Acquire-Release
|
||||
};
|
||||
|
||||
// Floating-point Rounding Mode
|
||||
enum class RMode : uint32_t {
|
||||
RNE = 0b000, // Round to Nearest, ties to Even
|
||||
RTZ = 0b001, // Round towards Zero
|
||||
RDN = 0b010, // Round Down (towards negative infinity)
|
||||
RUP = 0b011, // Round Up (towards positive infinity)
|
||||
RMM = 0b100, // Round to Nearest, ties to Max Magnitude
|
||||
DYN = 0b111, // Dynamic Rounding Mode
|
||||
};
|
||||
|
||||
} // namespace biscuit
|
@ -1,173 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <biscuit/assert.hpp>
|
||||
|
||||
namespace biscuit {
|
||||
|
||||
/**
|
||||
* A label is a representation of an address that can be used with branch and jump instructions.
|
||||
*
|
||||
* Labels do not need to be bound to a location immediately. A label can be created
|
||||
* to provide branches with a tentative, undecided location that is then bound
|
||||
* at a later point in time.
|
||||
*
|
||||
* @note Any label that is created, is used with a branch instruction,
|
||||
* but is *not* bound to a location (via Bind() in the assembler)
|
||||
* will result in an assertion being invoked when the label instance's
|
||||
* destructor is executed.
|
||||
*
|
||||
* @note A label may only be bound to one location. Any attempt to rebind
|
||||
* a label that is already bound will result in an assertion being
|
||||
* invoked.
|
||||
*
|
||||
* @par
|
||||
* An example of binding a label:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* Assembler as{...};
|
||||
* Label label;
|
||||
*
|
||||
* as.BNE(x2, x3, &label); // Use the label
|
||||
* as.ADD(x7, x8, x9);
|
||||
* as.XOR(x7, x10, x12);
|
||||
* as.Bind(&label); // Bind the label to a location
|
||||
* @endcode
|
||||
*/
|
||||
class Label {
|
||||
public:
|
||||
using Location = std::optional<ptrdiff_t>;
|
||||
using LocationOffset = Location::value_type;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*
|
||||
* This constructor results in a label being constructed that is not
|
||||
* bound to a particular location yet.
|
||||
*/
|
||||
explicit Label() = default;
|
||||
|
||||
/// Destructor
|
||||
~Label() noexcept {
|
||||
// It's a logic bug if something references a label and hasn't been handled.
|
||||
//
|
||||
// This is usually indicative of a scenario where a label is referenced but
|
||||
// hasn't been bound to a location.
|
||||
//
|
||||
BISCUIT_ASSERT(IsResolved());
|
||||
}
|
||||
|
||||
// We disable copying of labels, as this doesn't really make sense to do.
|
||||
// It also presents a problem. When labels are being resolved, if we have
|
||||
// two labels pointing to the same place, resolving the links to this address
|
||||
// are going to clobber each other N times for however many copies of the label
|
||||
// exist.
|
||||
//
|
||||
// This isn't a particularly major problem, since the resolving will still result
|
||||
// in the same end result, but it does make it annoying to think about label interactions
|
||||
// moving forward. Thus, I choose to simply not think about it at all!
|
||||
//
|
||||
Label(const Label&) = delete;
|
||||
Label& operator=(const Label&) = delete;
|
||||
|
||||
// Moving labels on the other hand is totally fine, this is just pushing data around
|
||||
// to another label while invalidating the label having it's data "stolen".
|
||||
Label(Label&&) noexcept = default;
|
||||
Label& operator=(Label&&) noexcept = default;
|
||||
|
||||
/**
|
||||
* Determines whether or not this label instance has a location assigned to it.
|
||||
*
|
||||
* A label is considered bound if it has an assigned location.
|
||||
*/
|
||||
[[nodiscard]] bool IsBound() const noexcept {
|
||||
return m_location.has_value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not this label is resolved.
|
||||
*
|
||||
* A label is considered resolved when all referencing offsets have been handled.
|
||||
*/
|
||||
[[nodiscard]] bool IsResolved() const noexcept {
|
||||
return m_offsets.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not this label is unresolved.
|
||||
*
|
||||
* A label is considered unresolved if it still has any unhandled referencing offsets.
|
||||
*/
|
||||
[[nodiscard]] bool IsUnresolved() const noexcept {
|
||||
return !IsResolved();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the location for this label.
|
||||
*
|
||||
* @note If the returned location is empty, then this label has not been assigned
|
||||
* a location yet.
|
||||
*/
|
||||
[[nodiscard]] Location GetLocation() const noexcept {
|
||||
return m_location;
|
||||
}
|
||||
|
||||
private:
|
||||
// A label instance is inherently bound to the assembler it's
|
||||
// used with, as the offsets within the label set depend on
|
||||
// said assemblers code buffer.
|
||||
friend class Assembler;
|
||||
|
||||
/**
|
||||
* Binds a label to the given location.
|
||||
*
|
||||
* @param offset The instruction offset to bind this label to.
|
||||
*
|
||||
* @pre The label must not have already been bound to a previous location.
|
||||
* Attempting to rebind a label is typically, in almost all scenarios,
|
||||
* the source of bugs.
|
||||
* Attempting to rebind an already bound label will result in an assertion
|
||||
* being triggered.
|
||||
*/
|
||||
void Bind(LocationOffset offset) noexcept {
|
||||
BISCUIT_ASSERT(!IsBound());
|
||||
m_location = offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the given address as dependent on this label.
|
||||
*
|
||||
* This is used in scenarios where a label exists, but has not yet been
|
||||
* bound to a location yet. It's important to track these addresses,
|
||||
* as we'll need to patch the dependent branch instructions with the
|
||||
* proper offset once the label is finally bound by the assembler.
|
||||
*
|
||||
* During label binding, the offset will be calculated and inserted
|
||||
* into dependent instructions.
|
||||
*/
|
||||
void AddOffset(LocationOffset offset) {
|
||||
// If a label is already bound to a location, then offset tracking
|
||||
// isn't necessary. Tripping this assert means we have a bug somewhere.
|
||||
BISCUIT_ASSERT(!IsBound());
|
||||
BISCUIT_ASSERT(IsNewOffset(offset));
|
||||
|
||||
m_offsets.insert(offset);
|
||||
}
|
||||
|
||||
// Clears all the underlying offsets for this label.
|
||||
void ClearOffsets() noexcept {
|
||||
m_offsets.clear();
|
||||
}
|
||||
|
||||
// Determines whether or not this address has already been added before.
|
||||
[[nodiscard]] bool IsNewOffset(LocationOffset offset) const noexcept {
|
||||
return m_offsets.find(offset) == m_offsets.cend();
|
||||
}
|
||||
|
||||
std::set<LocationOffset> m_offsets;
|
||||
Location m_location;
|
||||
};
|
||||
|
||||
} // namespace biscuit
|
@ -1,315 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <biscuit/assert.hpp>
|
||||
|
||||
#include <compare>
|
||||
#include <cstdint>
|
||||
|
||||
namespace biscuit {
|
||||
|
||||
/**
|
||||
* Generic abstraction around a register.
|
||||
*
|
||||
* This is less bug-prone than using raw primitive sizes
|
||||
* in opcode emitter functions, since it provides stronger typing.
|
||||
*/
|
||||
class Register {
|
||||
public:
|
||||
constexpr Register() noexcept = default;
|
||||
|
||||
/// Gets the index for this register.
|
||||
[[nodiscard]] constexpr uint32_t Index() const noexcept {
|
||||
return m_index;
|
||||
}
|
||||
|
||||
friend constexpr bool operator==(Register, Register) = default;
|
||||
friend constexpr auto operator<=>(Register, Register) = default;
|
||||
|
||||
protected:
|
||||
constexpr explicit Register(uint32_t index) noexcept
|
||||
: m_index{index} {}
|
||||
|
||||
private:
|
||||
uint32_t m_index{};
|
||||
};
|
||||
|
||||
/// General purpose register.
|
||||
class GPR final : public Register {
|
||||
public:
|
||||
constexpr GPR() noexcept : Register{0} {}
|
||||
constexpr explicit GPR(uint32_t index) noexcept : Register{index} {}
|
||||
|
||||
friend constexpr bool operator==(GPR, GPR) = default;
|
||||
friend constexpr auto operator<=>(GPR, GPR) = default;
|
||||
};
|
||||
|
||||
/// Floating point register.
|
||||
class FPR final : public Register {
|
||||
public:
|
||||
constexpr FPR() noexcept : Register{0} {}
|
||||
constexpr explicit FPR(uint32_t index) noexcept : Register{index} {}
|
||||
|
||||
friend constexpr bool operator==(FPR, FPR) = default;
|
||||
friend constexpr auto operator<=>(FPR, FPR) = default;
|
||||
};
|
||||
|
||||
/// Vector register.
|
||||
class Vec final : public Register {
|
||||
public:
|
||||
constexpr Vec() noexcept : Register{0} {}
|
||||
constexpr explicit Vec(uint32_t index) noexcept : Register{index} {}
|
||||
|
||||
friend constexpr bool operator==(Vec, Vec) = default;
|
||||
friend constexpr auto operator<=>(Vec, Vec) = default;
|
||||
};
|
||||
|
||||
// General-purpose Registers
|
||||
|
||||
constexpr GPR x0{0};
|
||||
constexpr GPR x1{1};
|
||||
constexpr GPR x2{2};
|
||||
constexpr GPR x3{3};
|
||||
constexpr GPR x4{4};
|
||||
constexpr GPR x5{5};
|
||||
constexpr GPR x6{6};
|
||||
constexpr GPR x7{7};
|
||||
constexpr GPR x8{8};
|
||||
constexpr GPR x9{9};
|
||||
constexpr GPR x10{10};
|
||||
constexpr GPR x11{11};
|
||||
constexpr GPR x12{12};
|
||||
constexpr GPR x13{13};
|
||||
constexpr GPR x14{14};
|
||||
constexpr GPR x15{15};
|
||||
constexpr GPR x16{16};
|
||||
constexpr GPR x17{17};
|
||||
constexpr GPR x18{18};
|
||||
constexpr GPR x19{19};
|
||||
constexpr GPR x20{20};
|
||||
constexpr GPR x21{21};
|
||||
constexpr GPR x22{22};
|
||||
constexpr GPR x23{23};
|
||||
constexpr GPR x24{24};
|
||||
constexpr GPR x25{25};
|
||||
constexpr GPR x26{26};
|
||||
constexpr GPR x27{27};
|
||||
constexpr GPR x28{28};
|
||||
constexpr GPR x29{29};
|
||||
constexpr GPR x30{30};
|
||||
constexpr GPR x31{31};
|
||||
|
||||
// Symbolic General-purpose Register Names
|
||||
|
||||
constexpr GPR zero{x0};
|
||||
|
||||
constexpr GPR ra{x1};
|
||||
constexpr GPR sp{x2};
|
||||
constexpr GPR gp{x3};
|
||||
constexpr GPR tp{x4};
|
||||
constexpr GPR fp{x8};
|
||||
|
||||
constexpr GPR a0{x10};
|
||||
constexpr GPR a1{x11};
|
||||
constexpr GPR a2{x12};
|
||||
constexpr GPR a3{x13};
|
||||
constexpr GPR a4{x14};
|
||||
constexpr GPR a5{x15};
|
||||
constexpr GPR a6{x16};
|
||||
constexpr GPR a7{x17};
|
||||
|
||||
constexpr GPR s0{x8};
|
||||
constexpr GPR s1{x9};
|
||||
constexpr GPR s2{x18};
|
||||
constexpr GPR s3{x19};
|
||||
constexpr GPR s4{x20};
|
||||
constexpr GPR s5{x21};
|
||||
constexpr GPR s6{x22};
|
||||
constexpr GPR s7{x23};
|
||||
constexpr GPR s8{x24};
|
||||
constexpr GPR s9{x25};
|
||||
constexpr GPR s10{x26};
|
||||
constexpr GPR s11{x27};
|
||||
|
||||
constexpr GPR t0{x5};
|
||||
constexpr GPR t1{x6};
|
||||
constexpr GPR t2{x7};
|
||||
constexpr GPR t3{x28};
|
||||
constexpr GPR t4{x29};
|
||||
constexpr GPR t5{x30};
|
||||
constexpr GPR t6{x31};
|
||||
|
||||
// Floating-point registers
|
||||
|
||||
constexpr FPR f0{0};
|
||||
constexpr FPR f1{1};
|
||||
constexpr FPR f2{2};
|
||||
constexpr FPR f3{3};
|
||||
constexpr FPR f4{4};
|
||||
constexpr FPR f5{5};
|
||||
constexpr FPR f6{6};
|
||||
constexpr FPR f7{7};
|
||||
constexpr FPR f8{8};
|
||||
constexpr FPR f9{9};
|
||||
constexpr FPR f10{10};
|
||||
constexpr FPR f11{11};
|
||||
constexpr FPR f12{12};
|
||||
constexpr FPR f13{13};
|
||||
constexpr FPR f14{14};
|
||||
constexpr FPR f15{15};
|
||||
constexpr FPR f16{16};
|
||||
constexpr FPR f17{17};
|
||||
constexpr FPR f18{18};
|
||||
constexpr FPR f19{19};
|
||||
constexpr FPR f20{20};
|
||||
constexpr FPR f21{21};
|
||||
constexpr FPR f22{22};
|
||||
constexpr FPR f23{23};
|
||||
constexpr FPR f24{24};
|
||||
constexpr FPR f25{25};
|
||||
constexpr FPR f26{26};
|
||||
constexpr FPR f27{27};
|
||||
constexpr FPR f28{28};
|
||||
constexpr FPR f29{29};
|
||||
constexpr FPR f30{30};
|
||||
constexpr FPR f31{31};
|
||||
|
||||
// Symbolic Floating-point Register Names
|
||||
|
||||
constexpr FPR fa0{f10};
|
||||
constexpr FPR fa1{f11};
|
||||
constexpr FPR fa2{f12};
|
||||
constexpr FPR fa3{f13};
|
||||
constexpr FPR fa4{f14};
|
||||
constexpr FPR fa5{f15};
|
||||
constexpr FPR fa6{f16};
|
||||
constexpr FPR fa7{f17};
|
||||
|
||||
constexpr FPR ft0{f0};
|
||||
constexpr FPR ft1{f1};
|
||||
constexpr FPR ft2{f2};
|
||||
constexpr FPR ft3{f3};
|
||||
constexpr FPR ft4{f4};
|
||||
constexpr FPR ft5{f5};
|
||||
constexpr FPR ft6{f6};
|
||||
constexpr FPR ft7{f7};
|
||||
constexpr FPR ft8{f28};
|
||||
constexpr FPR ft9{f29};
|
||||
constexpr FPR ft10{f30};
|
||||
constexpr FPR ft11{f31};
|
||||
|
||||
constexpr FPR fs0{f8};
|
||||
constexpr FPR fs1{f9};
|
||||
constexpr FPR fs2{f18};
|
||||
constexpr FPR fs3{f19};
|
||||
constexpr FPR fs4{f20};
|
||||
constexpr FPR fs5{f21};
|
||||
constexpr FPR fs6{f22};
|
||||
constexpr FPR fs7{f23};
|
||||
constexpr FPR fs8{f24};
|
||||
constexpr FPR fs9{f25};
|
||||
constexpr FPR fs10{f26};
|
||||
constexpr FPR fs11{f27};
|
||||
|
||||
// Vector registers (V extension)
|
||||
|
||||
constexpr Vec v0{0};
|
||||
constexpr Vec v1{1};
|
||||
constexpr Vec v2{2};
|
||||
constexpr Vec v3{3};
|
||||
constexpr Vec v4{4};
|
||||
constexpr Vec v5{5};
|
||||
constexpr Vec v6{6};
|
||||
constexpr Vec v7{7};
|
||||
constexpr Vec v8{8};
|
||||
constexpr Vec v9{9};
|
||||
constexpr Vec v10{10};
|
||||
constexpr Vec v11{11};
|
||||
constexpr Vec v12{12};
|
||||
constexpr Vec v13{13};
|
||||
constexpr Vec v14{14};
|
||||
constexpr Vec v15{15};
|
||||
constexpr Vec v16{16};
|
||||
constexpr Vec v17{17};
|
||||
constexpr Vec v18{18};
|
||||
constexpr Vec v19{19};
|
||||
constexpr Vec v20{20};
|
||||
constexpr Vec v21{21};
|
||||
constexpr Vec v22{22};
|
||||
constexpr Vec v23{23};
|
||||
constexpr Vec v24{24};
|
||||
constexpr Vec v25{25};
|
||||
constexpr Vec v26{26};
|
||||
constexpr Vec v27{27};
|
||||
constexpr Vec v28{28};
|
||||
constexpr Vec v29{29};
|
||||
constexpr Vec v30{30};
|
||||
constexpr Vec v31{31};
|
||||
|
||||
// Register utilities
|
||||
|
||||
// Used with compressed stack management instructions
|
||||
// (cm.push, cm.pop, etc) for building up a register list to encode.
|
||||
//
|
||||
// Also enforces that only valid registers are used in the lists.
|
||||
class PushPopList final {
|
||||
public:
|
||||
// Represents an inclusive range ([start, end]) of registers.
|
||||
struct Range final {
|
||||
// Signifies an empty range. Normally this doesn't need to explicitly
|
||||
// be created. Default parameters will usually take care of it.
|
||||
constexpr Range() : start{UINT32_MAX}, end{UINT32_MAX} {}
|
||||
|
||||
// This particular constructor is used for the case of rlist=5
|
||||
// where only ra and s0 get stored.
|
||||
constexpr Range(GPR start_end) noexcept : start{start_end}, end{start_end} {
|
||||
BISCUIT_ASSERT(start_end == s0);
|
||||
}
|
||||
|
||||
constexpr Range(GPR start_, GPR end_) noexcept : start{start_}, end{end_} {
|
||||
BISCUIT_ASSERT(start_ == s0);
|
||||
BISCUIT_ASSERT(IsSRegister(end_));
|
||||
|
||||
// See the Zc spec. The only way for s10 to be used is to also include s11.
|
||||
BISCUIT_ASSERT(end_ != s10);
|
||||
}
|
||||
|
||||
GPR start;
|
||||
GPR end;
|
||||
};
|
||||
|
||||
// Deliberately non-explicit to allow for convenient instantiation at usage sites.
|
||||
// e.g. Rather than CM.POP(PushPopList{ra, {s0, s2}}, 16), we can just have the
|
||||
// usage be transparent like CM.POP({ra, {s0, s2}}, 16). Nice and compact!
|
||||
constexpr PushPopList(GPR ra_reg, const Range& range = {}) noexcept
|
||||
: m_bitmask{BuildBitmask(range)} {
|
||||
BISCUIT_ASSERT(ra_reg == ra);
|
||||
}
|
||||
|
||||
// Gets the built-up bitmask of passed in registers
|
||||
[[nodiscard]] constexpr uint32_t GetBitmask() const noexcept {
|
||||
return m_bitmask;
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] static constexpr uint32_t BuildBitmask(const Range& range) noexcept {
|
||||
if (range.end.Index() == UINT32_MAX) {
|
||||
return 4U;
|
||||
}
|
||||
if (range.end == s11) {
|
||||
return 15U;
|
||||
}
|
||||
if (range.end == s0 || range.end == s1) {
|
||||
return range.end.Index() - 3U;
|
||||
}
|
||||
return range.end.Index() - 11U;
|
||||
}
|
||||
|
||||
// Aside from ra, it's only valid for s0-s11 to show up the register list ranges.
|
||||
[[nodiscard]] static constexpr bool IsSRegister(const GPR gpr) noexcept {
|
||||
return gpr == s0 || gpr == s1 || (gpr >= s2 && gpr <= s11);
|
||||
}
|
||||
|
||||
uint32_t m_bitmask = 0;
|
||||
};
|
||||
|
||||
} // namespace biscuit
|
@ -1,88 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// Source file for anything specific to the RISC-V vector extension.
|
||||
|
||||
namespace biscuit {
|
||||
|
||||
/// Describes whether or not an instruction should make use of the mask vector.
|
||||
enum class VecMask : uint32_t {
|
||||
Yes = 0,
|
||||
No = 1,
|
||||
};
|
||||
|
||||
/// Describes the selected element width.
|
||||
enum class SEW : uint32_t {
|
||||
E8 = 0b000, // 8-bit vector elements
|
||||
E16 = 0b001, // 16-bit vector elements
|
||||
E32 = 0b010, // 32-bit vector elements
|
||||
E64 = 0b011, // 64-bit vector elements
|
||||
E128 = 0b100, // 128-bit vector elements
|
||||
E256 = 0b101, // 256-bit vector elements
|
||||
E512 = 0b110, // 512-bit vector elements
|
||||
E1024 = 0b111, // 1024-bit vector elements
|
||||
};
|
||||
|
||||
/// Describes the selected register group multiplier.
|
||||
enum class LMUL : uint32_t {
|
||||
M1 = 0b000, // Group of one vector
|
||||
M2 = 0b001, // Groups of two vectors
|
||||
M4 = 0b010, // Groups of four vectors
|
||||
M8 = 0b011, // Groups of eight vectors
|
||||
MF8 = 0b101, // Fractional vector group (1/8)
|
||||
MF4 = 0b110, // Fractional vector group (1/4)
|
||||
MF2 = 0b111, // Fractional vector group (1/2)
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes whether or not vector masks are agnostic.
|
||||
*
|
||||
* From the RVV spec:
|
||||
*
|
||||
* When a set is marked undisturbed, the corresponding set of
|
||||
* destination elements in a vector register group retain the
|
||||
* value they previously held.
|
||||
*
|
||||
* When a set is marked agnostic, the corresponding set of destination
|
||||
* elements in any vector destination operand can either retain the value
|
||||
* they previously held, or are overwritten with 1s.
|
||||
*
|
||||
* Within a single vector instruction, each destination element can be either
|
||||
* left undisturbed or overwritten with 1s, in any combination, and the pattern
|
||||
* of undisturbed or overwritten with 1s is not required to be deterministic when
|
||||
* the instruction is executed with the same inputs. In addition, except for
|
||||
* mask load instructions, any element in the tail of a mask result can also be
|
||||
* written with the value the mask-producing operation would have calculated with vl=VLMAX
|
||||
*/
|
||||
enum class VMA : uint32_t {
|
||||
No, // Undisturbed
|
||||
Yes, // Agnostic
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes whether or not vector tail elements are agnostic.
|
||||
*
|
||||
* From the RVV spec:
|
||||
*
|
||||
* When a set is marked undisturbed, the corresponding set of
|
||||
* destination elements in a vector register group retain the
|
||||
* value they previously held.
|
||||
*
|
||||
* When a set is marked agnostic, the corresponding set of destination
|
||||
* elements in any vector destination operand can either retain the value
|
||||
* they previously held, or are overwritten with 1s.
|
||||
*
|
||||
* Within a single vector instruction, each destination element can be either
|
||||
* left undisturbed or overwritten with 1s, in any combination, and the pattern
|
||||
* of undisturbed or overwritten with 1s is not required to be deterministic when
|
||||
* the instruction is executed with the same inputs. In addition, except for
|
||||
* mask load instructions, any element in the tail of a mask result can also be
|
||||
* written with the value the mask-producing operation would have calculated with vl=VLMAX
|
||||
*/
|
||||
enum class VTA : uint32_t {
|
||||
No, // Undisturbed
|
||||
Yes, // Agnostic
|
||||
};
|
||||
|
||||
} // namespace biscuit
|
@ -1,156 +0,0 @@
|
||||
# Main library
|
||||
|
||||
add_library(biscuit
|
||||
# Source files
|
||||
assembler.cpp
|
||||
assembler_compressed.cpp
|
||||
assembler_crypto.cpp
|
||||
assembler_floating_point.cpp
|
||||
assembler_vector.cpp
|
||||
code_buffer.cpp
|
||||
cpuinfo.cpp
|
||||
|
||||
# Headers
|
||||
assembler_util.hpp
|
||||
"${PROJECT_SOURCE_DIR}/include/biscuit/assembler.hpp"
|
||||
"${PROJECT_SOURCE_DIR}/include/biscuit/assert.hpp"
|
||||
"${PROJECT_SOURCE_DIR}/include/biscuit/code_buffer.hpp"
|
||||
"${PROJECT_SOURCE_DIR}/include/biscuit/csr.hpp"
|
||||
"${PROJECT_SOURCE_DIR}/include/biscuit/isa.hpp"
|
||||
"${PROJECT_SOURCE_DIR}/include/biscuit/label.hpp"
|
||||
"${PROJECT_SOURCE_DIR}/include/biscuit/registers.hpp"
|
||||
"${PROJECT_SOURCE_DIR}/include/biscuit/vector.hpp"
|
||||
"${PROJECT_SOURCE_DIR}/include/biscuit/cpuinfo.hpp"
|
||||
)
|
||||
add_library(biscuit::biscuit ALIAS biscuit)
|
||||
|
||||
target_include_directories(biscuit
|
||||
PUBLIC
|
||||
$<INSTALL_INTERFACE:include>
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
target_compile_features(biscuit
|
||||
PRIVATE
|
||||
cxx_std_20
|
||||
)
|
||||
|
||||
if (MSVC)
|
||||
target_compile_options(biscuit
|
||||
PRIVATE
|
||||
/MP
|
||||
/Zi
|
||||
/Zo
|
||||
/permissive-
|
||||
/EHsc
|
||||
/utf-8
|
||||
/volatile:iso
|
||||
/Zc:externConstexpr
|
||||
/Zc:inline
|
||||
/Zc:throwingNew
|
||||
|
||||
# Warnings
|
||||
/W4
|
||||
/we4062 # enumerator 'identifier' in a switch of enum 'enumeration' is not handled
|
||||
/we4101 # 'identifier': unreferenced local variable
|
||||
/we4265 # 'class': class has virtual functions, but destructor is not virtual
|
||||
/we4287 # 'operator' : unsigned/negative constant mismatch
|
||||
/we4365 # 'action' : conversion from 'type_1' to 'type_2', signed/unsigned mismatch
|
||||
/we4388 # signed/unsigned mismatch
|
||||
/we4547 # 'operator' : operator before comma has no effect; expected operator with side-effect
|
||||
/we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'?
|
||||
/we4555 # Expression has no effect; expected expression with side-effect
|
||||
/we4715 # 'function': not all control paths return a value
|
||||
/we4834 # Discarding return value of function with 'nodiscard' attribute
|
||||
/we5038 # data member 'member1' will be initialized after data member 'member2'
|
||||
)
|
||||
elseif (("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU"))
|
||||
target_compile_options(biscuit
|
||||
PRIVATE
|
||||
-Wall
|
||||
-Wextra
|
||||
-Wconversion
|
||||
-Wsign-conversion
|
||||
|
||||
-Werror=array-bounds
|
||||
-Werror=cast-qual
|
||||
-Werror=ignored-qualifiers
|
||||
-Werror=implicit-fallthrough
|
||||
-Werror=sign-compare
|
||||
-Werror=reorder
|
||||
-Werror=uninitialized
|
||||
-Werror=unused-function
|
||||
-Werror=unused-result
|
||||
-Werror=unused-variable
|
||||
)
|
||||
endif()
|
||||
|
||||
if (BISCUIT_CODE_BUFFER_MMAP)
|
||||
target_compile_definitions(biscuit
|
||||
PRIVATE
|
||||
-DBISCUIT_CODE_BUFFER_MMAP
|
||||
)
|
||||
endif()
|
||||
|
||||
# Install target
|
||||
|
||||
include(GNUInstallDirs)
|
||||
set(BISCUIT_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/biscuit")
|
||||
|
||||
# Set install target and relevant includes.
|
||||
install(TARGETS biscuit
|
||||
EXPORT biscuit-targets
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
)
|
||||
install(
|
||||
DIRECTORY "${PROJECT_SOURCE_DIR}/include/"
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
)
|
||||
|
||||
# Export targets to a script
|
||||
install(EXPORT biscuit-targets
|
||||
FILE
|
||||
biscuit-targets.cmake
|
||||
NAMESPACE
|
||||
biscuit::
|
||||
DESTINATION
|
||||
"${BISCUIT_INSTALL_CONFIGDIR}"
|
||||
)
|
||||
|
||||
# Now create the config version script
|
||||
include(CMakePackageConfigHelpers)
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/biscuit-config-version.cmake"
|
||||
VERSION
|
||||
${PROJECT_VERSION}
|
||||
COMPATIBILITY
|
||||
SameMajorVersion
|
||||
)
|
||||
|
||||
configure_package_config_file(
|
||||
"${PROJECT_SOURCE_DIR}/cmake/biscuit-config.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/biscuit-config.cmake"
|
||||
|
||||
INSTALL_DESTINATION "${BISCUIT_INSTALL_CONFIGDIR}"
|
||||
)
|
||||
|
||||
# Now install the config and version files.
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/biscuit-config.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/biscuit-config-version.cmake"
|
||||
|
||||
DESTINATION "${BISCUIT_INSTALL_CONFIGDIR}"
|
||||
)
|
||||
|
||||
# Export library from the build tree.
|
||||
export(EXPORT biscuit-targets
|
||||
FILE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/biscuit-targets.cmake"
|
||||
NAMESPACE
|
||||
biscuit::
|
||||
)
|
||||
export(PACKAGE biscuit)
|
1401
externals/dynarmic/externals/biscuit/src/assembler.cpp
vendored
1401
externals/dynarmic/externals/biscuit/src/assembler.cpp
vendored
File diff suppressed because it is too large
Load Diff
@ -1,696 +0,0 @@
|
||||
#include <biscuit/assert.hpp>
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
|
||||
#include "assembler_util.hpp"
|
||||
|
||||
// RVC Extension Instructions
|
||||
|
||||
namespace biscuit {
|
||||
namespace {
|
||||
// Emits a compressed branch instruction. These consist of:
|
||||
// funct3 | imm[8|4:3] | rs | imm[7:6|2:1|5] | op
|
||||
void EmitCompressedBranch(CodeBuffer& buffer, uint32_t funct3, int32_t offset, GPR rs, uint32_t op) {
|
||||
BISCUIT_ASSERT(IsValidCBTypeImm(offset));
|
||||
BISCUIT_ASSERT(IsValid3BitCompressedReg(rs));
|
||||
|
||||
const auto transformed_imm = TransformToCBTypeImm(static_cast<uint32_t>(offset));
|
||||
const auto rs_san = CompressedRegTo3BitEncoding(rs);
|
||||
buffer.Emit16(((funct3 & 0b111) << 13) | transformed_imm | (rs_san << 7) | (op & 0b11));
|
||||
}
|
||||
|
||||
// Emits a compressed jump instruction. These consist of:
|
||||
// funct3 | imm | op
|
||||
void EmitCompressedJump(CodeBuffer& buffer, uint32_t funct3, int32_t offset, uint32_t op) {
|
||||
BISCUIT_ASSERT(IsValidCJTypeImm(offset));
|
||||
BISCUIT_ASSERT((offset % 2) == 0);
|
||||
|
||||
buffer.Emit16(TransformToCJTypeImm(static_cast<uint32_t>(offset)) |
|
||||
((funct3 & 0b111) << 13) | (op & 0b11));
|
||||
}
|
||||
|
||||
// Emits a compress immediate instruction. These consist of:
|
||||
// funct3 | imm | rd | imm | op
|
||||
void EmitCompressedImmediate(CodeBuffer& buffer, uint32_t funct3, uint32_t imm, GPR rd, uint32_t op) {
|
||||
BISCUIT_ASSERT(rd != x0);
|
||||
|
||||
const auto new_imm = ((imm & 0b11111) << 2) | ((imm & 0b100000) << 7);
|
||||
buffer.Emit16(((funct3 & 0b111) << 13) | new_imm | (rd.Index() << 7) | (op & 0b11));
|
||||
}
|
||||
|
||||
// Emits a compressed load instruction. These consist of:
|
||||
// funct3 | imm | rs1 | imm | rd | op
|
||||
void EmitCompressedLoad(CodeBuffer& buffer, uint32_t funct3, uint32_t imm, GPR rs,
|
||||
Register rd, uint32_t op) {
|
||||
BISCUIT_ASSERT(IsValid3BitCompressedReg(rs));
|
||||
BISCUIT_ASSERT(IsValid3BitCompressedReg(rd));
|
||||
|
||||
imm &= 0xF8;
|
||||
|
||||
const auto imm_enc = ((imm & 0x38) << 7) | ((imm & 0xC0) >> 1);
|
||||
const auto rd_san = CompressedRegTo3BitEncoding(rd);
|
||||
const auto rs_san = CompressedRegTo3BitEncoding(rs);
|
||||
buffer.Emit16(((funct3 & 0b111) << 13) | imm_enc | (rs_san << 7) | (rd_san << 2) | (op & 0b11));
|
||||
}
|
||||
|
||||
// Emits a compressed register arithmetic instruction. These consist of:
|
||||
// funct6 | rd | funct2 | rs | op
|
||||
void EmitCompressedRegArith(CodeBuffer& buffer, uint32_t funct6, GPR rd, uint32_t funct2,
|
||||
GPR rs, uint32_t op) {
|
||||
BISCUIT_ASSERT(IsValid3BitCompressedReg(rs));
|
||||
BISCUIT_ASSERT(IsValid3BitCompressedReg(rd));
|
||||
|
||||
const auto rd_san = CompressedRegTo3BitEncoding(rd);
|
||||
const auto rs_san = CompressedRegTo3BitEncoding(rs);
|
||||
buffer.Emit16(((funct6 & 0b111111) << 10) | (rd_san << 7) | ((funct2 & 0b11) << 5) |
|
||||
(rs_san << 2) | (op & 0b11));
|
||||
}
|
||||
|
||||
// Emits a compressed store instruction. These consist of:
|
||||
// funct3 | imm | rs1 | imm | rs2 | op
|
||||
void EmitCompressedStore(CodeBuffer& buffer, uint32_t funct3, uint32_t imm, GPR rs1,
|
||||
Register rs2, uint32_t op) {
|
||||
// This has the same format as a compressed load, with rs2 taking the place of rd.
|
||||
// We can reuse the code we've already written to handle this.
|
||||
EmitCompressedLoad(buffer, funct3, imm, rs1, rs2, op);
|
||||
}
|
||||
|
||||
// Emits a compressed wide immediate instruction. These consist of:
|
||||
// funct3 | imm | rd | opcode
|
||||
void EmitCompressedWideImmediate(CodeBuffer& buffer, uint32_t funct3, uint32_t imm,
|
||||
GPR rd, uint32_t op) {
|
||||
BISCUIT_ASSERT(IsValid3BitCompressedReg(rd));
|
||||
|
||||
const auto rd_sanitized = CompressedRegTo3BitEncoding(rd);
|
||||
buffer.Emit16(((funct3 & 0b111) << 13) | ((imm & 0xFF) << 5) |
|
||||
(rd_sanitized << 2) | (op & 0b11));
|
||||
}
|
||||
|
||||
void EmitCLBType(CodeBuffer& buffer, uint32_t funct6, GPR rs, uint32_t uimm, GPR rd,
|
||||
uint32_t op, uint32_t b6) {
|
||||
BISCUIT_ASSERT(IsValid3BitCompressedReg(rs));
|
||||
BISCUIT_ASSERT(IsValid3BitCompressedReg(rd));
|
||||
BISCUIT_ASSERT(uimm <= 3);
|
||||
|
||||
const auto rd_san = CompressedRegTo3BitEncoding(rd);
|
||||
const auto rs_san = CompressedRegTo3BitEncoding(rs);
|
||||
|
||||
buffer.Emit16((funct6 << 10) | (rs_san << 7) | (b6 << 6) | (uimm << 5) | (rd_san << 2) | op);
|
||||
}
|
||||
|
||||
void EmitCLHType(CodeBuffer& buffer, uint32_t funct6, GPR rs, uint32_t uimm, GPR rd,
|
||||
uint32_t op, uint32_t b6) {
|
||||
BISCUIT_ASSERT((uimm % 2) == 0);
|
||||
BISCUIT_ASSERT(uimm <= 2);
|
||||
|
||||
// Only have 1 bit of encoding space for the immediate.
|
||||
const uint32_t uimm_fixed = uimm >> 1;
|
||||
EmitCLBType(buffer, funct6, rs, uimm_fixed, rd, op, b6);
|
||||
}
|
||||
|
||||
// These have the same layout as the equivalent loads, we just essentially alias
|
||||
// the name of those to provide better intent at the call site.
|
||||
void EmitCSBType(CodeBuffer& buffer, uint32_t funct6, GPR rs, uint32_t uimm, GPR rd, uint32_t op) {
|
||||
EmitCLBType(buffer, funct6, rs, uimm, rd, op, 0);
|
||||
}
|
||||
void EmitCSHType(CodeBuffer& buffer, uint32_t funct6, GPR rs, uint32_t uimm, GPR rd, uint32_t op) {
|
||||
EmitCLHType(buffer, funct6, rs, uimm, rd, op, 0);
|
||||
}
|
||||
|
||||
void EmitCUType(CodeBuffer& buffer, uint32_t funct6, GPR rd, uint32_t funct5, uint32_t op) {
|
||||
BISCUIT_ASSERT(IsValid3BitCompressedReg(rd));
|
||||
const auto rd_san = CompressedRegTo3BitEncoding(rd);
|
||||
|
||||
buffer.Emit16((funct6 << 10) | (rd_san << 7) | (funct5 << 2) | op);
|
||||
}
|
||||
|
||||
void EmitCMJTType(CodeBuffer& buffer, uint32_t funct6, uint32_t index, uint32_t op) {
|
||||
buffer.Emit16((funct6 << 10) | (index << 2) | op);
|
||||
}
|
||||
|
||||
void EmitCMMVType(CodeBuffer& buffer, uint32_t funct6, GPR r1s, uint32_t funct2, GPR r2s, uint32_t op) {
|
||||
const auto is_valid_s_register = [](GPR reg) {
|
||||
return reg == s0 || reg == s1 || (reg >= s2 && reg <= s7);
|
||||
};
|
||||
|
||||
BISCUIT_ASSERT(r1s != r2s);
|
||||
BISCUIT_ASSERT(is_valid_s_register(r1s));
|
||||
BISCUIT_ASSERT(is_valid_s_register(r2s));
|
||||
|
||||
const auto r1s_san = r1s.Index() & 0b111;
|
||||
const auto r2s_san = r2s.Index() & 0b111;
|
||||
|
||||
buffer.Emit16((funct6 << 10) | (r1s_san << 7) | (funct2 << 5) | (r2s_san << 2) | op);
|
||||
}
|
||||
|
||||
void EmitCMPPType(CodeBuffer& buffer, uint32_t funct6, uint32_t funct2, PushPopList reglist,
|
||||
int32_t stack_adj, uint32_t op, ArchFeature feature) {
|
||||
BISCUIT_ASSERT(stack_adj % 16 == 0);
|
||||
|
||||
static constexpr std::array stack_adj_bases_rv32{
|
||||
0U, 0U, 0U, 0U, 16U, 16U, 16U, 16U,
|
||||
32U, 32U, 32U, 32U, 48U, 48U, 48U, 64U,
|
||||
};
|
||||
static constexpr std::array stack_adj_bases_rv64{
|
||||
0U, 0U, 0U, 0U, 16U, 16U, 32U, 32U,
|
||||
48U, 48U, 64U, 64U, 80U, 80U, 96U, 112U
|
||||
};
|
||||
|
||||
const auto bitmask = reglist.GetBitmask();
|
||||
const auto stack_adj_base = IsRV64(feature) ? stack_adj_bases_rv64[bitmask]
|
||||
: stack_adj_bases_rv32[bitmask];
|
||||
const auto stack_adj_u = static_cast<uint32_t>(std::abs(stack_adj));
|
||||
const auto spimm = (stack_adj_u - stack_adj_base) / 16U;
|
||||
|
||||
// We can only encode up to three differenct values as the upper spimm bits.
|
||||
// Ensure we catch any cases where we end up going outside of them.
|
||||
BISCUIT_ASSERT(stack_adj_u == stack_adj_base ||
|
||||
stack_adj_u == stack_adj_base + 16 ||
|
||||
stack_adj_u == stack_adj_base + 32 ||
|
||||
stack_adj_u == stack_adj_base + 48);
|
||||
|
||||
buffer.Emit16((funct6 << 10) | (funct2 << 8) | (bitmask << 4) | (spimm << 2) | op);
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
void Assembler::C_ADD(GPR rd, GPR rs) noexcept {
|
||||
BISCUIT_ASSERT(rs != x0);
|
||||
m_buffer.Emit16(0x9002 | (rd.Index() << 7) | (rs.Index() << 2));
|
||||
}
|
||||
|
||||
void Assembler::C_ADDI(GPR rd, int32_t imm) noexcept {
|
||||
BISCUIT_ASSERT(imm != 0);
|
||||
BISCUIT_ASSERT(IsValidSigned6BitImm(imm));
|
||||
EmitCompressedImmediate(m_buffer, 0b000, static_cast<uint32_t>(imm), rd, 0b01);
|
||||
}
|
||||
|
||||
void Assembler::C_ADDIW(GPR rd, int32_t imm) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64OrRV128(m_features));
|
||||
BISCUIT_ASSERT(IsValidSigned6BitImm(imm));
|
||||
EmitCompressedImmediate(m_buffer, 0b001, static_cast<uint32_t>(imm), rd, 0b01);
|
||||
}
|
||||
|
||||
void Assembler::C_ADDI4SPN(GPR rd, uint32_t imm) noexcept {
|
||||
BISCUIT_ASSERT(imm != 0);
|
||||
BISCUIT_ASSERT(imm <= 1020);
|
||||
BISCUIT_ASSERT(imm % 4 == 0);
|
||||
|
||||
// clang-format off
|
||||
const auto new_imm = ((imm & 0x030) << 2) |
|
||||
((imm & 0x3C0) >> 4) |
|
||||
((imm & 0x004) >> 1) |
|
||||
((imm & 0x008) >> 3);
|
||||
// clang-format on
|
||||
|
||||
EmitCompressedWideImmediate(m_buffer, 0b000, new_imm, rd, 0b00);
|
||||
}
|
||||
|
||||
void Assembler::C_ADDW(GPR rd, GPR rs) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64OrRV128(m_features));
|
||||
EmitCompressedRegArith(m_buffer, 0b100111, rd, 0b01, rs, 0b01);
|
||||
}
|
||||
|
||||
void Assembler::C_ADDI16SP(int32_t imm) noexcept {
|
||||
BISCUIT_ASSERT(imm != 0);
|
||||
BISCUIT_ASSERT(imm >= -512 && imm <= 496);
|
||||
BISCUIT_ASSERT(imm % 16 == 0);
|
||||
|
||||
// clang-format off
|
||||
const auto uimm = static_cast<uint32_t>(imm);
|
||||
const auto new_imm = ((uimm & 0x020) >> 3) |
|
||||
((uimm & 0x180) >> 4) |
|
||||
((uimm & 0x040) >> 1) |
|
||||
((uimm & 0x010) << 2) |
|
||||
((uimm & 0x200) << 3);
|
||||
// clang-format on
|
||||
|
||||
m_buffer.Emit16(0x6000U | new_imm | (x2.Index() << 7) | 0b01U);
|
||||
}
|
||||
|
||||
void Assembler::C_AND(GPR rd, GPR rs) noexcept {
|
||||
EmitCompressedRegArith(m_buffer, 0b100011, rd, 0b11, rs, 0b01);
|
||||
}
|
||||
|
||||
void Assembler::C_ANDI(GPR rd, uint32_t imm) noexcept {
|
||||
BISCUIT_ASSERT(IsValid3BitCompressedReg(rd));
|
||||
|
||||
constexpr auto base = 0x8801U;
|
||||
const auto shift_enc = ((imm & 0b11111) << 2) | ((imm & 0b100000) << 7);
|
||||
const auto reg = CompressedRegTo3BitEncoding(rd);
|
||||
|
||||
m_buffer.Emit16(base | shift_enc | (reg << 7));
|
||||
}
|
||||
|
||||
void Assembler::C_BEQZ(GPR rs, int32_t offset) noexcept {
|
||||
EmitCompressedBranch(m_buffer, 0b110, offset, rs, 0b01);
|
||||
}
|
||||
|
||||
void Assembler::C_BEQZ(GPR rs, Label* label) noexcept {
|
||||
const auto address = LinkAndGetOffset(label);
|
||||
C_BEQZ(rs, static_cast<int32_t>(address));
|
||||
}
|
||||
|
||||
void Assembler::C_BNEZ(GPR rs, int32_t offset) noexcept {
|
||||
EmitCompressedBranch(m_buffer, 0b111, offset, rs, 0b01);
|
||||
}
|
||||
|
||||
void Assembler::C_BNEZ(GPR rs, Label* label) noexcept {
|
||||
const auto address = LinkAndGetOffset(label);
|
||||
C_BNEZ(rs, static_cast<int32_t>(address));
|
||||
}
|
||||
|
||||
void Assembler::C_EBREAK() noexcept {
|
||||
m_buffer.Emit16(0x9002);
|
||||
}
|
||||
|
||||
void Assembler::C_FLD(FPR rd, uint32_t imm, GPR rs) noexcept {
|
||||
BISCUIT_ASSERT(IsRV32OrRV64(m_features));
|
||||
BISCUIT_ASSERT(imm <= 248);
|
||||
BISCUIT_ASSERT(imm % 8 == 0);
|
||||
|
||||
EmitCompressedLoad(m_buffer, 0b001, imm, rs, rd, 0b00);
|
||||
}
|
||||
|
||||
void Assembler::C_FLDSP(FPR rd, uint32_t imm) noexcept {
|
||||
BISCUIT_ASSERT(IsRV32OrRV64(m_features));
|
||||
BISCUIT_ASSERT(imm <= 504);
|
||||
BISCUIT_ASSERT(imm % 8 == 0);
|
||||
|
||||
// clang-format off
|
||||
const auto new_imm = ((imm & 0x018) << 2) |
|
||||
((imm & 0x1C0) >> 4) |
|
||||
((imm & 0x020) << 7);
|
||||
// clang-format on
|
||||
|
||||
m_buffer.Emit16(0x2002U | (rd.Index() << 7) | new_imm);
|
||||
}
|
||||
|
||||
void Assembler::C_FLW(FPR rd, uint32_t imm, GPR rs) noexcept {
|
||||
BISCUIT_ASSERT(IsRV32(m_features));
|
||||
BISCUIT_ASSERT(imm <= 124);
|
||||
BISCUIT_ASSERT(imm % 4 == 0);
|
||||
|
||||
imm &= 0x7C;
|
||||
const auto new_imm = ((imm & 0b0100) << 5) | (imm & 0x78);
|
||||
EmitCompressedLoad(m_buffer, 0b011, new_imm, rs, rd, 0b00);
|
||||
}
|
||||
|
||||
void Assembler::C_FLWSP(FPR rd, uint32_t imm) noexcept {
|
||||
BISCUIT_ASSERT(IsRV32(m_features));
|
||||
BISCUIT_ASSERT(imm <= 252);
|
||||
BISCUIT_ASSERT(imm % 4 == 0);
|
||||
|
||||
// clang-format off
|
||||
const auto new_imm = ((imm & 0x020) << 7) |
|
||||
((imm & 0x0C0) >> 4) |
|
||||
((imm & 0x01C) << 2);
|
||||
// clang-format on
|
||||
|
||||
m_buffer.Emit16(0x6002U | (rd.Index() << 7) | new_imm);
|
||||
}
|
||||
|
||||
void Assembler::C_FSD(FPR rs2, uint32_t imm, GPR rs1) noexcept {
|
||||
BISCUIT_ASSERT(IsRV32OrRV64(m_features));
|
||||
BISCUIT_ASSERT(imm <= 248);
|
||||
BISCUIT_ASSERT(imm % 8 == 0);
|
||||
|
||||
EmitCompressedStore(m_buffer, 0b101, imm, rs1, rs2, 0b00);
|
||||
}
|
||||
|
||||
void Assembler::C_FSDSP(FPR rs, uint32_t imm) noexcept {
|
||||
BISCUIT_ASSERT(IsRV32OrRV64(m_features));
|
||||
BISCUIT_ASSERT(imm <= 504);
|
||||
BISCUIT_ASSERT(imm % 8 == 0);
|
||||
|
||||
// clang-format off
|
||||
const auto new_imm = ((imm & 0x038) << 7) |
|
||||
((imm & 0x1C0) << 1);
|
||||
// clang-format on
|
||||
|
||||
m_buffer.Emit16(0xA002U | (rs.Index() << 2) | new_imm);
|
||||
}
|
||||
|
||||
void Assembler::C_J(Label* label) noexcept {
|
||||
const auto address = LinkAndGetOffset(label);
|
||||
C_J(static_cast<int32_t>(address));
|
||||
}
|
||||
|
||||
void Assembler::C_J(int32_t offset) noexcept {
|
||||
EmitCompressedJump(m_buffer, 0b101, offset, 0b01);
|
||||
}
|
||||
|
||||
void Assembler::C_JAL(Label* label) noexcept {
|
||||
const auto address = LinkAndGetOffset(label);
|
||||
C_JAL(static_cast<int32_t>(address));
|
||||
}
|
||||
|
||||
void Assembler::C_JAL(int32_t offset) noexcept {
|
||||
BISCUIT_ASSERT(IsRV32(m_features));
|
||||
EmitCompressedJump(m_buffer, 0b001, offset, 0b01);
|
||||
}
|
||||
|
||||
void Assembler::C_FSW(FPR rs2, uint32_t imm, GPR rs1) noexcept {
|
||||
BISCUIT_ASSERT(IsRV32(m_features));
|
||||
BISCUIT_ASSERT(imm <= 124);
|
||||
BISCUIT_ASSERT(imm % 4 == 0);
|
||||
|
||||
imm &= 0x7C;
|
||||
const auto new_imm = ((imm & 0b0100) << 5) | (imm & 0x78);
|
||||
EmitCompressedStore(m_buffer, 0b111, new_imm, rs1, rs2, 0b00);
|
||||
}
|
||||
|
||||
void Assembler::C_FSWSP(FPR rs, uint32_t imm) noexcept {
|
||||
BISCUIT_ASSERT(IsRV32(m_features));
|
||||
BISCUIT_ASSERT(imm <= 252);
|
||||
BISCUIT_ASSERT(imm % 4 == 0);
|
||||
|
||||
// clang-format off
|
||||
const auto new_imm = ((imm & 0x0C0) << 1) |
|
||||
((imm & 0x03C) << 7);
|
||||
// clang-format on
|
||||
|
||||
m_buffer.Emit16(0xE002U | (rs.Index() << 2) | new_imm);
|
||||
}
|
||||
|
||||
void Assembler::C_JALR(GPR rs) noexcept {
|
||||
BISCUIT_ASSERT(rs != x0);
|
||||
m_buffer.Emit16(0x9002 | (rs.Index() << 7));
|
||||
}
|
||||
|
||||
void Assembler::C_JR(GPR rs) noexcept {
|
||||
BISCUIT_ASSERT(rs != x0);
|
||||
m_buffer.Emit16(0x8002 | (rs.Index() << 7));
|
||||
}
|
||||
|
||||
void Assembler::C_LD(GPR rd, uint32_t imm, GPR rs) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64OrRV128(m_features));
|
||||
BISCUIT_ASSERT(imm <= 248);
|
||||
BISCUIT_ASSERT(imm % 8 == 0);
|
||||
|
||||
EmitCompressedLoad(m_buffer, 0b011, imm, rs, rd, 0b00);
|
||||
}
|
||||
|
||||
void Assembler::C_LDSP(GPR rd, uint32_t imm) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64OrRV128(m_features));
|
||||
BISCUIT_ASSERT(rd != x0);
|
||||
BISCUIT_ASSERT(imm <= 504);
|
||||
BISCUIT_ASSERT(imm % 8 == 0);
|
||||
|
||||
// clang-format off
|
||||
const auto new_imm = ((imm & 0x018) << 2) |
|
||||
((imm & 0x1C0) >> 4) |
|
||||
((imm & 0x020) << 7);
|
||||
// clang-format on
|
||||
|
||||
m_buffer.Emit16(0x6002U | (rd.Index() << 7) | new_imm);
|
||||
}
|
||||
|
||||
void Assembler::C_LI(GPR rd, int32_t imm) noexcept {
|
||||
BISCUIT_ASSERT(IsValidSigned6BitImm(imm));
|
||||
EmitCompressedImmediate(m_buffer, 0b010, static_cast<uint32_t>(imm), rd, 0b01);
|
||||
}
|
||||
|
||||
void Assembler::C_LQ(GPR rd, uint32_t imm, GPR rs) noexcept {
|
||||
BISCUIT_ASSERT(IsRV128(m_features));
|
||||
BISCUIT_ASSERT(imm <= 496);
|
||||
BISCUIT_ASSERT(imm % 16 == 0);
|
||||
|
||||
imm &= 0x1F0;
|
||||
const auto new_imm = ((imm & 0x100) >> 5) | (imm & 0xF0);
|
||||
EmitCompressedLoad(m_buffer, 0b001, new_imm, rs, rd, 0b00);
|
||||
}
|
||||
|
||||
void Assembler::C_LQSP(GPR rd, uint32_t imm) noexcept {
|
||||
BISCUIT_ASSERT(IsRV128(m_features));
|
||||
BISCUIT_ASSERT(rd != x0);
|
||||
BISCUIT_ASSERT(imm <= 1008);
|
||||
BISCUIT_ASSERT(imm % 16 == 0);
|
||||
|
||||
// clang-format off
|
||||
const auto new_imm = ((imm & 0x020) << 7) |
|
||||
((imm & 0x010) << 2) |
|
||||
((imm & 0x3C0) >> 4);
|
||||
// clang-format on
|
||||
|
||||
m_buffer.Emit16(0x2002U | (rd.Index() << 7) | new_imm);
|
||||
}
|
||||
|
||||
void Assembler::C_LUI(GPR rd, uint32_t imm) noexcept {
|
||||
BISCUIT_ASSERT(imm != 0);
|
||||
BISCUIT_ASSERT(rd != x0 && rd != x2);
|
||||
|
||||
const auto new_imm = (imm & 0x3F000) >> 12;
|
||||
EmitCompressedImmediate(m_buffer, 0b011, new_imm, rd, 0b01);
|
||||
}
|
||||
|
||||
void Assembler::C_LW(GPR rd, uint32_t imm, GPR rs) noexcept {
|
||||
BISCUIT_ASSERT(imm <= 124);
|
||||
BISCUIT_ASSERT(imm % 4 == 0);
|
||||
|
||||
imm &= 0x7C;
|
||||
const auto new_imm = ((imm & 0b0100) << 5) | (imm & 0x78);
|
||||
EmitCompressedLoad(m_buffer, 0b010, new_imm, rs, rd, 0b00);
|
||||
}
|
||||
|
||||
void Assembler::C_LWSP(GPR rd, uint32_t imm) noexcept {
|
||||
BISCUIT_ASSERT(rd != x0);
|
||||
BISCUIT_ASSERT(imm <= 252);
|
||||
BISCUIT_ASSERT(imm % 4 == 0);
|
||||
|
||||
// clang-format off
|
||||
const auto new_imm = ((imm & 0x020) << 7) |
|
||||
((imm & 0x0C0) >> 4) |
|
||||
((imm & 0x01C) << 2);
|
||||
// clang-format on
|
||||
|
||||
m_buffer.Emit16(0x4002U | (rd.Index() << 7) | new_imm);
|
||||
}
|
||||
|
||||
void Assembler::C_MV(GPR rd, GPR rs) noexcept {
|
||||
BISCUIT_ASSERT(rd != x0);
|
||||
BISCUIT_ASSERT(rs != x0);
|
||||
m_buffer.Emit16(0x8002 | (rd.Index() << 7) | (rs.Index() << 2));
|
||||
}
|
||||
|
||||
void Assembler::C_NOP() noexcept {
|
||||
m_buffer.Emit16(1);
|
||||
}
|
||||
|
||||
void Assembler::C_OR(GPR rd, GPR rs) noexcept {
|
||||
EmitCompressedRegArith(m_buffer, 0b100011, rd, 0b10, rs, 0b01);
|
||||
}
|
||||
|
||||
void Assembler::C_SD(GPR rs2, uint32_t imm, GPR rs1) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64OrRV128(m_features));
|
||||
BISCUIT_ASSERT(imm <= 248);
|
||||
BISCUIT_ASSERT(imm % 8 == 0);
|
||||
|
||||
EmitCompressedLoad(m_buffer, 0b111, imm, rs1, rs2, 0b00);
|
||||
}
|
||||
|
||||
void Assembler::C_SDSP(GPR rs, uint32_t imm) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64OrRV128(m_features));
|
||||
BISCUIT_ASSERT(imm <= 504);
|
||||
BISCUIT_ASSERT(imm % 8 == 0);
|
||||
|
||||
// clang-format off
|
||||
const auto new_imm = ((imm & 0x038) << 7) |
|
||||
((imm & 0x1C0) << 1);
|
||||
// clang-format on
|
||||
|
||||
m_buffer.Emit16(0xE002U | (rs.Index() << 2) | new_imm);
|
||||
}
|
||||
|
||||
void Assembler::C_SLLI(GPR rd, uint32_t shift) noexcept {
|
||||
BISCUIT_ASSERT(rd != x0);
|
||||
BISCUIT_ASSERT(IsValidCompressedShiftAmount(shift));
|
||||
|
||||
// RV128C encodes a 64-bit shift with an encoding of 0.
|
||||
if (shift == 64) {
|
||||
BISCUIT_ASSERT(IsRV128(m_features));
|
||||
shift = 0;
|
||||
}
|
||||
|
||||
const auto shift_enc = ((shift & 0b11111) << 2) | ((shift & 0b100000) << 7);
|
||||
m_buffer.Emit16(0x0002U | shift_enc | (rd.Index() << 7));
|
||||
}
|
||||
|
||||
void Assembler::C_SQ(GPR rs2, uint32_t imm, GPR rs1) noexcept {
|
||||
BISCUIT_ASSERT(IsRV128(m_features));
|
||||
BISCUIT_ASSERT(imm <= 496);
|
||||
BISCUIT_ASSERT(imm % 16 == 0);
|
||||
|
||||
imm &= 0x1F0;
|
||||
const auto new_imm = ((imm & 0x100) >> 5) | (imm & 0xF0);
|
||||
EmitCompressedStore(m_buffer, 0b101, new_imm, rs1, rs2, 0b00);
|
||||
}
|
||||
|
||||
void Assembler::C_SQSP(GPR rs, uint32_t imm) noexcept {
|
||||
BISCUIT_ASSERT(IsRV128(m_features));
|
||||
BISCUIT_ASSERT(imm <= 1008);
|
||||
BISCUIT_ASSERT(imm % 16 == 0);
|
||||
|
||||
// clang-format off
|
||||
const auto new_imm = ((imm & 0x3C0) << 1) |
|
||||
((imm & 0x030) << 7);
|
||||
// clang-format on
|
||||
|
||||
m_buffer.Emit16(0xA002U | (rs.Index() << 2) | new_imm);
|
||||
}
|
||||
|
||||
void Assembler::C_SRAI(GPR rd, uint32_t shift) noexcept {
|
||||
BISCUIT_ASSERT(IsValid3BitCompressedReg(rd));
|
||||
BISCUIT_ASSERT(IsValidCompressedShiftAmount(shift));
|
||||
|
||||
// RV128C encodes a 64-bit shift with an encoding of 0.
|
||||
if (shift == 64) {
|
||||
BISCUIT_ASSERT(IsRV128(m_features));
|
||||
shift = 0;
|
||||
}
|
||||
|
||||
constexpr auto base = 0x8401U;
|
||||
const auto shift_enc = ((shift & 0b11111) << 2) | ((shift & 0b100000) << 7);
|
||||
const auto reg = CompressedRegTo3BitEncoding(rd);
|
||||
|
||||
m_buffer.Emit16(base | shift_enc | (reg << 7));
|
||||
}
|
||||
|
||||
void Assembler::C_SRLI(GPR rd, uint32_t shift) noexcept {
|
||||
BISCUIT_ASSERT(IsValid3BitCompressedReg(rd));
|
||||
BISCUIT_ASSERT(IsValidCompressedShiftAmount(shift));
|
||||
|
||||
// RV128C encodes a 64-bit shift with an encoding of 0.
|
||||
if (shift == 64) {
|
||||
BISCUIT_ASSERT(IsRV128(m_features));
|
||||
shift = 0;
|
||||
}
|
||||
|
||||
constexpr auto base = 0x8001U;
|
||||
const auto shift_enc = ((shift & 0b11111) << 2) | ((shift & 0b100000) << 7);
|
||||
const auto reg = CompressedRegTo3BitEncoding(rd);
|
||||
|
||||
m_buffer.Emit16(base | shift_enc | (reg << 7));
|
||||
}
|
||||
|
||||
void Assembler::C_SUB(GPR rd, GPR rs) noexcept {
|
||||
EmitCompressedRegArith(m_buffer, 0b100011, rd, 0b00, rs, 0b01);
|
||||
}
|
||||
|
||||
void Assembler::C_SUBW(GPR rd, GPR rs) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64OrRV128(m_features));
|
||||
EmitCompressedRegArith(m_buffer, 0b100111, rd, 0b00, rs, 0b01);
|
||||
}
|
||||
|
||||
void Assembler::C_SW(GPR rs2, uint32_t imm, GPR rs1) noexcept {
|
||||
BISCUIT_ASSERT(imm <= 124);
|
||||
BISCUIT_ASSERT(imm % 4 == 0);
|
||||
|
||||
imm &= 0x7C;
|
||||
const auto new_imm = ((imm & 0b0100) << 5) | (imm & 0x78);
|
||||
EmitCompressedStore(m_buffer, 0b110, new_imm, rs1, rs2, 0b00);
|
||||
}
|
||||
|
||||
void Assembler::C_SWSP(GPR rs, uint32_t imm) noexcept {
|
||||
BISCUIT_ASSERT(imm <= 252);
|
||||
BISCUIT_ASSERT(imm % 4 == 0);
|
||||
|
||||
// clang-format off
|
||||
const auto new_imm = ((imm & 0x0C0) << 1) |
|
||||
((imm & 0x03C) << 7);
|
||||
// clang-format on
|
||||
|
||||
m_buffer.Emit16(0xC002U | (rs.Index() << 2) | new_imm);
|
||||
}
|
||||
|
||||
void Assembler::C_UNDEF() noexcept {
|
||||
m_buffer.Emit16(0);
|
||||
}
|
||||
|
||||
void Assembler::C_XOR(GPR rd, GPR rs) noexcept {
|
||||
EmitCompressedRegArith(m_buffer, 0b100011, rd, 0b01, rs, 0b01);
|
||||
}
|
||||
|
||||
// Zc Extension Instructions
|
||||
|
||||
void Assembler::C_LBU(GPR rd, uint32_t uimm, GPR rs) noexcept {
|
||||
// C.LBU swaps the ordering of the immediate.
|
||||
const auto uimm_fixed = ((uimm & 0b01) << 1) | ((uimm & 0b10) >> 1);
|
||||
|
||||
EmitCLBType(m_buffer, 0b100000, rs, uimm_fixed, rd, 0b00, 0);
|
||||
}
|
||||
void Assembler::C_LH(GPR rd, uint32_t uimm, GPR rs) noexcept {
|
||||
EmitCLHType(m_buffer, 0b100001, rs, uimm, rd, 0b00, 1);
|
||||
}
|
||||
void Assembler::C_LHU(GPR rd, uint32_t uimm, GPR rs) noexcept {
|
||||
EmitCLHType(m_buffer, 0b100001, rs, uimm, rd, 0b00, 0);
|
||||
}
|
||||
void Assembler::C_SB(GPR rs2, uint32_t uimm, GPR rs1) noexcept {
|
||||
// C.SB swaps the ordering of the immediate.
|
||||
const auto uimm_fixed = ((uimm & 0b01) << 1) | ((uimm & 0b10) >> 1);
|
||||
|
||||
EmitCSBType(m_buffer, 0b100010, rs1, uimm_fixed, rs2, 0b00);
|
||||
}
|
||||
void Assembler::C_SH(GPR rs2, uint32_t uimm, GPR rs1) noexcept {
|
||||
EmitCSHType(m_buffer, 0b100011, rs1, uimm, rs2, 0b00);
|
||||
}
|
||||
|
||||
void Assembler::C_SEXT_B(GPR rd) noexcept {
|
||||
EmitCUType(m_buffer, 0b100111, rd, 0b11001, 0b01);
|
||||
}
|
||||
void Assembler::C_SEXT_H(GPR rd) noexcept {
|
||||
EmitCUType(m_buffer, 0b100111, rd, 0b11011, 0b01);
|
||||
}
|
||||
void Assembler::C_ZEXT_B(GPR rd) noexcept {
|
||||
EmitCUType(m_buffer, 0b100111, rd, 0b11000, 0b01);
|
||||
}
|
||||
void Assembler::C_ZEXT_H(GPR rd) noexcept {
|
||||
EmitCUType(m_buffer, 0b100111, rd, 0b11010, 0b01);
|
||||
}
|
||||
void Assembler::C_ZEXT_W(GPR rd) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
EmitCUType(m_buffer, 0b100111, rd, 0b11100, 0b01);
|
||||
}
|
||||
|
||||
void Assembler::C_MUL(GPR rsd, GPR rs2) noexcept {
|
||||
EmitCompressedRegArith(m_buffer, 0b100111, rsd, 0b10, rs2, 0b01);
|
||||
}
|
||||
void Assembler::C_NOT(GPR rd) noexcept {
|
||||
EmitCUType(m_buffer, 0b100111, rd, 0b11101, 0b01);
|
||||
}
|
||||
|
||||
void Assembler::CM_JALT(uint32_t index) noexcept {
|
||||
BISCUIT_ASSERT(index >= 32 && index <= 255);
|
||||
EmitCMJTType(m_buffer, 0b101000, index, 0b10);
|
||||
}
|
||||
void Assembler::CM_JT(uint32_t index) noexcept {
|
||||
BISCUIT_ASSERT(index <= 31);
|
||||
EmitCMJTType(m_buffer, 0b101000, index, 0b10);
|
||||
}
|
||||
|
||||
void Assembler::CM_MVA01S(GPR r1s, GPR r2s) noexcept {
|
||||
EmitCMMVType(m_buffer, 0b101011, r1s, 0b11, r2s, 0b10);
|
||||
}
|
||||
void Assembler::CM_MVSA01(GPR r1s, GPR r2s) noexcept {
|
||||
EmitCMMVType(m_buffer, 0b101011, r1s, 0b01, r2s, 0b10);
|
||||
}
|
||||
|
||||
void Assembler::CM_POP(PushPopList reg_list, int32_t stack_adj) noexcept {
|
||||
BISCUIT_ASSERT(stack_adj > 0);
|
||||
EmitCMPPType(m_buffer, 0b101110, 0b10, reg_list, stack_adj, 0b10, m_features);
|
||||
}
|
||||
void Assembler::CM_POPRET(PushPopList reg_list, int32_t stack_adj) noexcept {
|
||||
BISCUIT_ASSERT(stack_adj > 0);
|
||||
EmitCMPPType(m_buffer, 0b101111, 0b10, reg_list, stack_adj, 0b10, m_features);
|
||||
}
|
||||
void Assembler::CM_POPRETZ(PushPopList reg_list, int32_t stack_adj) noexcept {
|
||||
BISCUIT_ASSERT(stack_adj > 0);
|
||||
EmitCMPPType(m_buffer, 0b101111, 0b00, reg_list, stack_adj, 0b10, m_features);
|
||||
}
|
||||
void Assembler::CM_PUSH(PushPopList reg_list, int32_t stack_adj) noexcept {
|
||||
BISCUIT_ASSERT(stack_adj < 0);
|
||||
EmitCMPPType(m_buffer, 0b101110, 0b00, reg_list, stack_adj, 0b10, m_features);
|
||||
}
|
||||
|
||||
} // namespace biscuit
|
@ -1,172 +0,0 @@
|
||||
#include <biscuit/assert.hpp>
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include "assembler_util.hpp"
|
||||
|
||||
namespace biscuit {
|
||||
namespace {
|
||||
void EmitAES32Instruction(CodeBuffer& buffer, uint32_t op, GPR rd, GPR rs1, GPR rs2, uint32_t bs) noexcept {
|
||||
BISCUIT_ASSERT(bs <= 0b11);
|
||||
buffer.Emit32(op | (bs << 30) | (rs2.Index() << 20) |
|
||||
(rs1.Index() << 15) | (rd.Index() << 7));
|
||||
}
|
||||
|
||||
void EmitSM4Instruction(CodeBuffer& buffer, uint32_t op, GPR rd, GPR rs1, GPR rs2, uint32_t bs) noexcept {
|
||||
// Same behavior, function exists for a better contextual name.
|
||||
EmitAES32Instruction(buffer, op, rd, rs1, rs2, bs);
|
||||
}
|
||||
|
||||
void EmitAES64Instruction(CodeBuffer& buffer, uint32_t op, GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||
buffer.Emit32(op | (rs2.Index() << 20) | (rs1.Index() << 15) | (rd.Index() << 7));
|
||||
}
|
||||
|
||||
void EmitSHAInstruction(CodeBuffer& buffer, uint32_t op, GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||
// Same behavior, function exists for a better contextual name.
|
||||
EmitAES64Instruction(buffer, op, rd, rs1, rs2);
|
||||
}
|
||||
|
||||
void EmitSM3Instruction(CodeBuffer& buffer, uint32_t op, GPR rd, GPR rs) noexcept {
|
||||
// Same behavior, function exists for a better contextual name.
|
||||
EmitAES64Instruction(buffer, op, rd, rs, x0);
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
void Assembler::AES32DSI(GPR rd, GPR rs1, GPR rs2, uint32_t bs) noexcept {
|
||||
BISCUIT_ASSERT(IsRV32(m_features));
|
||||
EmitAES32Instruction(m_buffer, 0x2A000033, rd, rs1, rs2, bs);
|
||||
}
|
||||
|
||||
void Assembler::AES32DSMI(GPR rd, GPR rs1, GPR rs2, uint32_t bs) noexcept {
|
||||
BISCUIT_ASSERT(IsRV32(m_features));
|
||||
EmitAES32Instruction(m_buffer, 0x2E000033, rd, rs1, rs2, bs);
|
||||
}
|
||||
|
||||
void Assembler::AES32ESI(GPR rd, GPR rs1, GPR rs2, uint32_t bs) noexcept {
|
||||
BISCUIT_ASSERT(IsRV32(m_features));
|
||||
EmitAES32Instruction(m_buffer, 0x22000033, rd, rs1, rs2, bs);
|
||||
}
|
||||
|
||||
void Assembler::AES32ESMI(GPR rd, GPR rs1, GPR rs2, uint32_t bs) noexcept {
|
||||
BISCUIT_ASSERT(IsRV32(m_features));
|
||||
EmitAES32Instruction(m_buffer, 0x26000033, rd, rs1, rs2, bs);
|
||||
}
|
||||
|
||||
void Assembler::AES64DS(GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
EmitAES64Instruction(m_buffer, 0x3A000033, rd, rs1, rs2);
|
||||
}
|
||||
|
||||
void Assembler::AES64DSM(GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
EmitAES64Instruction(m_buffer, 0x3E000033, rd, rs1, rs2);
|
||||
}
|
||||
|
||||
void Assembler::AES64ES(GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
EmitAES64Instruction(m_buffer, 0x32000033, rd, rs1, rs2);
|
||||
}
|
||||
|
||||
void Assembler::AES64ESM(GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
EmitAES64Instruction(m_buffer, 0x36000033, rd, rs1, rs2);
|
||||
}
|
||||
|
||||
void Assembler::AES64IM(GPR rd, GPR rs) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
EmitAES64Instruction(m_buffer, 0x30001013, rd, rs, x0);
|
||||
}
|
||||
|
||||
void Assembler::AES64KS1I(GPR rd, GPR rs, uint32_t rnum) noexcept {
|
||||
// RVK spec states that rnums 0xB to 0xF are reserved.
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
BISCUIT_ASSERT(rnum <= 0xA);
|
||||
EmitAES64Instruction(m_buffer, 0x31001013, rd, rs, GPR{rnum});
|
||||
}
|
||||
|
||||
void Assembler::AES64KS2(GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
EmitAES64Instruction(m_buffer, 0x7E000033, rd, rs1, rs2);
|
||||
}
|
||||
|
||||
void Assembler::SHA256SIG0(GPR rd, GPR rs) noexcept {
|
||||
EmitSHAInstruction(m_buffer, 0x10201013, rd, rs, x0);
|
||||
}
|
||||
|
||||
void Assembler::SHA256SIG1(GPR rd, GPR rs) noexcept {
|
||||
EmitSHAInstruction(m_buffer, 0x10301013, rd, rs, x0);
|
||||
}
|
||||
|
||||
void Assembler::SHA256SUM0(GPR rd, GPR rs) noexcept {
|
||||
EmitSHAInstruction(m_buffer, 0x10001013, rd, rs, x0);
|
||||
}
|
||||
|
||||
void Assembler::SHA256SUM1(GPR rd, GPR rs) noexcept {
|
||||
EmitSHAInstruction(m_buffer, 0x10101013, rd, rs, x0);
|
||||
}
|
||||
|
||||
void Assembler::SHA512SIG0(GPR rd, GPR rs) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
EmitSHAInstruction(m_buffer, 0x10601013, rd, rs, x0);
|
||||
}
|
||||
|
||||
void Assembler::SHA512SIG0H(GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||
BISCUIT_ASSERT(IsRV32(m_features));
|
||||
EmitSHAInstruction(m_buffer, 0x5C000033, rd, rs1, rs2);
|
||||
}
|
||||
|
||||
void Assembler::SHA512SIG0L(GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||
BISCUIT_ASSERT(IsRV32(m_features));
|
||||
EmitSHAInstruction(m_buffer, 0x54000033, rd, rs1, rs2);
|
||||
}
|
||||
|
||||
void Assembler::SHA512SIG1(GPR rd, GPR rs) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
EmitSHAInstruction(m_buffer, 0x10701013, rd, rs, x0);
|
||||
}
|
||||
|
||||
void Assembler::SHA512SIG1H(GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||
BISCUIT_ASSERT(IsRV32(m_features));
|
||||
EmitSHAInstruction(m_buffer, 0x5E000033, rd, rs1, rs2);
|
||||
}
|
||||
|
||||
void Assembler::SHA512SIG1L(GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||
BISCUIT_ASSERT(IsRV32(m_features));
|
||||
EmitSHAInstruction(m_buffer, 0x56000033, rd, rs1, rs2);
|
||||
}
|
||||
|
||||
void Assembler::SHA512SUM0(GPR rd, GPR rs) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
EmitSHAInstruction(m_buffer, 0x10401013, rd, rs, x0);
|
||||
}
|
||||
|
||||
void Assembler::SHA512SUM0R(GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||
BISCUIT_ASSERT(IsRV32(m_features));
|
||||
EmitSHAInstruction(m_buffer, 0x50000033, rd, rs1, rs2);
|
||||
}
|
||||
|
||||
void Assembler::SHA512SUM1(GPR rd, GPR rs) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
EmitSHAInstruction(m_buffer, 0x10501013, rd, rs, x0);
|
||||
}
|
||||
|
||||
void Assembler::SHA512SUM1R(GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||
BISCUIT_ASSERT(IsRV32(m_features));
|
||||
EmitSHAInstruction(m_buffer, 0x52000033, rd, rs1, rs2);
|
||||
}
|
||||
|
||||
void Assembler::SM3P0(GPR rd, GPR rs) noexcept {
|
||||
EmitSM3Instruction(m_buffer, 0x10801013, rd, rs);
|
||||
}
|
||||
|
||||
void Assembler::SM3P1(GPR rd, GPR rs) noexcept {
|
||||
EmitSM3Instruction(m_buffer, 0x10901013, rd, rs);
|
||||
}
|
||||
|
||||
void Assembler::SM4ED(GPR rd, GPR rs1, GPR rs2, uint32_t bs) noexcept {
|
||||
EmitSM4Instruction(m_buffer, 0x30000033, rd, rs1, rs2, bs);
|
||||
}
|
||||
|
||||
void Assembler::SM4KS(GPR rd, GPR rs1, GPR rs2, uint32_t bs) noexcept {
|
||||
EmitSM4Instruction(m_buffer, 0x34000033, rd, rs1, rs2, bs);
|
||||
}
|
||||
} // namespace biscuit
|
@ -1,648 +0,0 @@
|
||||
#include <biscuit/assert.hpp>
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
|
||||
#include "assembler_util.hpp"
|
||||
|
||||
// Various floating-point-based extension instructions.
|
||||
|
||||
namespace biscuit {
|
||||
|
||||
// RV32F Extension Instructions
|
||||
|
||||
void Assembler::FADD_S(FPR rd, FPR rs1, FPR rs2, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0000000, rs2, rs1, rmode, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCLASS_S(GPR rd, FPR rs1) noexcept {
|
||||
EmitRType(m_buffer, 0b1110000, f0, rs1, 0b001, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_S_W(FPR rd, GPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b1101000, f0, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_S_WU(FPR rd, GPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b1101000, f1, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_W_S(GPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b1100000, f0, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_WU_S(GPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b1100000, f1, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FDIV_S(FPR rd, FPR rs1, FPR rs2, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0001100, rs2, rs1, rmode, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FEQ_S(GPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b1010000, rs2, rs1, 0b010, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FLE_S(GPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b1010000, rs2, rs1, 0b000, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FLT_S(GPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b1010000, rs2, rs1, 0b001, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FLW(FPR rd, int32_t offset, GPR rs) noexcept {
|
||||
BISCUIT_ASSERT(IsValidSigned12BitImm(offset));
|
||||
EmitIType(m_buffer, static_cast<uint32_t>(offset), rs, 0b010, rd, 0b0000111);
|
||||
}
|
||||
void Assembler::FMADD_S(FPR rd, FPR rs1, FPR rs2, FPR rs3, RMode rmode) noexcept {
|
||||
EmitR4Type(m_buffer, rs3, 0b00, rs2, rs1, rmode, rd, 0b1000011);
|
||||
}
|
||||
void Assembler::FMAX_S(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010100, rs2, rs1, 0b001, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMIN_S(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010100, rs2, rs1, 0b000, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMSUB_S(FPR rd, FPR rs1, FPR rs2, FPR rs3, RMode rmode) noexcept {
|
||||
EmitR4Type(m_buffer, rs3, 0b00, rs2, rs1, rmode, rd, 0b1000111);
|
||||
}
|
||||
void Assembler::FMUL_S(FPR rd, FPR rs1, FPR rs2, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0001000, rs2, rs1, rmode, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMV_W_X(FPR rd, GPR rs1) noexcept {
|
||||
EmitRType(m_buffer, 0b1111000, f0, rs1, 0b000, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMV_X_W(GPR rd, FPR rs1) noexcept {
|
||||
EmitRType(m_buffer, 0b1110000, f0, rs1, 0b000, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FNMADD_S(FPR rd, FPR rs1, FPR rs2, FPR rs3, RMode rmode) noexcept {
|
||||
EmitR4Type(m_buffer, rs3, 0b00, rs2, rs1, rmode, rd, 0b1001111);
|
||||
}
|
||||
void Assembler::FNMSUB_S(FPR rd, FPR rs1, FPR rs2, FPR rs3, RMode rmode) noexcept {
|
||||
EmitR4Type(m_buffer, rs3, 0b00, rs2, rs1, rmode, rd, 0b1001011);
|
||||
}
|
||||
void Assembler::FSGNJ_S(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010000, rs2, rs1, 0b000, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FSGNJN_S(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010000, rs2, rs1, 0b001, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FSGNJX_S(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010000, rs2, rs1, 0b010, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FSQRT_S(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0101100, f0, rs1, rmode, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FSUB_S(FPR rd, FPR rs1, FPR rs2, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0000100, rs2, rs1, rmode, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FSW(FPR rs2, int32_t offset, GPR rs1) noexcept {
|
||||
BISCUIT_ASSERT(IsValidSigned12BitImm(offset));
|
||||
EmitSType(m_buffer, static_cast<uint32_t>(offset), rs2, rs1, 0b010, 0b0100111);
|
||||
}
|
||||
|
||||
void Assembler::FABS_S(FPR rd, FPR rs) noexcept {
|
||||
FSGNJX_S(rd, rs, rs);
|
||||
}
|
||||
void Assembler::FMV_S(FPR rd, FPR rs) noexcept {
|
||||
FSGNJ_S(rd, rs, rs);
|
||||
}
|
||||
void Assembler::FNEG_S(FPR rd, FPR rs) noexcept {
|
||||
FSGNJN_S(rd, rs, rs);
|
||||
}
|
||||
|
||||
// RV64F Extension Instructions
|
||||
|
||||
void Assembler::FCVT_L_S(GPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
EmitRType(m_buffer, 0b1100000, f2, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_LU_S(GPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
EmitRType(m_buffer, 0b1100000, f3, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_S_L(FPR rd, GPR rs1, RMode rmode) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
EmitRType(m_buffer, 0b1101000, f2, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_S_LU(FPR rd, GPR rs1, RMode rmode) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
EmitRType(m_buffer, 0b1101000, f3, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
|
||||
// RV32D Extension Instructions
|
||||
|
||||
void Assembler::FADD_D(FPR rd, FPR rs1, FPR rs2, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0000001, rs2, rs1, rmode, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCLASS_D(GPR rd, FPR rs1) noexcept {
|
||||
EmitRType(m_buffer, 0b1110001, f0, rs1, 0b001, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_D_W(FPR rd, GPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b1101001, f0, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_D_WU(FPR rd, GPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b1101001, f1, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_W_D(GPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b1100001, f0, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_WU_D(GPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b1100001, f1, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_D_S(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0100001, f0, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_S_D(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0100000, f1, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FDIV_D(FPR rd, FPR rs1, FPR rs2, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0001101, rs2, rs1, rmode, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FEQ_D(GPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b1010001, rs2, rs1, 0b010, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FLE_D(GPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b1010001, rs2, rs1, 0b000, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FLT_D(GPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b1010001, rs2, rs1, 0b001, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FLD(FPR rd, int32_t offset, GPR rs) noexcept {
|
||||
BISCUIT_ASSERT(IsValidSigned12BitImm(offset));
|
||||
EmitIType(m_buffer, static_cast<uint32_t>(offset), rs, 0b011, rd, 0b0000111);
|
||||
}
|
||||
void Assembler::FMADD_D(FPR rd, FPR rs1, FPR rs2, FPR rs3, RMode rmode) noexcept {
|
||||
EmitR4Type(m_buffer, rs3, 0b01, rs2, rs1, rmode, rd, 0b1000011);
|
||||
}
|
||||
void Assembler::FMAX_D(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010101, rs2, rs1, 0b001, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMIN_D(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010101, rs2, rs1, 0b000, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMSUB_D(FPR rd, FPR rs1, FPR rs2, FPR rs3, RMode rmode) noexcept {
|
||||
EmitR4Type(m_buffer, rs3, 0b01, rs2, rs1, rmode, rd, 0b1000111);
|
||||
}
|
||||
void Assembler::FMUL_D(FPR rd, FPR rs1, FPR rs2, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0001001, rs2, rs1, rmode, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FNMADD_D(FPR rd, FPR rs1, FPR rs2, FPR rs3, RMode rmode) noexcept {
|
||||
EmitR4Type(m_buffer, rs3, 0b01, rs2, rs1, rmode, rd, 0b1001111);
|
||||
}
|
||||
void Assembler::FNMSUB_D(FPR rd, FPR rs1, FPR rs2, FPR rs3, RMode rmode) noexcept {
|
||||
EmitR4Type(m_buffer, rs3, 0b01, rs2, rs1, rmode, rd, 0b1001011);
|
||||
}
|
||||
void Assembler::FSGNJ_D(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010001, rs2, rs1, 0b000, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FSGNJN_D(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010001, rs2, rs1, 0b001, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FSGNJX_D(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010001, rs2, rs1, 0b010, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FSQRT_D(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0101101, f0, rs1, rmode, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FSUB_D(FPR rd, FPR rs1, FPR rs2, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0000101, rs2, rs1, rmode, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FSD(FPR rs2, int32_t offset, GPR rs1) noexcept {
|
||||
BISCUIT_ASSERT(IsValidSigned12BitImm(offset));
|
||||
EmitSType(m_buffer, static_cast<uint32_t>(offset), rs2, rs1, 0b011, 0b0100111);
|
||||
}
|
||||
|
||||
void Assembler::FABS_D(FPR rd, FPR rs) noexcept {
|
||||
FSGNJX_D(rd, rs, rs);
|
||||
}
|
||||
void Assembler::FMV_D(FPR rd, FPR rs) noexcept {
|
||||
FSGNJ_D(rd, rs, rs);
|
||||
}
|
||||
void Assembler::FNEG_D(FPR rd, FPR rs) noexcept {
|
||||
FSGNJN_D(rd, rs, rs);
|
||||
}
|
||||
|
||||
// RV64D Extension Instructions
|
||||
|
||||
void Assembler::FCVT_L_D(GPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
EmitRType(m_buffer, 0b1100001, f2, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_LU_D(GPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
EmitRType(m_buffer, 0b1100001, f3, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_D_L(FPR rd, GPR rs1, RMode rmode) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
EmitRType(m_buffer, 0b1101001, f2, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_D_LU(FPR rd, GPR rs1, RMode rmode) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
EmitRType(m_buffer, 0b1101001, f3, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMV_D_X(FPR rd, GPR rs1) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64OrRV128(m_features));
|
||||
EmitRType(m_buffer, 0b1111001, f0, rs1, 0b000, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMV_X_D(GPR rd, FPR rs1) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64OrRV128(m_features));
|
||||
EmitRType(m_buffer, 0b1110001, f0, rs1, 0b000, rd, 0b1010011);
|
||||
}
|
||||
|
||||
// RV32Q Extension Instructions
|
||||
|
||||
void Assembler::FADD_Q(FPR rd, FPR rs1, FPR rs2, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0000011, rs2, rs1, rmode, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCLASS_Q(GPR rd, FPR rs1) noexcept {
|
||||
EmitRType(m_buffer, 0b1110011, f0, rs1, 0b001, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_Q_W(FPR rd, GPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b1101011, f0, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_Q_WU(FPR rd, GPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b1101011, f1, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_W_Q(GPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b1100011, f0, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_WU_Q(GPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b1100011, f1, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_Q_D(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0100011, f1, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_D_Q(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0100001, f3, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_Q_S(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0100011, f0, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_S_Q(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0100000, f3, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FDIV_Q(FPR rd, FPR rs1, FPR rs2, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0001111, rs2, rs1, rmode, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FEQ_Q(GPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b1010011, rs2, rs1, 0b010, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FLE_Q(GPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b1010011, rs2, rs1, 0b000, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FLT_Q(GPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b1010011, rs2, rs1, 0b001, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FLQ(FPR rd, int32_t offset, GPR rs) noexcept {
|
||||
BISCUIT_ASSERT(IsValidSigned12BitImm(offset));
|
||||
EmitIType(m_buffer, static_cast<uint32_t>(offset), rs, 0b100, rd, 0b0000111);
|
||||
}
|
||||
void Assembler::FMADD_Q(FPR rd, FPR rs1, FPR rs2, FPR rs3, RMode rmode) noexcept {
|
||||
EmitR4Type(m_buffer, rs3, 0b11, rs2, rs1, rmode, rd, 0b1000011);
|
||||
}
|
||||
void Assembler::FMAX_Q(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010111, rs2, rs1, 0b001, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMIN_Q(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010111, rs2, rs1, 0b000, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMSUB_Q(FPR rd, FPR rs1, FPR rs2, FPR rs3, RMode rmode) noexcept {
|
||||
EmitR4Type(m_buffer, rs3, 0b11, rs2, rs1, rmode, rd, 0b1000111);
|
||||
}
|
||||
void Assembler::FMUL_Q(FPR rd, FPR rs1, FPR rs2, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0001011, rs2, rs1, rmode, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FNMADD_Q(FPR rd, FPR rs1, FPR rs2, FPR rs3, RMode rmode) noexcept {
|
||||
EmitR4Type(m_buffer, rs3, 0b11, rs2, rs1, rmode, rd, 0b1001111);
|
||||
}
|
||||
void Assembler::FNMSUB_Q(FPR rd, FPR rs1, FPR rs2, FPR rs3, RMode rmode) noexcept {
|
||||
EmitR4Type(m_buffer, rs3, 0b11, rs2, rs1, rmode, rd, 0b1001011);
|
||||
}
|
||||
void Assembler::FSGNJ_Q(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010011, rs2, rs1, 0b000, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FSGNJN_Q(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010011, rs2, rs1, 0b001, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FSGNJX_Q(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010011, rs2, rs1, 0b010, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FSQRT_Q(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0101111, f0, rs1, rmode, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FSUB_Q(FPR rd, FPR rs1, FPR rs2, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0000111, rs2, rs1, rmode, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FSQ(FPR rs2, int32_t offset, GPR rs1) noexcept {
|
||||
BISCUIT_ASSERT(IsValidSigned12BitImm(offset));
|
||||
EmitSType(m_buffer, static_cast<uint32_t>(offset), rs2, rs1, 0b100, 0b0100111);
|
||||
}
|
||||
|
||||
void Assembler::FABS_Q(FPR rd, FPR rs) noexcept {
|
||||
FSGNJX_Q(rd, rs, rs);
|
||||
}
|
||||
void Assembler::FMV_Q(FPR rd, FPR rs) noexcept {
|
||||
FSGNJ_Q(rd, rs, rs);
|
||||
}
|
||||
void Assembler::FNEG_Q(FPR rd, FPR rs) noexcept {
|
||||
FSGNJN_Q(rd, rs, rs);
|
||||
}
|
||||
|
||||
// RV64Q Extension Instructions
|
||||
|
||||
void Assembler::FCVT_L_Q(GPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
EmitRType(m_buffer, 0b1100011, f2, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_LU_Q(GPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
EmitRType(m_buffer, 0b1100011, f3, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_Q_L(FPR rd, GPR rs1, RMode rmode) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
EmitRType(m_buffer, 0b1101011, f2, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_Q_LU(FPR rd, GPR rs1, RMode rmode) noexcept {
|
||||
BISCUIT_ASSERT(IsRV64(m_features));
|
||||
EmitRType(m_buffer, 0b1101011, f3, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
|
||||
// RV32Zfh Extension Instructions
|
||||
|
||||
void Assembler::FADD_H(FPR rd, FPR rs1, FPR rs2, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0000010, rs2, rs1, rmode, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCLASS_H(GPR rd, FPR rs1) noexcept {
|
||||
EmitRType(m_buffer, 0b1110010, f0, rs1, 0b001, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_D_H(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0100001, f2, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_H_D(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0100010, f1, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_H_Q(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0100010, f3, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_H_S(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0100010, f0, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_H_W(FPR rd, GPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b1101010, f0, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_H_WU(FPR rd, GPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b1101010, f1, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_Q_H(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0100011, f2, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_S_H(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0100000, f2, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_W_H(GPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b1100010, f0, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_WU_H(GPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b1100010, f1, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FDIV_H(FPR rd, FPR rs1, FPR rs2, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0001110, rs2, rs1, rmode, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FEQ_H(GPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b1010010, rs2, rs1, 0b010, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FLE_H(GPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b1010010, rs2, rs1, 0b000, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FLH(FPR rd, int32_t offset, GPR rs) noexcept {
|
||||
BISCUIT_ASSERT(IsValidSigned12BitImm(offset));
|
||||
EmitIType(m_buffer, static_cast<uint32_t>(offset), rs, 0b001, rd, 0b0000111);
|
||||
}
|
||||
void Assembler::FLT_H(GPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b1010010, rs2, rs1, 0b001, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMADD_H(FPR rd, FPR rs1, FPR rs2, FPR rs3, RMode rmode) noexcept {
|
||||
EmitR4Type(m_buffer, rs3, 0b10, rs2, rs1, rmode, rd, 0b1000011);
|
||||
}
|
||||
void Assembler::FMAX_H(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010110, rs2, rs1, 0b001, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMIN_H(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010110, rs2, rs1, 0b000, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMSUB_H(FPR rd, FPR rs1, FPR rs2, FPR rs3, RMode rmode) noexcept {
|
||||
EmitR4Type(m_buffer, rs3, 0b10, rs2, rs1, rmode, rd, 0b1000111);
|
||||
}
|
||||
void Assembler::FMUL_H(FPR rd, FPR rs1, FPR rs2, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0001010, rs2, rs1, rmode, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMV_H_X(FPR rd, GPR rs1) noexcept {
|
||||
EmitRType(m_buffer, 0b1111010, f0, rs1, 0b000, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMV_X_H(GPR rd, FPR rs1) noexcept {
|
||||
EmitRType(m_buffer, 0b1110010, f0, rs1, 0b000, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FNMADD_H(FPR rd, FPR rs1, FPR rs2, FPR rs3, RMode rmode) noexcept {
|
||||
EmitR4Type(m_buffer, rs3, 0b10, rs2, rs1, rmode, rd, 0b1001111);
|
||||
}
|
||||
void Assembler::FNMSUB_H(FPR rd, FPR rs1, FPR rs2, FPR rs3, RMode rmode) noexcept {
|
||||
EmitR4Type(m_buffer, rs3, 0b10, rs2, rs1, rmode, rd, 0b1001011);
|
||||
}
|
||||
void Assembler::FSGNJ_H(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010010, rs2, rs1, 0b000, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FSGNJN_H(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010010, rs2, rs1, 0b001, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FSGNJX_H(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010010, rs2, rs1, 0b010, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FSH(FPR rs2, int32_t offset, GPR rs1) noexcept {
|
||||
BISCUIT_ASSERT(IsValidSigned12BitImm(offset));
|
||||
EmitSType(m_buffer, static_cast<uint32_t>(offset), rs2, rs1, 0b001, 0b0100111);
|
||||
}
|
||||
void Assembler::FSQRT_H(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0101110, f0, rs1, rmode, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FSUB_H(FPR rd, FPR rs1, FPR rs2, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0000110, rs2, rs1, rmode, rd, 0b1010011);
|
||||
}
|
||||
|
||||
// RV64Zfh Extension Instructions
|
||||
|
||||
void Assembler::FCVT_L_H(GPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b1100010, f2, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_LU_H(GPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b1100010, f3, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_H_L(FPR rd, GPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b1101010, f2, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FCVT_H_LU(FPR rd, GPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b1101010, f3, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
|
||||
// Zfa Extension Instructions
|
||||
|
||||
static void FLIImpl(CodeBuffer& buffer, uint32_t funct7, FPR rd, double value) noexcept {
|
||||
static constexpr std::array fli_table{
|
||||
0xBFF0000000000000ULL, // -1.0
|
||||
0x0010000000000000ULL, // Minimum positive normal
|
||||
0x3EF0000000000000ULL, // 1.0 * 2^-16
|
||||
0x3F00000000000000ULL, // 1.0 * 2^-15
|
||||
0x3F70000000000000ULL, // 1.0 * 2^-8
|
||||
0x3F80000000000000ULL, // 1.0 * 2^-7
|
||||
0x3FB0000000000000ULL, // 1.0 * 2^-4
|
||||
0x3FC0000000000000ULL, // 1.0 * 2^-3
|
||||
0x3FD0000000000000ULL, // 0.25
|
||||
0x3FD4000000000000ULL, // 0.3125
|
||||
0x3FD8000000000000ULL, // 0.375
|
||||
0x3FDC000000000000ULL, // 0.4375
|
||||
0x3FE0000000000000ULL, // 0.5
|
||||
0x3FE4000000000000ULL, // 0.625
|
||||
0x3FE8000000000000ULL, // 0.75
|
||||
0x3FEC000000000000ULL, // 0.875
|
||||
0x3FF0000000000000ULL, // 1.0
|
||||
0x3FF4000000000000ULL, // 1.25
|
||||
0x3FF8000000000000ULL, // 1.5
|
||||
0x3FFC000000000000ULL, // 1.75
|
||||
0x4000000000000000ULL, // 2.0
|
||||
0x4004000000000000ULL, // 2.5
|
||||
0x4008000000000000ULL, // 3
|
||||
0x4010000000000000ULL, // 4
|
||||
0x4020000000000000ULL, // 8
|
||||
0x4030000000000000ULL, // 16
|
||||
0x4060000000000000ULL, // 2^7
|
||||
0x4070000000000000ULL, // 2^8
|
||||
0x40E0000000000000ULL, // 2^15
|
||||
0x40F0000000000000ULL, // 2^16
|
||||
0x7FF0000000000000ULL, // +inf
|
||||
0x7FF8000000000000ULL, // Canonical NaN
|
||||
};
|
||||
|
||||
uint64_t ivalue{};
|
||||
std::memcpy(&ivalue, &value, sizeof(uint64_t));
|
||||
|
||||
const auto iter = std::find_if(fli_table.cbegin(), fli_table.cend(), [ivalue](uint64_t entry) {
|
||||
return entry == ivalue;
|
||||
});
|
||||
BISCUIT_ASSERT(iter != fli_table.cend());
|
||||
|
||||
const auto index = static_cast<uint32_t>(std::distance(fli_table.cbegin(), iter));
|
||||
EmitRType(buffer, funct7, f1, GPR{index}, 0b000, rd, 0b1010011);
|
||||
}
|
||||
|
||||
void Assembler::FLI_D(FPR rd, double value) noexcept {
|
||||
FLIImpl(m_buffer, 0b1111001, rd, value);
|
||||
}
|
||||
void Assembler::FLI_H(FPR rd, double value) noexcept {
|
||||
FLIImpl(m_buffer, 0b1111010, rd, value);
|
||||
}
|
||||
void Assembler::FLI_S(FPR rd, double value) noexcept {
|
||||
FLIImpl(m_buffer, 0b1111000, rd, value);
|
||||
}
|
||||
|
||||
void Assembler::FMINM_D(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010101, rs2, rs1, 0b010, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMINM_H(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010110, rs2, rs1, 0b010, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMINM_Q(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010111, rs2, rs1, 0b010, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMINM_S(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010100, rs2, rs1, 0b010, rd, 0b1010011);
|
||||
}
|
||||
|
||||
void Assembler::FMAXM_D(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010101, rs2, rs1, 0b011, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMAXM_H(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010110, rs2, rs1, 0b011, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMAXM_Q(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010111, rs2, rs1, 0b011, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMAXM_S(FPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b0010100, rs2, rs1, 0b011, rd, 0b1010011);
|
||||
}
|
||||
|
||||
void Assembler::FROUND_D(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0100001, f4, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FROUND_H(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0100010, f4, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FROUND_Q(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0100011, f4, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FROUND_S(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0100000, f4, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
|
||||
void Assembler::FROUNDNX_D(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0100001, f5, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FROUNDNX_H(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0100010, f5, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FROUNDNX_Q(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0100011, f5, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FROUNDNX_S(FPR rd, FPR rs1, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0100000, f5, rs1, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
|
||||
void Assembler::FCVTMOD_W_D(GPR rd, FPR rs1) noexcept {
|
||||
EmitRType(m_buffer, 0b1100001, f8, rs1, static_cast<uint32_t>(RMode::RTZ), rd, 0b1010011);
|
||||
}
|
||||
|
||||
void Assembler::FMVH_X_D(GPR rd, FPR rs1) noexcept {
|
||||
EmitRType(m_buffer, 0b1110001, f1, rs1, 0b000, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMVH_X_Q(GPR rd, FPR rs1) noexcept {
|
||||
EmitRType(m_buffer, 0b1110011, f1, rs1, 0b000, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMVP_D_X(FPR rd, GPR rs1, GPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b1011001, rs2, rs1, 0b000, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FMVP_Q_X(FPR rd, GPR rs1, GPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b1011011, rs2, rs1, 0b000, rd, 0b1010011);
|
||||
}
|
||||
|
||||
void Assembler::FLEQ_D(GPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b1010001, rs2, rs1, 0b100, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FLTQ_D(GPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b1010001, rs2, rs1, 0b101, rd, 0b1010011);
|
||||
}
|
||||
|
||||
void Assembler::FLEQ_H(GPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b1010010, rs2, rs1, 0b100, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FLTQ_H(GPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b1010010, rs2, rs1, 0b101, rd, 0b1010011);
|
||||
}
|
||||
|
||||
void Assembler::FLEQ_Q(GPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b1010011, rs2, rs1, 0b100, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FLTQ_Q(GPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b1010011, rs2, rs1, 0b101, rd, 0b1010011);
|
||||
}
|
||||
|
||||
void Assembler::FLEQ_S(GPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b1010000, rs2, rs1, 0b100, rd, 0b1010011);
|
||||
}
|
||||
void Assembler::FLTQ_S(GPR rd, FPR rs1, FPR rs2) noexcept {
|
||||
EmitRType(m_buffer, 0b1010000, rs2, rs1, 0b101, rd, 0b1010011);
|
||||
}
|
||||
|
||||
// Zfbfmin, Zvfbfmin, Zvfbfwma Extension Instructions
|
||||
|
||||
void Assembler::FCVT_BF16_S(FPR rd, FPR rs, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0100010, f8, rs, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
|
||||
void Assembler::FCVT_S_BF16(FPR rd, FPR rs, RMode rmode) noexcept {
|
||||
EmitRType(m_buffer, 0b0100000, f6, rs, static_cast<uint32_t>(rmode), rd, 0b1010011);
|
||||
}
|
||||
|
||||
} // namespace biscuit
|
@ -1,224 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <biscuit/assert.hpp>
|
||||
#include <biscuit/code_buffer.hpp>
|
||||
#include <biscuit/registers.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
// Generic internal utility header for various helper functions related
|
||||
// to encoding instructions.
|
||||
|
||||
namespace biscuit {
|
||||
// Determines if a value lies within the range of a 6-bit immediate.
|
||||
[[nodiscard]] constexpr bool IsValidSigned6BitImm(ptrdiff_t value) {
|
||||
return value >= -32 && value <= 31;
|
||||
}
|
||||
|
||||
// S-type and I-type immediates are 12 bits in size
|
||||
[[nodiscard]] constexpr bool IsValidSigned12BitImm(ptrdiff_t value) {
|
||||
return value >= -2048 && value <= 2047;
|
||||
}
|
||||
|
||||
// B-type immediates only provide -4KiB to +4KiB range branches.
|
||||
[[nodiscard]] constexpr bool IsValidBTypeImm(ptrdiff_t value) {
|
||||
return value >= -4096 && value <= 4095;
|
||||
}
|
||||
|
||||
// J-type immediates only provide -1MiB to +1MiB range branches.
|
||||
[[nodiscard]] constexpr bool IsValidJTypeImm(ptrdiff_t value) {
|
||||
return value >= -0x80000 && value <= 0x7FFFF;
|
||||
}
|
||||
|
||||
// CB-type immediates only provide -256B to +256B range branches.
|
||||
[[nodiscard]] constexpr bool IsValidCBTypeImm(ptrdiff_t value) {
|
||||
return value >= -256 && value <= 255;
|
||||
}
|
||||
|
||||
// CJ-type immediates only provide -2KiB to +2KiB range branches.
|
||||
[[nodiscard]] constexpr bool IsValidCJTypeImm(ptrdiff_t value) {
|
||||
return IsValidSigned12BitImm(value);
|
||||
}
|
||||
|
||||
// Determines whether or not the register fits in 3-bit compressed encoding.
|
||||
[[nodiscard]] constexpr bool IsValid3BitCompressedReg(Register reg) {
|
||||
const auto index = reg.Index();
|
||||
return index >= 8 && index <= 15;
|
||||
}
|
||||
|
||||
// Determines whether or not the given shift amount is valid for a compressed shift instruction
|
||||
[[nodiscard]] constexpr bool IsValidCompressedShiftAmount(uint32_t shift) {
|
||||
return shift > 0 && shift <= 64;
|
||||
}
|
||||
|
||||
// Turns a compressed register into its encoding.
|
||||
[[nodiscard]] constexpr uint32_t CompressedRegTo3BitEncoding(Register reg) {
|
||||
return reg.Index() - 8;
|
||||
}
|
||||
|
||||
// Transforms a regular value into an immediate encoded in a B-type instruction.
|
||||
[[nodiscard]] constexpr uint32_t TransformToBTypeImm(uint32_t imm) {
|
||||
// clang-format off
|
||||
return ((imm & 0x07E0) << 20) |
|
||||
((imm & 0x1000) << 19) |
|
||||
((imm & 0x001E) << 7) |
|
||||
((imm & 0x0800) >> 4);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
// Transforms a regular value into an immediate encoded in a J-type instruction.
|
||||
[[nodiscard]] constexpr uint32_t TransformToJTypeImm(uint32_t imm) {
|
||||
// clang-format off
|
||||
return ((imm & 0x0FF000) >> 0) |
|
||||
((imm & 0x000800) << 9) |
|
||||
((imm & 0x0007FE) << 20) |
|
||||
((imm & 0x100000) << 11);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
// Transforms a regular value into an immediate encoded in a CB-type instruction.
|
||||
[[nodiscard]] constexpr uint32_t TransformToCBTypeImm(uint32_t imm) {
|
||||
// clang-format off
|
||||
return ((imm & 0x0C0) >> 1) |
|
||||
((imm & 0x006) << 2) |
|
||||
((imm & 0x020) >> 3) |
|
||||
((imm & 0x018) << 7) |
|
||||
((imm & 0x100) << 4);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
// Transforms a regular value into an immediate encoded in a CJ-type instruction.
|
||||
[[nodiscard]] constexpr uint32_t TransformToCJTypeImm(uint32_t imm) {
|
||||
// clang-format off
|
||||
return ((imm & 0x800) << 1) |
|
||||
((imm & 0x010) << 7) |
|
||||
((imm & 0x300) << 1) |
|
||||
((imm & 0x400) >> 2) |
|
||||
((imm & 0x040) << 1) |
|
||||
((imm & 0x080) >> 1) |
|
||||
((imm & 0x00E) << 4) |
|
||||
((imm & 0x020) >> 3);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
// Emits a B type RISC-V instruction. These consist of:
|
||||
// imm[12|10:5] | rs2 | rs1 | funct3 | imm[4:1] | imm[11] | opcode
|
||||
inline void EmitBType(CodeBuffer& buffer, uint32_t imm, GPR rs2, GPR rs1,
|
||||
uint32_t funct3, uint32_t opcode) {
|
||||
imm &= 0x1FFE;
|
||||
|
||||
buffer.Emit32(TransformToBTypeImm(imm) | (rs2.Index() << 20) | (rs1.Index() << 15) |
|
||||
((funct3 & 0b111) << 12) | (opcode & 0x7F));
|
||||
}
|
||||
|
||||
// Emits a I type RISC-V instruction. These consist of:
|
||||
// imm[11:0] | rs1 | funct3 | rd | opcode
|
||||
inline void EmitIType(CodeBuffer& buffer, uint32_t imm, Register rs1, uint32_t funct3,
|
||||
Register rd, uint32_t opcode) {
|
||||
imm &= 0xFFF;
|
||||
|
||||
buffer.Emit32((imm << 20) | (rs1.Index() << 15) | ((funct3 & 0b111) << 12) |
|
||||
(rd.Index() << 7) | (opcode & 0x7F));
|
||||
}
|
||||
|
||||
// Emits a J type RISC-V instruction. These consist of:
|
||||
// imm[20|10:1|11|19:12] | rd | opcode
|
||||
inline void EmitJType(CodeBuffer& buffer, uint32_t imm, GPR rd, uint32_t opcode) {
|
||||
imm &= 0x1FFFFE;
|
||||
|
||||
buffer.Emit32(TransformToJTypeImm(imm) | rd.Index() << 7 | (opcode & 0x7F));
|
||||
}
|
||||
|
||||
// Emits a R type RISC instruction. These consist of:
|
||||
// funct7 | rs2 | rs1 | funct3 | rd | opcode
|
||||
inline void EmitRType(CodeBuffer& buffer, uint32_t funct7, Register rs2, Register rs1,
|
||||
uint32_t funct3, Register rd, uint32_t opcode) {
|
||||
// clang-format off
|
||||
const auto value = ((funct7 & 0xFF) << 25) |
|
||||
(rs2.Index() << 20) |
|
||||
(rs1.Index() << 15) |
|
||||
((funct3 & 0b111) << 12) |
|
||||
(rd.Index() << 7) |
|
||||
(opcode & 0x7F);
|
||||
// clang-format off
|
||||
|
||||
buffer.Emit32(value);
|
||||
}
|
||||
|
||||
// Emits a R type RISC instruction. These consist of:
|
||||
// funct7 | rs2 | rs1 | funct3 | rd | opcode
|
||||
inline void EmitRType(CodeBuffer& buffer, uint32_t funct7, FPR rs2, FPR rs1, RMode funct3,
|
||||
FPR rd, uint32_t opcode) {
|
||||
EmitRType(buffer, funct7, rs2, rs1, static_cast<uint32_t>(funct3), rd, opcode);
|
||||
}
|
||||
|
||||
// Emits a R4 type RISC instruction. These consist of:
|
||||
// rs3 | funct2 | rs2 | rs1 | funct3 | rd | opcode
|
||||
inline void EmitR4Type(CodeBuffer& buffer, FPR rs3, uint32_t funct2, FPR rs2, FPR rs1,
|
||||
RMode funct3, FPR rd, uint32_t opcode) {
|
||||
const auto reg_bits = (rs3.Index() << 27) | (rs2.Index() << 20) | (rs1.Index() << 15) | (rd.Index() << 7);
|
||||
const auto funct_bits = ((funct2 & 0b11) << 25) | (static_cast<uint32_t>(funct3) << 12);
|
||||
buffer.Emit32(reg_bits | funct_bits | (opcode & 0x7F));
|
||||
}
|
||||
|
||||
// Emits a S type RISC-V instruction. These consist of:
|
||||
// imm[11:5] | rs2 | rs1 | funct3 | imm[4:0] | opcode
|
||||
inline void EmitSType(CodeBuffer& buffer, uint32_t imm, Register rs2, GPR rs1,
|
||||
uint32_t funct3, uint32_t opcode) {
|
||||
imm &= 0xFFF;
|
||||
|
||||
// clang-format off
|
||||
const auto new_imm = ((imm & 0x01F) << 7) |
|
||||
((imm & 0xFE0) << 20);
|
||||
// clang-format on
|
||||
|
||||
buffer.Emit32(new_imm | (rs2.Index() << 20) | (rs1.Index() << 15) |
|
||||
((funct3 & 0b111) << 12) | (opcode & 0x7F));
|
||||
}
|
||||
|
||||
// Emits a U type RISC-V instruction. These consist of:
|
||||
// imm[31:12] | rd | opcode
|
||||
inline void EmitUType(CodeBuffer& buffer, uint32_t imm, GPR rd, uint32_t opcode) {
|
||||
buffer.Emit32((imm & 0x000FFFFF) << 12 | rd.Index() << 7 | (opcode & 0x7F));
|
||||
}
|
||||
|
||||
// Emits an atomic instruction.
|
||||
inline void EmitAtomic(CodeBuffer& buffer, uint32_t funct5, Ordering ordering, GPR rs2, GPR rs1,
|
||||
uint32_t funct3, GPR rd, uint32_t opcode) noexcept {
|
||||
const auto funct7 = (funct5 << 2) | static_cast<uint32_t>(ordering);
|
||||
EmitRType(buffer, funct7, rs2, rs1, funct3, rd, opcode);
|
||||
}
|
||||
|
||||
// Emits a fence instruction
|
||||
inline void EmitFENCE(CodeBuffer& buffer, uint32_t fm, FenceOrder pred, FenceOrder succ,
|
||||
GPR rs, uint32_t funct3, GPR rd, uint32_t opcode) noexcept {
|
||||
// clang-format off
|
||||
buffer.Emit32(((fm & 0b1111) << 28) |
|
||||
(static_cast<uint32_t>(pred) << 24) |
|
||||
(static_cast<uint32_t>(succ) << 20) |
|
||||
(rs.Index() << 15) |
|
||||
((funct3 & 0b111) << 12) |
|
||||
(rd.Index() << 7) |
|
||||
(opcode & 0x7F));
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
// Internal helpers for siloing away particular comparisons for behavior.
|
||||
constexpr bool IsRV32(ArchFeature feature) {
|
||||
return feature == ArchFeature::RV32;
|
||||
}
|
||||
constexpr bool IsRV64(ArchFeature feature) {
|
||||
return feature == ArchFeature::RV64;
|
||||
}
|
||||
constexpr bool IsRV128(ArchFeature feature) {
|
||||
return feature == ArchFeature::RV128;
|
||||
}
|
||||
constexpr bool IsRV32OrRV64(ArchFeature feature) {
|
||||
return IsRV32(feature) || IsRV64(feature);
|
||||
}
|
||||
constexpr bool IsRV64OrRV128(ArchFeature feature) {
|
||||
return IsRV64(feature) || IsRV128(feature);
|
||||
}
|
||||
|
||||
} // namespace biscuit
|
File diff suppressed because it is too large
Load Diff
@ -1,111 +0,0 @@
|
||||
#include <biscuit/assert.hpp>
|
||||
#include <biscuit/code_buffer.hpp>
|
||||
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
|
||||
#ifdef BISCUIT_CODE_BUFFER_MMAP
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
namespace biscuit {
|
||||
|
||||
CodeBuffer::CodeBuffer(size_t capacity)
|
||||
: m_capacity{capacity}, m_is_managed{true} {
|
||||
if (capacity == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef BISCUIT_CODE_BUFFER_MMAP
|
||||
m_buffer = static_cast<uint8_t*>(mmap(nullptr, capacity,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0));
|
||||
BISCUIT_ASSERT(m_buffer != nullptr);
|
||||
#else
|
||||
m_buffer = new uint8_t[capacity]();
|
||||
#endif
|
||||
|
||||
m_cursor = m_buffer;
|
||||
}
|
||||
|
||||
CodeBuffer::CodeBuffer(uint8_t* buffer, size_t capacity)
|
||||
: m_buffer{buffer}, m_cursor{buffer}, m_capacity{capacity} {
|
||||
BISCUIT_ASSERT(buffer != nullptr);
|
||||
}
|
||||
|
||||
CodeBuffer::CodeBuffer(CodeBuffer&& other) noexcept
|
||||
: m_buffer{std::exchange(other.m_buffer, nullptr)}
|
||||
, m_cursor{std::exchange(other.m_cursor, nullptr)}
|
||||
, m_capacity{std::exchange(other.m_capacity, size_t{0})}
|
||||
, m_is_managed{std::exchange(other.m_is_managed, false)} {}
|
||||
|
||||
CodeBuffer& CodeBuffer::operator=(CodeBuffer&& other) noexcept {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::swap(m_buffer, other.m_buffer);
|
||||
std::swap(m_cursor, other.m_cursor);
|
||||
std::swap(m_capacity, other.m_capacity);
|
||||
std::swap(m_is_managed, other.m_is_managed);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CodeBuffer::~CodeBuffer() noexcept {
|
||||
if (!m_is_managed) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef BISCUIT_CODE_BUFFER_MMAP
|
||||
munmap(m_buffer, m_capacity);
|
||||
#else
|
||||
delete[] m_buffer;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CodeBuffer::Grow(size_t new_capacity) {
|
||||
BISCUIT_ASSERT(IsManaged());
|
||||
|
||||
// No-op, just return.
|
||||
if (new_capacity <= m_capacity) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto cursor_offset = GetCursorOffset();
|
||||
|
||||
#ifdef BISCUIT_CODE_BUFFER_MMAP
|
||||
auto* new_buffer = static_cast<uint8_t*>(mremap(m_buffer, m_capacity, new_capacity, MREMAP_MAYMOVE));
|
||||
BISCUIT_ASSERT(new_buffer != nullptr);
|
||||
#else
|
||||
auto* new_buffer = new uint8_t[new_capacity]();
|
||||
std::memcpy(new_buffer, m_buffer, m_capacity);
|
||||
delete[] m_buffer;
|
||||
#endif
|
||||
|
||||
m_buffer = new_buffer;
|
||||
m_capacity = new_capacity;
|
||||
m_cursor = m_buffer + cursor_offset;
|
||||
}
|
||||
|
||||
void CodeBuffer::SetExecutable() {
|
||||
#ifdef BISCUIT_CODE_BUFFER_MMAP
|
||||
const auto result = mprotect(m_buffer, m_capacity, PROT_READ | PROT_EXEC);
|
||||
BISCUIT_ASSERT(result == 0);
|
||||
#else
|
||||
// Unimplemented/Unnecessary for new
|
||||
BISCUIT_ASSERT(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CodeBuffer::SetWritable() {
|
||||
#ifdef BISCUIT_CODE_BUFFER_MMAP
|
||||
const auto result = mprotect(m_buffer, m_capacity, PROT_READ | PROT_WRITE);
|
||||
BISCUIT_ASSERT(result == 0);
|
||||
#else
|
||||
// Unimplemented/Unnecessary for new
|
||||
BISCUIT_ASSERT(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace biscuit
|
@ -1,39 +0,0 @@
|
||||
// Copyright (c), 2022, KNS Group LLC (YADRO)
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://opensource.org/licenses/MIT.
|
||||
|
||||
#include <biscuit/cpuinfo.hpp>
|
||||
|
||||
namespace biscuit {
|
||||
|
||||
bool CPUInfo::Has(RISCVExtension extension) const {
|
||||
#if defined(__linux__) && defined(__riscv)
|
||||
const static uint64_t features = getauxval(AT_HWCAP) & (
|
||||
COMPAT_HWCAP_ISA_I |
|
||||
COMPAT_HWCAP_ISA_M |
|
||||
COMPAT_HWCAP_ISA_A |
|
||||
COMPAT_HWCAP_ISA_F |
|
||||
COMPAT_HWCAP_ISA_D |
|
||||
COMPAT_HWCAP_ISA_C |
|
||||
COMPAT_HWCAP_ISA_V
|
||||
);
|
||||
#else
|
||||
const static uint64_t features = 0;
|
||||
#endif
|
||||
|
||||
return (features & static_cast<uint64_t>(extension)) != 0;
|
||||
}
|
||||
|
||||
uint32_t CPUInfo::GetVlenb() const {
|
||||
if(Has(RISCVExtension::V)) {
|
||||
static CSRReader<CSR::VLenb> csrReader;
|
||||
const static auto getVLEN = csrReader.GetCode<uint32_t (*)()>();
|
||||
return getVLEN();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace biscuit
|
@ -1,76 +0,0 @@
|
||||
project(biscuit_tests)
|
||||
|
||||
add_executable(${PROJECT_NAME}
|
||||
src/assembler_bfloat_tests.cpp
|
||||
src/assembler_branch_tests.cpp
|
||||
src/assembler_cmo_tests.cpp
|
||||
src/assembler_privileged_tests.cpp
|
||||
src/assembler_rv32i_tests.cpp
|
||||
src/assembler_rv64i_tests.cpp
|
||||
src/assembler_rva_tests.cpp
|
||||
src/assembler_rvb_tests.cpp
|
||||
src/assembler_rvc_tests.cpp
|
||||
src/assembler_rvd_tests.cpp
|
||||
src/assembler_rvf_tests.cpp
|
||||
src/assembler_rvk_tests.cpp
|
||||
src/assembler_rvm_tests.cpp
|
||||
src/assembler_rvq_tests.cpp
|
||||
src/assembler_rvv_tests.cpp
|
||||
src/assembler_vector_crypto_tests.cpp
|
||||
src/assembler_zacas_tests.cpp
|
||||
src/assembler_zawrs_tests.cpp
|
||||
src/assembler_zc_tests.cpp
|
||||
src/assembler_zfa_tests.cpp
|
||||
src/assembler_zicond_tests.cpp
|
||||
src/assembler_zicsr_tests.cpp
|
||||
src/assembler_zihintntl_tests.cpp
|
||||
src/main.cpp
|
||||
|
||||
src/assembler_test_utils.hpp
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
externals/
|
||||
)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
biscuit
|
||||
)
|
||||
|
||||
target_compile_features(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
cxx_std_20
|
||||
)
|
||||
|
||||
if (MSVC)
|
||||
target_compile_options(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
/MP
|
||||
/Zi
|
||||
/Zo
|
||||
/permissive-
|
||||
/EHsc
|
||||
/utf-8
|
||||
/volatile:iso
|
||||
/Zc:externConstexpr
|
||||
/Zc:inline
|
||||
/Zc:throwingNew
|
||||
|
||||
# Warnings
|
||||
/W4
|
||||
/we4062 # enumerator 'identifier' in a switch of enum 'enumeration' is not handled
|
||||
/we4101 # 'identifier': unreferenced local variable
|
||||
/we4265 # 'class': class has virtual functions, but destructor is not virtual
|
||||
/we4388 # signed/unsigned mismatch
|
||||
/we4547 # 'operator' : operator before comma has no effect; expected operator with side-effect
|
||||
/we4549 # 'operator1': operator before comma has no effect; did you intend 'operator2'?
|
||||
/we4555 # Expression has no effect; expected expression with side-effect
|
||||
/we4715 # 'function': not all control paths return a value
|
||||
/we4834 # Discarding return value of function with 'nodiscard' attribute
|
||||
/we5038 # data member 'member1' will be initialized after data member 'member2'
|
||||
)
|
||||
endif()
|
||||
|
||||
add_test(biscuit_tests_ctest ${PROJECT_NAME})
|
File diff suppressed because it is too large
Load Diff
@ -1,95 +0,0 @@
|
||||
#include <catch/catch.hpp>
|
||||
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include "assembler_test_utils.hpp"
|
||||
|
||||
using namespace biscuit;
|
||||
|
||||
TEST_CASE("FCVT.BF16.S", "[Zfbfmin]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FCVT_BF16_S(f31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0x44838FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_BF16_S(f31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0x4483CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_BF16_S(f31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0x4483FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVT.S.BF16", "[Zfbfmin]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FCVT_S_BF16(f31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0x40638FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_S_BF16(f31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0x4063CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_S_BF16(f31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0x4063FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("VFNCVTBF16.F.F.W", "[Zvfbfmin]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.VFNCVTBF16_F_F_W(v31, v7, VecMask::Yes);
|
||||
REQUIRE(value == 0x487E9FD7);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VFNCVTBF16_F_F_W(v31, v7, VecMask::No);
|
||||
REQUIRE(value == 0x4A7E9FD7);
|
||||
}
|
||||
|
||||
TEST_CASE("VFWCVTBF16.F.F.V", "[Zvfbfmin]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.VFWCVTBF16_F_F_V(v31, v7, VecMask::Yes);
|
||||
REQUIRE(value == 0x48769FD7);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VFWCVTBF16_F_F_V(v31, v7, VecMask::No);
|
||||
REQUIRE(value == 0x4A769FD7);
|
||||
}
|
||||
|
||||
TEST_CASE("VFWMACCBF16.VF", "[Zvfbfwma]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.VFWMACCBF16(v31, f7, v20, VecMask::Yes);
|
||||
REQUIRE(value == 0xED43DFD7);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VFWMACCBF16(v31, f7, v20, VecMask::No);
|
||||
REQUIRE(value == 0xEF43DFD7);
|
||||
}
|
||||
|
||||
TEST_CASE("VFWMACCBF16.VV", "[Zvfbfwma]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.VFWMACCBF16(v31, v7, v20, VecMask::Yes);
|
||||
REQUIRE(value == 0xED439FD7);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VFWMACCBF16(v31, v7, v20, VecMask::No);
|
||||
REQUIRE(value == 0xEF439FD7);
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
#include <catch/catch.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include "assembler_test_utils.hpp"
|
||||
|
||||
using namespace biscuit;
|
||||
|
||||
TEST_CASE("Branch to Self", "[branch]") {
|
||||
uint32_t data;
|
||||
auto as = MakeAssembler32(data);
|
||||
|
||||
// Simple branch to self with a jump instruction.
|
||||
{
|
||||
Label label;
|
||||
as.Bind(&label);
|
||||
as.J(&label);
|
||||
REQUIRE(data == 0x0000006F);
|
||||
}
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
// Simple branch to self with a compressed jump instruction.
|
||||
{
|
||||
Label label;
|
||||
as.Bind(&label);
|
||||
as.C_J(&label);
|
||||
REQUIRE((data & 0xFFFF) == 0xA001);
|
||||
}
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
// Simple branch to self with a conditional branch instruction.
|
||||
{
|
||||
Label label;
|
||||
as.Bind(&label);
|
||||
as.BNE(x3, x4, &label);
|
||||
REQUIRE(data == 0x00419063);
|
||||
}
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
// Simple branch to self with a compressed branch instruction.
|
||||
{
|
||||
Label label;
|
||||
as.Bind(&label);
|
||||
as.C_BNEZ(x15, &label);
|
||||
REQUIRE((data & 0xFFFF) == 0xE381);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Branch with Instructions Between", "[branch]") {
|
||||
std::array<uint32_t, 20> data{};
|
||||
auto as = MakeAssembler32(data);
|
||||
|
||||
// Simple branch backward
|
||||
{
|
||||
Label label;
|
||||
as.Bind(&label);
|
||||
as.ADD(x1, x2, x3);
|
||||
as.SUB(x2, x4, x3);
|
||||
as.J(&label);
|
||||
REQUIRE(data[2] == 0xFF9FF06F);
|
||||
}
|
||||
|
||||
as.RewindBuffer();
|
||||
data.fill(0);
|
||||
|
||||
// Simple branch forward
|
||||
{
|
||||
Label label;
|
||||
as.J(&label);
|
||||
as.ADD(x1, x2, x3);
|
||||
as.SUB(x2, x4, x3);
|
||||
as.Bind(&label);
|
||||
REQUIRE(data[0] == 0x00C0006F);
|
||||
}
|
||||
|
||||
as.RewindBuffer();
|
||||
data.fill(0);
|
||||
|
||||
// Simple branch backward (compressed)
|
||||
{
|
||||
Label label;
|
||||
as.Bind(&label);
|
||||
as.ADD(x1, x2, x3);
|
||||
as.SUB(x2, x4, x3);
|
||||
as.C_J(&label);
|
||||
REQUIRE((data[2] & 0xFFFF) == 0xBFC5);
|
||||
}
|
||||
|
||||
as.RewindBuffer();
|
||||
data.fill(0);
|
||||
|
||||
// Simple branch forward (compressed)
|
||||
{
|
||||
Label label;
|
||||
as.C_J(&label);
|
||||
as.ADD(x1, x2, x3);
|
||||
as.SUB(x2, x4, x3);
|
||||
as.Bind(&label);
|
||||
REQUIRE((data[0] & 0xFFFF) == 0xA0A1);
|
||||
}
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
#include <catch/catch.hpp>
|
||||
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include "assembler_test_utils.hpp"
|
||||
|
||||
using namespace biscuit;
|
||||
|
||||
TEST_CASE("CBO.CLEAN", "[cmo]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.CBO_CLEAN(x0);
|
||||
REQUIRE(value == 0x0010200F);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.CBO_CLEAN(x31);
|
||||
REQUIRE(value == 0x001FA00F);
|
||||
}
|
||||
|
||||
TEST_CASE("CBO.FLUSH", "[cmo]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.CBO_FLUSH(x0);
|
||||
REQUIRE(value == 0x0020200F);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.CBO_FLUSH(x31);
|
||||
REQUIRE(value == 0x002FA00F);
|
||||
}
|
||||
|
||||
TEST_CASE("CBO.INVAL", "[cmo]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.CBO_INVAL(x0);
|
||||
REQUIRE(value == 0x0000200F);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.CBO_INVAL(x31);
|
||||
REQUIRE(value == 0x000FA00F);
|
||||
}
|
||||
|
||||
TEST_CASE("CBO.ZERO", "[cmo]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.CBO_ZERO(x0);
|
||||
REQUIRE(value == 0x0040200F);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.CBO_ZERO(x31);
|
||||
REQUIRE(value == 0x004FA00F);
|
||||
}
|
||||
|
||||
TEST_CASE("PREFETCH.I", "[cmo]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.PREFETCH_I(x0);
|
||||
REQUIRE(value == 0x00006013);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.PREFETCH_I(x31, 2016);
|
||||
REQUIRE(value == 0x7E0FE013);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.PREFETCH_I(x31, -2016);
|
||||
REQUIRE(value == 0x820FE013);
|
||||
}
|
||||
|
||||
TEST_CASE("PREFETCH.R", "[cmo]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.PREFETCH_R(x0);
|
||||
REQUIRE(value == 0x00106013);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.PREFETCH_R(x31, 2016);
|
||||
REQUIRE(value == 0x7E1FE013);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.PREFETCH_R(x31, -2016);
|
||||
REQUIRE(value == 0x821FE013);
|
||||
}
|
||||
|
||||
TEST_CASE("PREFETCH.W", "[cmo]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.PREFETCH_W(x0);
|
||||
REQUIRE(value == 0x00306013);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.PREFETCH_W(x31, 2016);
|
||||
REQUIRE(value == 0x7E3FE013);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.PREFETCH_W(x31, -2016);
|
||||
REQUIRE(value == 0x823FE013);
|
||||
}
|
@ -1,302 +0,0 @@
|
||||
#include <catch/catch.hpp>
|
||||
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include "assembler_test_utils.hpp"
|
||||
|
||||
using namespace biscuit;
|
||||
|
||||
TEST_CASE("HFENCE.VVMA", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.HFENCE_VVMA(x0, x0);
|
||||
REQUIRE(value == 0x22000073);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.HFENCE_VVMA(x15, x15);
|
||||
REQUIRE(value == 0x22F78073);
|
||||
}
|
||||
|
||||
TEST_CASE("HFENCE.GVMA", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.HFENCE_GVMA(x0, x0);
|
||||
REQUIRE(value == 0x62000073);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.HFENCE_GVMA(x15, x15);
|
||||
REQUIRE(value == 0x62F78073);
|
||||
}
|
||||
|
||||
TEST_CASE("HINVAL.VVMA", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.HINVAL_VVMA(x0, x0);
|
||||
REQUIRE(value == 0x26000073);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.HINVAL_VVMA(x15, x15);
|
||||
REQUIRE(value == 0x26F78073);
|
||||
}
|
||||
|
||||
TEST_CASE("HINVAL.GVMA", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.HINVAL_GVMA(x0, x0);
|
||||
REQUIRE(value == 0x66000073);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.HINVAL_GVMA(x15, x15);
|
||||
REQUIRE(value == 0x66F78073);
|
||||
}
|
||||
|
||||
TEST_CASE("HLV.B", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.HLV_B(x0, x0);
|
||||
REQUIRE(value == 0x60004073);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.HLV_B(x15, x14);
|
||||
REQUIRE(value == 0x600747F3);
|
||||
}
|
||||
|
||||
TEST_CASE("HLV.BU", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.HLV_BU(x0, x0);
|
||||
REQUIRE(value == 0x60104073);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.HLV_BU(x15, x14);
|
||||
REQUIRE(value == 0x601747F3);
|
||||
}
|
||||
|
||||
TEST_CASE("HLV.D", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.HLV_D(x0, x0);
|
||||
REQUIRE(value == 0x6C004073);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.HLV_D(x15, x14);
|
||||
REQUIRE(value == 0x6C0747F3);
|
||||
}
|
||||
|
||||
TEST_CASE("HLV.H", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.HLV_H(x0, x0);
|
||||
REQUIRE(value == 0x64004073);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.HLV_H(x15, x14);
|
||||
REQUIRE(value == 0x640747F3);
|
||||
}
|
||||
|
||||
TEST_CASE("HLV.HU", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.HLV_HU(x0, x0);
|
||||
REQUIRE(value == 0x64104073);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.HLV_HU(x15, x14);
|
||||
REQUIRE(value == 0x641747F3);
|
||||
}
|
||||
|
||||
TEST_CASE("HLV.W", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.HLV_W(x0, x0);
|
||||
REQUIRE(value == 0x68004073);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.HLV_W(x15, x14);
|
||||
REQUIRE(value == 0x680747F3);
|
||||
}
|
||||
|
||||
TEST_CASE("HLV.WU", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.HLV_WU(x0, x0);
|
||||
REQUIRE(value == 0x68104073);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.HLV_WU(x15, x14);
|
||||
REQUIRE(value == 0x681747F3);
|
||||
}
|
||||
|
||||
TEST_CASE("HLVX.HU", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.HLVX_HU(x0, x0);
|
||||
REQUIRE(value == 0x64304073);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.HLVX_HU(x15, x14);
|
||||
REQUIRE(value == 0x643747F3);
|
||||
}
|
||||
|
||||
TEST_CASE("HLVX.WU", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.HLVX_WU(x0, x0);
|
||||
REQUIRE(value == 0x68304073);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.HLVX_WU(x15, x14);
|
||||
REQUIRE(value == 0x683747F3);
|
||||
}
|
||||
|
||||
TEST_CASE("HSV.B", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.HSV_B(x0, x0);
|
||||
REQUIRE(value == 0x62004073);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.HSV_B(x15, x14);
|
||||
REQUIRE(value == 0x62F74073);
|
||||
}
|
||||
|
||||
TEST_CASE("HSV.D", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.HSV_D(x0, x0);
|
||||
REQUIRE(value == 0x6E004073);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.HSV_D(x15, x14);
|
||||
REQUIRE(value == 0x6EF74073);
|
||||
}
|
||||
|
||||
TEST_CASE("HSV.H", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.HSV_H(x0, x0);
|
||||
REQUIRE(value == 0x66004073);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.HSV_H(x15, x14);
|
||||
REQUIRE(value == 0x66F74073);
|
||||
}
|
||||
|
||||
TEST_CASE("HSV.W", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.HSV_W(x0, x0);
|
||||
REQUIRE(value == 0x6A004073);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.HSV_W(x15, x14);
|
||||
REQUIRE(value == 0x6AF74073);
|
||||
}
|
||||
|
||||
TEST_CASE("MRET", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.MRET();
|
||||
REQUIRE(value == 0x30200073);
|
||||
}
|
||||
|
||||
TEST_CASE("SFENCE.INVAL.IR", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SFENCE_INVAL_IR();
|
||||
REQUIRE(value == 0x18100073);
|
||||
}
|
||||
|
||||
TEST_CASE("SFENCE.VMA", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SFENCE_VMA(x0, x0);
|
||||
REQUIRE(value == 0x12000073);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SFENCE_VMA(x15, x15);
|
||||
REQUIRE(value == 0x12F78073);
|
||||
}
|
||||
|
||||
TEST_CASE("SFENCE.W.INVAL", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SFENCE_W_INVAL();
|
||||
REQUIRE(value == 0x18000073);
|
||||
}
|
||||
|
||||
TEST_CASE("SINVAL.VMA", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SINVAL_VMA(x0, x0);
|
||||
REQUIRE(value == 0x16000073);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SINVAL_VMA(x15, x15);
|
||||
REQUIRE(value == 0x16F78073);
|
||||
}
|
||||
|
||||
TEST_CASE("SRET", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SRET();
|
||||
REQUIRE(value == 0x10200073);
|
||||
}
|
||||
|
||||
TEST_CASE("URET", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.URET();
|
||||
REQUIRE(value == 0x00200073);
|
||||
}
|
||||
|
||||
TEST_CASE("WFI", "[rvpriv]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.WFI();
|
||||
REQUIRE(value == 0x10500073);
|
||||
}
|
@ -1,769 +0,0 @@
|
||||
#include <catch/catch.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include "assembler_test_utils.hpp"
|
||||
|
||||
using namespace biscuit;
|
||||
|
||||
TEST_CASE("ADD", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.ADD(x7, x15, x31);
|
||||
REQUIRE(value == 0x01F783B3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.ADD(x31, x31, x31);
|
||||
REQUIRE(value == 0x01FF8FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.ADD(x0, x0, x0);
|
||||
REQUIRE(value == 0x00000033);
|
||||
}
|
||||
|
||||
TEST_CASE("ADDI", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.ADDI(x15, x31, 1024);
|
||||
REQUIRE(value == 0x400F8793);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.ADDI(x15, x31, 2048);
|
||||
REQUIRE(value == 0x800F8793);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.ADDI(x15, x31, 4095);
|
||||
REQUIRE(value == 0xFFFF8793);
|
||||
}
|
||||
|
||||
TEST_CASE("AND", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.AND(x7, x15, x31);
|
||||
REQUIRE(value == 0x01F7F3B3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AND(x31, x31, x31);
|
||||
REQUIRE(value == 0x01FFFFB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AND(x0, x0, x0);
|
||||
REQUIRE(value == 0x00007033);
|
||||
}
|
||||
|
||||
TEST_CASE("ANDI", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.ANDI(x15, x31, 1024);
|
||||
REQUIRE(value == 0x400FF793);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.ANDI(x15, x31, 2048);
|
||||
REQUIRE(value == 0x800FF793);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.ANDI(x15, x31, 4095);
|
||||
REQUIRE(value == 0xFFFFF793);
|
||||
}
|
||||
|
||||
TEST_CASE("AUIPC", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.AUIPC(x31, -1);
|
||||
REQUIRE(value == 0xFFFFFF97);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AUIPC(x31, 0);
|
||||
REQUIRE(value == 0x00000F97);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AUIPC(x31, 0x00FF00FF);
|
||||
REQUIRE(value == 0xF00FFF97);
|
||||
}
|
||||
|
||||
TEST_CASE("BEQ", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.BEQ(x15, x31, 2000);
|
||||
REQUIRE(value == 0x7DF78863);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BEQ(x15, x31, -2);
|
||||
REQUIRE(value == 0xFFF78FE3);
|
||||
}
|
||||
|
||||
TEST_CASE("BGE", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.BGE(x15, x31, 2000);
|
||||
REQUIRE(value == 0x7DF7D863);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BGE(x15, x31, -2);
|
||||
REQUIRE(value == 0xFFF7DFE3);
|
||||
}
|
||||
|
||||
TEST_CASE("BGEU", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.BGEU(x15, x31, 2000);
|
||||
REQUIRE(value == 0x7DF7F863);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BGEU(x15, x31, -2);
|
||||
REQUIRE(value == 0xFFF7FFE3);
|
||||
}
|
||||
|
||||
TEST_CASE("BNE", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.BNE(x15, x31, 2000);
|
||||
REQUIRE(value == 0x7DF79863);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BNE(x15, x31, -2);
|
||||
REQUIRE(value == 0xFFF79FE3);
|
||||
}
|
||||
|
||||
TEST_CASE("BLT", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.BLT(x15, x31, 2000);
|
||||
REQUIRE(value == 0x7DF7C863);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BLT(x15, x31, -2);
|
||||
REQUIRE(value == 0xFFF7CFE3);
|
||||
}
|
||||
|
||||
TEST_CASE("BLTU", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.BLTU(x15, x31, 2000);
|
||||
REQUIRE(value == 0x7DF7E863);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BLTU(x15, x31, -2);
|
||||
REQUIRE(value == 0xFFF7EFE3);
|
||||
}
|
||||
|
||||
TEST_CASE("CALL", "[rv32i]") {
|
||||
std::array<uint32_t, 2> vals{};
|
||||
auto as = MakeAssembler32(vals);
|
||||
|
||||
const auto compare_vals = [&vals](uint32_t val_1, uint32_t val_2) {
|
||||
REQUIRE(vals[0] == val_1);
|
||||
REQUIRE(vals[1] == val_2);
|
||||
};
|
||||
|
||||
as.CALL(-1);
|
||||
compare_vals(0x00000097, 0xFFF080E7);
|
||||
}
|
||||
|
||||
TEST_CASE("EBREAK", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.EBREAK();
|
||||
REQUIRE(value == 0x00100073);
|
||||
}
|
||||
|
||||
TEST_CASE("ECALL", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.ECALL();
|
||||
REQUIRE(value == 0x00000073);
|
||||
}
|
||||
|
||||
TEST_CASE("FENCE", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FENCE(FenceOrder::IORW, FenceOrder::IORW);
|
||||
REQUIRE(value == 0x0FF0000F);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FENCETSO();
|
||||
REQUIRE(value == 0x8330000F);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FENCEI();
|
||||
REQUIRE(value == 0x0000100F);
|
||||
}
|
||||
|
||||
TEST_CASE("JAL", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.JAL(x31, 0xFFFFFFFF);
|
||||
REQUIRE(value == 0xFFFFFFEF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.JAL(x31, 2000);
|
||||
REQUIRE(value == 0x7D000FEF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.JAL(x31, 100000);
|
||||
REQUIRE(value == 0x6A018FEF);
|
||||
}
|
||||
|
||||
TEST_CASE("JALR", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.JALR(x15, 1024, x31);
|
||||
REQUIRE(value == 0x400F87E7);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.JALR(x15, 1536, x31);
|
||||
REQUIRE(value == 0x600F87E7);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.JALR(x15, -1, x31);
|
||||
REQUIRE(value == 0xFFFF87E7);
|
||||
}
|
||||
|
||||
TEST_CASE("LB", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.LB(x15, 1024, x31);
|
||||
REQUIRE(value == 0x400F8783);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.LB(x15, 1536, x31);
|
||||
REQUIRE(value == 0x600F8783);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.LB(x15, -1, x31);
|
||||
REQUIRE(value == 0xFFFF8783);
|
||||
}
|
||||
|
||||
TEST_CASE("LBU", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.LBU(x15, 1024, x31);
|
||||
REQUIRE(value == 0x400FC783);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.LBU(x15, 1536, x31);
|
||||
REQUIRE(value == 0x600FC783);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.LBU(x15, -1, x31);
|
||||
REQUIRE(value == 0xFFFFC783);
|
||||
}
|
||||
|
||||
TEST_CASE("LH", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.LH(x15, 1024, x31);
|
||||
REQUIRE(value == 0x400F9783);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.LH(x15, 1536, x31);
|
||||
REQUIRE(value == 0x600F9783);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.LH(x15, -1, x31);
|
||||
REQUIRE(value == 0xFFFF9783);
|
||||
}
|
||||
|
||||
TEST_CASE("LHU", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.LHU(x15, 1024, x31);
|
||||
REQUIRE(value == 0x400FD783);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.LHU(x15, 1536, x31);
|
||||
REQUIRE(value == 0x600FD783);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.LHU(x15, -1, x31);
|
||||
REQUIRE(value == 0xFFFFD783);
|
||||
}
|
||||
|
||||
TEST_CASE("LI", "[rv32i]") {
|
||||
std::array<uint32_t, 2> vals{};
|
||||
auto as = MakeAssembler32(vals);
|
||||
|
||||
const auto compare_vals = [&vals](uint32_t val_1, uint32_t val_2) {
|
||||
REQUIRE(vals[0] == val_1);
|
||||
REQUIRE(vals[1] == val_2);
|
||||
};
|
||||
|
||||
///////// Single ADDI cases
|
||||
|
||||
as.LI(x1, 0);
|
||||
// addi x1, x0, 0
|
||||
compare_vals(0x00000093, 0x00000000);
|
||||
as.RewindBuffer();
|
||||
vals = {};
|
||||
|
||||
as.LI(x1, -1);
|
||||
// addi x1, x0, -1
|
||||
compare_vals(0xFFF00093, 0x00000000);
|
||||
as.RewindBuffer();
|
||||
vals = {};
|
||||
|
||||
as.LI(x1, 42);
|
||||
// addi x1, x0, 42
|
||||
compare_vals(0x02A00093, 0x000000000);
|
||||
as.RewindBuffer();
|
||||
vals = {};
|
||||
|
||||
as.LI(x1, 0x7ff);
|
||||
// addi x1, x0, 2047
|
||||
compare_vals(0x7FF00093, 0x00000000);
|
||||
as.RewindBuffer();
|
||||
vals = {};
|
||||
|
||||
///////// Single LUI cases
|
||||
|
||||
as.LI(x1, 0x2A000);
|
||||
// lui x1, 42
|
||||
compare_vals(0x0002A0B7, 0x00000000);
|
||||
as.RewindBuffer();
|
||||
vals = {};
|
||||
|
||||
as.LI(x1, ~0xFFF);
|
||||
// lui x1, -1
|
||||
compare_vals(0xFFFFF0B7, 0x00000000);
|
||||
as.RewindBuffer();
|
||||
vals = {};
|
||||
|
||||
as.LI(x1, INT32_MIN);
|
||||
// lui x1, -524288
|
||||
compare_vals(0x800000B7, 0x00000000);
|
||||
as.RewindBuffer();
|
||||
vals = {};
|
||||
|
||||
///////// Full LUI+ADDI cases
|
||||
|
||||
as.LI(x1, 0x11111111);
|
||||
// lui x1, 69905
|
||||
// addi x1, x1, 273
|
||||
compare_vals(0x111110B7, 0x11108093);
|
||||
as.RewindBuffer();
|
||||
vals = {};
|
||||
|
||||
as.LI(x1, INT32_MAX);
|
||||
// lui x1, -524288
|
||||
// addi x1, x1, -1
|
||||
compare_vals(0x800000B7, 0xFFF08093);
|
||||
}
|
||||
|
||||
TEST_CASE("LUI", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.LUI(x10, 0xFFFFFFFF);
|
||||
REQUIRE(value == 0xFFFFF537);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.LUI(x10, 0xFFF7FFFF);
|
||||
REQUIRE(value == 0x7FFFF537);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.LUI(x31, 0xFFFFFFFF);
|
||||
REQUIRE(value == 0xFFFFFFB7);
|
||||
}
|
||||
|
||||
TEST_CASE("LW", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.LW(x15, 1024, x31);
|
||||
REQUIRE(value == 0x400FA783);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.LW(x15, 1536, x31);
|
||||
REQUIRE(value == 0x600FA783);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.LW(x15, -1, x31);
|
||||
REQUIRE(value == 0xFFFFA783);
|
||||
}
|
||||
|
||||
TEST_CASE("OR", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.OR(x7, x15, x31);
|
||||
REQUIRE(value == 0x01F7E3B3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.OR(x31, x31, x31);
|
||||
REQUIRE(value == 0x01FFEFB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.OR(x0, x0, x0);
|
||||
REQUIRE(value == 0x00006033);
|
||||
}
|
||||
|
||||
TEST_CASE("ORI", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.ORI(x15, x31, 1024);
|
||||
REQUIRE(value == 0x400FE793);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.ORI(x15, x31, 2048);
|
||||
REQUIRE(value == 0x800FE793);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.ORI(x15, x31, 4095);
|
||||
REQUIRE(value == 0xFFFFE793);
|
||||
}
|
||||
|
||||
TEST_CASE("PAUSE", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.PAUSE();
|
||||
REQUIRE(value == 0x0100000F);
|
||||
}
|
||||
|
||||
TEST_CASE("SB", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SB(x31, 1024, x15);
|
||||
REQUIRE(value == 0x41F78023);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SB(x31, 1536, x15);
|
||||
REQUIRE(value == 0x61F78023);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SB(x31, -1, x15);
|
||||
REQUIRE(value == 0xFFF78FA3);
|
||||
}
|
||||
|
||||
TEST_CASE("SH", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SH(x31, 1024, x15);
|
||||
REQUIRE(value == 0x41F79023);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SH(x31, 1536, x15);
|
||||
REQUIRE(value == 0x61F79023);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SH(x31, -1, x15);
|
||||
REQUIRE(value == 0xFFF79FA3);
|
||||
}
|
||||
|
||||
TEST_CASE("SLL", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SLL(x7, x15, x31);
|
||||
REQUIRE(value == 0x01F793B3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SLL(x31, x31, x31);
|
||||
REQUIRE(value == 0x01FF9FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SLL(x0, x0, x0);
|
||||
REQUIRE(value == 0x00001033);
|
||||
}
|
||||
|
||||
TEST_CASE("SLLI", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SLLI(x31, x15, 10);
|
||||
REQUIRE(value == 0x00A79F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SLLI(x31, x15, 20);
|
||||
REQUIRE(value == 0x01479F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SLLI(x31, x15, 31);
|
||||
REQUIRE(value == 0x01F79F93);
|
||||
}
|
||||
|
||||
TEST_CASE("SLT", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SLT(x7, x15, x31);
|
||||
REQUIRE(value == 0x01F7A3B3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SLT(x31, x31, x31);
|
||||
REQUIRE(value == 0x01FFAFB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SLT(x0, x0, x0);
|
||||
REQUIRE(value == 0x00002033);
|
||||
}
|
||||
|
||||
TEST_CASE("SLTI", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SLTI(x15, x31, 1024);
|
||||
REQUIRE(value == 0x400FA793);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SLTI(x15, x31, -2048);
|
||||
REQUIRE(value == 0x800FA793);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SLTI(x15, x31, -1);
|
||||
REQUIRE(value == 0xFFFFA793);
|
||||
}
|
||||
|
||||
TEST_CASE("SLTIU", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SLTIU(x15, x31, 1024);
|
||||
REQUIRE(value == 0x400FB793);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SLTIU(x15, x31, -2048);
|
||||
REQUIRE(value == 0x800FB793);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SLTIU(x15, x31, -1);
|
||||
REQUIRE(value == 0xFFFFB793);
|
||||
}
|
||||
|
||||
TEST_CASE("SLTU", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SLTU(x7, x15, x31);
|
||||
REQUIRE(value == 0x01F7B3B3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SLTU(x31, x31, x31);
|
||||
REQUIRE(value == 0x01FFBFB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SLTU(x0, x0, x0);
|
||||
REQUIRE(value == 0x00003033);
|
||||
}
|
||||
|
||||
TEST_CASE("SRA", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SRA(x7, x15, x31);
|
||||
REQUIRE(value == 0x41F7D3B3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SRA(x31, x31, x31);
|
||||
REQUIRE(value == 0x41FFDFB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SRA(x0, x0, x0);
|
||||
REQUIRE(value == 0x40005033);
|
||||
}
|
||||
|
||||
TEST_CASE("SRAI", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SRAI(x31, x15, 10);
|
||||
REQUIRE(value == 0x40A7DF93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SRAI(x31, x15, 20);
|
||||
REQUIRE(value == 0x4147DF93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SRAI(x31, x15, 31);
|
||||
REQUIRE(value == 0x41F7DF93);
|
||||
}
|
||||
|
||||
TEST_CASE("SRL", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SRL(x7, x15, x31);
|
||||
REQUIRE(value == 0x01F7D3B3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SRL(x31, x31, x31);
|
||||
REQUIRE(value == 0x01FFDFB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SRL(x0, x0, x0);
|
||||
REQUIRE(value == 0x00005033);
|
||||
}
|
||||
|
||||
TEST_CASE("SRLI", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SRLI(x31, x15, 10);
|
||||
REQUIRE(value == 0x00A7DF93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SRLI(x31, x15, 20);
|
||||
REQUIRE(value == 0x0147DF93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SRLI(x31, x15, 31);
|
||||
REQUIRE(value == 0x01F7DF93);
|
||||
}
|
||||
|
||||
TEST_CASE("SUB", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SUB(x7, x15, x31);
|
||||
REQUIRE(value == 0x41F783B3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SUB(x31, x31, x31);
|
||||
REQUIRE(value == 0x41FF8FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SUB(x0, x0, x0);
|
||||
REQUIRE(value == 0x40000033);
|
||||
}
|
||||
|
||||
TEST_CASE("SW", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SW(x31, 1024, x15);
|
||||
REQUIRE(value == 0x41F7A023);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SW(x31, 1536, x15);
|
||||
REQUIRE(value == 0x61F7A023);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SW(x31, -1, x15);
|
||||
REQUIRE(value == 0xFFF7AFA3);
|
||||
}
|
||||
|
||||
TEST_CASE("XOR", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.XOR(x7, x15, x31);
|
||||
REQUIRE(value == 0x01F7C3B3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.XOR(x31, x31, x31);
|
||||
REQUIRE(value == 0x01FFCFB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.XOR(x0, x0, x0);
|
||||
REQUIRE(value == 0x00004033);
|
||||
}
|
||||
|
||||
TEST_CASE("XORI", "[rv32i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.XORI(x15, x31, 1024);
|
||||
REQUIRE(value == 0x400FC793);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.XORI(x15, x31, 2048);
|
||||
REQUIRE(value == 0x800FC793);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.XORI(x15, x31, 4095);
|
||||
REQUIRE(value == 0xFFFFC793);
|
||||
}
|
@ -1,436 +0,0 @@
|
||||
#include <catch/catch.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include "assembler_test_utils.hpp"
|
||||
|
||||
using namespace biscuit;
|
||||
|
||||
TEST_CASE("ADDIW", "[rv64i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.ADDIW(x31, x15, 1024);
|
||||
REQUIRE(value == 0x40078F9B);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.ADDIW(x31, x15, 2048);
|
||||
REQUIRE(value == 0x80078F9B);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.ADDIW(x31, x15, 4095);
|
||||
REQUIRE(value == 0xFFF78F9B);
|
||||
}
|
||||
|
||||
TEST_CASE("ADDW", "[rv64i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.ADDW(x7, x15, x31);
|
||||
REQUIRE(value == 0x01F783BB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.ADDW(x31, x31, x31);
|
||||
REQUIRE(value == 0x01FF8FBB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.ADDW(x0, x0, x0);
|
||||
REQUIRE(value == 0x0000003B);
|
||||
}
|
||||
|
||||
TEST_CASE("LWU", "[rv64i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.LWU(x15, 1024, x31);
|
||||
REQUIRE(value == 0x400FE783);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.LWU(x15, 1536, x31);
|
||||
REQUIRE(value == 0x600FE783);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.LWU(x15, -1, x31);
|
||||
REQUIRE(value == 0xFFFFE783);
|
||||
}
|
||||
|
||||
TEST_CASE("LD", "[rv64i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.LD(x15, 1024, x31);
|
||||
REQUIRE(value == 0x400FB783);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.LD(x15, 1536, x31);
|
||||
REQUIRE(value == 0x600FB783);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.LD(x15, -1, x31);
|
||||
REQUIRE(value == 0xFFFFB783);
|
||||
}
|
||||
|
||||
TEST_CASE("LI (RV64)", "[rv64i]") {
|
||||
// Up to 8 instructions can be generated
|
||||
std::array<uint32_t, 8> vals{};
|
||||
auto as = MakeAssembler64(vals);
|
||||
|
||||
const auto compare_vals = [&vals]<typename... Args>(const Args&... args) {
|
||||
static_assert(sizeof...(args) <= vals.size());
|
||||
|
||||
size_t i = 0;
|
||||
for (const auto arg : {args...}) {
|
||||
REQUIRE(vals[i] == arg);
|
||||
i++;
|
||||
}
|
||||
};
|
||||
|
||||
///////// Single ADDIW cases
|
||||
|
||||
as.LI(x1, 0);
|
||||
// addiw x1, x0, 0
|
||||
compare_vals(0x0000009BU, 0x00000000U);
|
||||
as.RewindBuffer();
|
||||
vals = {};
|
||||
|
||||
as.LI(x1, -1);
|
||||
// addiw x1, x0, -1
|
||||
compare_vals(0xFFF0009BU, 0x00000000U);
|
||||
as.RewindBuffer();
|
||||
vals = {};
|
||||
|
||||
as.LI(x1, 42);
|
||||
// addiw x1, x0, 42
|
||||
compare_vals(0x02A0009BU, 0x000000000U);
|
||||
as.RewindBuffer();
|
||||
vals = {};
|
||||
|
||||
as.LI(x1, 0x7ff);
|
||||
// addiw x1, x0, 2047
|
||||
compare_vals(0x7FF0009BU, 0x00000000U);
|
||||
as.RewindBuffer();
|
||||
vals = {};
|
||||
|
||||
///////// Single LUI cases
|
||||
|
||||
as.LI(x1, 0x2A000);
|
||||
// lui x1, 42
|
||||
compare_vals(0x0002A0B7U, 0x00000000U);
|
||||
as.RewindBuffer();
|
||||
vals = {};
|
||||
|
||||
as.LI(x1, ~0xFFF);
|
||||
// lui x1, -1
|
||||
compare_vals(0xFFFFF0B7U, 0x00000000U);
|
||||
as.RewindBuffer();
|
||||
vals = {};
|
||||
|
||||
as.LI(x1, INT32_MIN);
|
||||
// lui x1, -524288
|
||||
compare_vals(0x800000B7U, 0x00000000U);
|
||||
as.RewindBuffer();
|
||||
vals = {};
|
||||
|
||||
///////// LUI+ADDIW cases
|
||||
|
||||
as.LI(x1, 0x11111111);
|
||||
// lui x1, 69905
|
||||
// addiw x1, x1, 273
|
||||
compare_vals(0x111110B7U, 0x1110809BU, 0x00000000U);
|
||||
as.RewindBuffer();
|
||||
vals = {};
|
||||
|
||||
as.LI(x1, INT32_MAX);
|
||||
// lui x1, -524288
|
||||
// addiw x1, x1, -1
|
||||
compare_vals(0x800000B7U, 0xFFF0809BU, 0x00000000U);
|
||||
as.RewindBuffer();
|
||||
vals = {};
|
||||
|
||||
///////// ADDIW+SLLI cases
|
||||
|
||||
as.LI(x1, 0x7FF0000000ULL);
|
||||
// addiw x1, x0, 2047
|
||||
// slli x1, x1, 28
|
||||
compare_vals(0x7FF0009BU, 0x01C09093U, 0x000000000U);
|
||||
as.RewindBuffer();
|
||||
vals = {};
|
||||
|
||||
as.LI(x1, 0xABC00000ULL);
|
||||
// addiw x1, x0, 687
|
||||
// slli x1, x1, 22
|
||||
compare_vals(0x2AF0009BU, 0x01609093U, 0x000000000U);
|
||||
as.RewindBuffer();
|
||||
vals = {};
|
||||
|
||||
///////// LUI+ADDIW+SLLI cases
|
||||
|
||||
as.LI(x1, 0x7FFFFFFF0000ULL);
|
||||
// lui x1, -524288
|
||||
// addiw x1, x1, -1
|
||||
// slli x1, x1, 16
|
||||
compare_vals(0x800000B7U, 0xFFF0809BU, 0x01009093U, 0x000000000U);
|
||||
as.RewindBuffer();
|
||||
vals = {};
|
||||
|
||||
///////// LUI+ADDIW+SLLI+ADDI cases
|
||||
|
||||
as.LI(x1, 0x7FFFFFFF0123);
|
||||
// lui x1, -524288
|
||||
// addiw x1, x1, -1
|
||||
// slli x1, x1, 16
|
||||
// addi x1, x1, 291
|
||||
compare_vals(0x800000B7U, 0xfff0809BU, 0x01009093U, 0x12308093U,
|
||||
0x000000000U);
|
||||
as.RewindBuffer();
|
||||
vals = {};
|
||||
|
||||
///////// ADDIW+SLLI+ADDI+SLLI+ADDI cases
|
||||
|
||||
as.LI(x1, 0x8000000080000001ULL);
|
||||
// addiw x1, x0, -1
|
||||
// slli x1, x1, 32
|
||||
// addi x1, x1, 1
|
||||
// slli x1, x1, 31
|
||||
// addi x1, x1, 1
|
||||
compare_vals(0xFFF0009BU, 0x02009093U, 0x00108093U, 0x01F09093U,
|
||||
0x00108093U, 0x000000000U);
|
||||
as.RewindBuffer();
|
||||
vals = {};
|
||||
|
||||
///////// Full LUI+ADDIW+SLLI+ADDI+SLLI+ADDI+SLLI+ADDI cases
|
||||
|
||||
as.LI(x1, 0x80808000808080F1ULL);
|
||||
// lui x1, -16
|
||||
// addiw x1, x1, 257
|
||||
// slli x1, x1, 16
|
||||
// addi x1, x1, 1
|
||||
// slli x1, x1, 16
|
||||
// addi x1, x1, 257
|
||||
// slli x1, x1, 15
|
||||
// addi x1, x1, 241
|
||||
compare_vals(0xFFFF00B7U, 0x1010809BU, 0x01009093U, 0x00108093U,
|
||||
0x01009093U, 0x10108093U, 0x00F09093U, 0x0F108093U);
|
||||
}
|
||||
|
||||
TEST_CASE("SD", "[rv64i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SD(x15, 1024, x31);
|
||||
REQUIRE(value == 0x40FFB023);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SD(x15, 1536, x31);
|
||||
REQUIRE(value == 0x60FFB023);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SD(x15, -1, x31);
|
||||
REQUIRE(value == 0xFEFFBFA3);
|
||||
}
|
||||
|
||||
TEST_CASE("SLLI (RV64)", "[rv64i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SLLI(x31, x15, 10);
|
||||
REQUIRE(value == 0x00A79F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SLLI(x31, x15, 20);
|
||||
REQUIRE(value == 0x01479F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SLLI(x31, x15, 31);
|
||||
REQUIRE(value == 0x01F79F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SLLI(x31, x15, 63);
|
||||
REQUIRE(value == 0x03F79F93);
|
||||
}
|
||||
|
||||
TEST_CASE("SLLIW", "[rv64i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SLLIW(x31, x15, 10);
|
||||
REQUIRE(value == 0x00A79F9B);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SLLIW(x31, x15, 20);
|
||||
REQUIRE(value == 0x01479F9B);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SLLIW(x31, x15, 31);
|
||||
REQUIRE(value == 0x01F79F9B);
|
||||
}
|
||||
|
||||
TEST_CASE("SLLW", "[rv64i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SLLW(x7, x15, x31);
|
||||
REQUIRE(value == 0x01F793BB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SLLW(x31, x31, x31);
|
||||
REQUIRE(value == 0x01FF9FBB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SLLW(x0, x0, x0);
|
||||
REQUIRE(value == 0x0000103B);
|
||||
}
|
||||
|
||||
TEST_CASE("SRAI (RV64)", "[rv64i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SRAI(x31, x15, 10);
|
||||
REQUIRE(value == 0x40A7DF93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SRAI(x31, x15, 20);
|
||||
REQUIRE(value == 0x4147DF93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SRAI(x31, x15, 31);
|
||||
REQUIRE(value == 0x41F7DF93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SRAI(x31, x15, 63);
|
||||
REQUIRE(value == 0x43F7DF93);
|
||||
}
|
||||
|
||||
TEST_CASE("SRAIW", "[rv64i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SRAIW(x31, x15, 10);
|
||||
REQUIRE(value == 0x40A7DF9B);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SRAIW(x31, x15, 20);
|
||||
REQUIRE(value == 0x4147DF9B);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SRAIW(x31, x15, 31);
|
||||
REQUIRE(value == 0x41F7DF9B);
|
||||
}
|
||||
|
||||
TEST_CASE("SRAW", "[rv64i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SRAW(x7, x15, x31);
|
||||
REQUIRE(value == 0x41F7D3BB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SRAW(x31, x31, x31);
|
||||
REQUIRE(value == 0x41FFDFBB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SRAW(x0, x0, x0);
|
||||
REQUIRE(value == 0x4000503B);
|
||||
}
|
||||
|
||||
TEST_CASE("SRLI (RV64)", "[rv64i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SRLI(x31, x15, 10);
|
||||
REQUIRE(value == 0x00A7DF93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SRLI(x31, x15, 20);
|
||||
REQUIRE(value == 0x0147DF93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SRLI(x31, x15, 31);
|
||||
REQUIRE(value == 0x01F7DF93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SRLI(x31, x15, 63);
|
||||
REQUIRE(value == 0x03F7DF93);
|
||||
}
|
||||
|
||||
TEST_CASE("SRLIW", "[rv64i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SRLIW(x31, x15, 10);
|
||||
REQUIRE(value == 0x00A7DF9B);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SRLIW(x31, x15, 20);
|
||||
REQUIRE(value == 0x0147DF9B);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SRLIW(x31, x15, 31);
|
||||
REQUIRE(value == 0x01F7DF9B);
|
||||
}
|
||||
|
||||
TEST_CASE("SRLW", "[rv64i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SRLW(x7, x15, x31);
|
||||
REQUIRE(value == 0x01F7D3BB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SRLW(x31, x31, x31);
|
||||
REQUIRE(value == 0x01FFDFBB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SRLW(x0, x0, x0);
|
||||
REQUIRE(value == 0x0000503B);
|
||||
}
|
||||
|
||||
TEST_CASE("SUBW", "[rv64i]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SUBW(x7, x15, x31);
|
||||
REQUIRE(value == 0x41F783BB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SUBW(x31, x31, x31);
|
||||
REQUIRE(value == 0x41FF8FBB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SUBW(x0, x0, x0);
|
||||
REQUIRE(value == 0x4000003B);
|
||||
}
|
@ -1,513 +0,0 @@
|
||||
#include <catch/catch.hpp>
|
||||
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include "assembler_test_utils.hpp"
|
||||
|
||||
using namespace biscuit;
|
||||
|
||||
TEST_CASE("AMOADD.D", "[rv64a]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.AMOADD_D(Ordering::None, x31, x7, x15);
|
||||
REQUIRE(value == 0x0077BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOADD_D(Ordering::AQ, x31, x7, x15);
|
||||
REQUIRE(value == 0x0477BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOADD_D(Ordering::RL, x31, x7, x15);
|
||||
REQUIRE(value == 0x0277BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOADD_D(Ordering::AQRL, x31, x7, x15);
|
||||
REQUIRE(value == 0x0677BFAF);
|
||||
}
|
||||
|
||||
TEST_CASE("AMOADD.W", "[rv32a]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.AMOADD_W(Ordering::None, x31, x7, x15);
|
||||
REQUIRE(value == 0x0077AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOADD_W(Ordering::AQ, x31, x7, x15);
|
||||
REQUIRE(value == 0x0477AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOADD_W(Ordering::RL, x31, x7, x15);
|
||||
REQUIRE(value == 0x0277AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOADD_W(Ordering::AQRL, x31, x7, x15);
|
||||
REQUIRE(value == 0x0677AFAF);
|
||||
}
|
||||
|
||||
TEST_CASE("AMOAND.D", "[rv64a]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.AMOAND_D(Ordering::None, x31, x7, x15);
|
||||
REQUIRE(value == 0x6077BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOAND_D(Ordering::AQ, x31, x7, x15);
|
||||
REQUIRE(value == 0x6477BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOAND_D(Ordering::RL, x31, x7, x15);
|
||||
REQUIRE(value == 0x6277BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOAND_D(Ordering::AQRL, x31, x7, x15);
|
||||
REQUIRE(value == 0x6677BFAF);
|
||||
}
|
||||
|
||||
TEST_CASE("AMOAND.W", "[rv32a]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.AMOAND_W(Ordering::None, x31, x7, x15);
|
||||
REQUIRE(value == 0x6077AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOAND_W(Ordering::AQ, x31, x7, x15);
|
||||
REQUIRE(value == 0x6477AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOAND_W(Ordering::RL, x31, x7, x15);
|
||||
REQUIRE(value == 0x6277AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOAND_W(Ordering::AQRL, x31, x7, x15);
|
||||
REQUIRE(value == 0x6677AFAF);
|
||||
}
|
||||
|
||||
TEST_CASE("AMOMAX.D", "[rv64a]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.AMOMAX_D(Ordering::None, x31, x7, x15);
|
||||
REQUIRE(value == 0xA077BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMAX_D(Ordering::AQ, x31, x7, x15);
|
||||
REQUIRE(value == 0xA477BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMAX_D(Ordering::RL, x31, x7, x15);
|
||||
REQUIRE(value == 0xA277BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMAX_D(Ordering::AQRL, x31, x7, x15);
|
||||
REQUIRE(value == 0xA677BFAF);
|
||||
}
|
||||
|
||||
TEST_CASE("AMOMAX.W", "[rv32a]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.AMOMAX_W(Ordering::None, x31, x7, x15);
|
||||
REQUIRE(value == 0xA077AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMAX_W(Ordering::AQ, x31, x7, x15);
|
||||
REQUIRE(value == 0xA477AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMAX_W(Ordering::RL, x31, x7, x15);
|
||||
REQUIRE(value == 0xA277AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMAX_W(Ordering::AQRL, x31, x7, x15);
|
||||
REQUIRE(value == 0xA677AFAF);
|
||||
}
|
||||
|
||||
TEST_CASE("AMOMAXU.D", "[rv64a]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.AMOMAXU_D(Ordering::None, x31, x7, x15);
|
||||
REQUIRE(value == 0xE077BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMAXU_D(Ordering::AQ, x31, x7, x15);
|
||||
REQUIRE(value == 0xE477BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMAXU_D(Ordering::RL, x31, x7, x15);
|
||||
REQUIRE(value == 0xE277BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMAXU_D(Ordering::AQRL, x31, x7, x15);
|
||||
REQUIRE(value == 0xE677BFAF);
|
||||
}
|
||||
|
||||
TEST_CASE("AMOMAXU.W", "[rv32a]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.AMOMAXU_W(Ordering::None, x31, x7, x15);
|
||||
REQUIRE(value == 0xE077AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMAXU_W(Ordering::AQ, x31, x7, x15);
|
||||
REQUIRE(value == 0xE477AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMAXU_W(Ordering::RL, x31, x7, x15);
|
||||
REQUIRE(value == 0xE277AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMAXU_W(Ordering::AQRL, x31, x7, x15);
|
||||
REQUIRE(value == 0xE677AFAF);
|
||||
}
|
||||
|
||||
TEST_CASE("AMOMIN.D", "[rv64a]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.AMOMIN_D(Ordering::None, x31, x7, x15);
|
||||
REQUIRE(value == 0x8077BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMIN_D(Ordering::AQ, x31, x7, x15);
|
||||
REQUIRE(value == 0x8477BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMIN_D(Ordering::RL, x31, x7, x15);
|
||||
REQUIRE(value == 0x8277BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMIN_D(Ordering::AQRL, x31, x7, x15);
|
||||
REQUIRE(value == 0x8677BFAF);
|
||||
}
|
||||
|
||||
TEST_CASE("AMOMIN.W", "[rv32a]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.AMOMIN_W(Ordering::None, x31, x7, x15);
|
||||
REQUIRE(value == 0x8077AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMIN_W(Ordering::AQ, x31, x7, x15);
|
||||
REQUIRE(value == 0x8477AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMIN_W(Ordering::RL, x31, x7, x15);
|
||||
REQUIRE(value == 0x8277AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMIN_W(Ordering::AQRL, x31, x7, x15);
|
||||
REQUIRE(value == 0x8677AFAF);
|
||||
}
|
||||
|
||||
TEST_CASE("AMOMINU.D", "[rv64a]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.AMOMINU_D(Ordering::None, x31, x7, x15);
|
||||
REQUIRE(value == 0xC077BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMINU_D(Ordering::AQ, x31, x7, x15);
|
||||
REQUIRE(value == 0xC477BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMINU_D(Ordering::RL, x31, x7, x15);
|
||||
REQUIRE(value == 0xC277BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMINU_D(Ordering::AQRL, x31, x7, x15);
|
||||
REQUIRE(value == 0xC677BFAF);
|
||||
}
|
||||
|
||||
TEST_CASE("AMOMINU.W", "[rv32a]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.AMOMINU_W(Ordering::None, x31, x7, x15);
|
||||
REQUIRE(value == 0xC077AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMINU_W(Ordering::AQ, x31, x7, x15);
|
||||
REQUIRE(value == 0xC477AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMINU_W(Ordering::RL, x31, x7, x15);
|
||||
REQUIRE(value == 0xC277AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOMINU_W(Ordering::AQRL, x31, x7, x15);
|
||||
REQUIRE(value == 0xC677AFAF);
|
||||
}
|
||||
|
||||
TEST_CASE("AMOOR.D", "[rv64a]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.AMOOR_D(Ordering::None, x31, x7, x15);
|
||||
REQUIRE(value == 0x4077BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOOR_D(Ordering::AQ, x31, x7, x15);
|
||||
REQUIRE(value == 0x4477BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOOR_D(Ordering::RL, x31, x7, x15);
|
||||
REQUIRE(value == 0x4277BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOOR_D(Ordering::AQRL, x31, x7, x15);
|
||||
REQUIRE(value == 0x4677BFAF);
|
||||
}
|
||||
|
||||
TEST_CASE("AMOOR.W", "[rv32a]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.AMOOR_W(Ordering::None, x31, x7, x15);
|
||||
REQUIRE(value == 0x4077AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOOR_W(Ordering::AQ, x31, x7, x15);
|
||||
REQUIRE(value == 0x4477AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOOR_W(Ordering::RL, x31, x7, x15);
|
||||
REQUIRE(value == 0x4277AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOOR_W(Ordering::AQRL, x31, x7, x15);
|
||||
REQUIRE(value == 0x4677AFAF);
|
||||
}
|
||||
|
||||
TEST_CASE("AMOSWAP.D", "[rv64a]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.AMOSWAP_D(Ordering::None, x31, x7, x15);
|
||||
REQUIRE(value == 0x0877BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOSWAP_D(Ordering::AQ, x31, x7, x15);
|
||||
REQUIRE(value == 0x0C77BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOSWAP_D(Ordering::RL, x31, x7, x15);
|
||||
REQUIRE(value == 0x0A77BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOSWAP_D(Ordering::AQRL, x31, x7, x15);
|
||||
REQUIRE(value == 0x0E77BFAF);
|
||||
}
|
||||
|
||||
TEST_CASE("AMOSWAP.W", "[rv32a]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.AMOSWAP_W(Ordering::None, x31, x7, x15);
|
||||
REQUIRE(value == 0x0877AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOSWAP_W(Ordering::AQ, x31, x7, x15);
|
||||
REQUIRE(value == 0x0C77AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOSWAP_W(Ordering::RL, x31, x7, x15);
|
||||
REQUIRE(value == 0x0A77AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOSWAP_W(Ordering::AQRL, x31, x7, x15);
|
||||
REQUIRE(value == 0x0E77AFAF);
|
||||
}
|
||||
|
||||
TEST_CASE("AMOXOR.D", "[rv64a]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.AMOXOR_D(Ordering::None, x31, x7, x15);
|
||||
REQUIRE(value == 0x2077BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOXOR_D(Ordering::AQ, x31, x7, x15);
|
||||
REQUIRE(value == 0x2477BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOXOR_D(Ordering::RL, x31, x7, x15);
|
||||
REQUIRE(value == 0x2277BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOXOR_D(Ordering::AQRL, x31, x7, x15);
|
||||
REQUIRE(value == 0x2677BFAF);
|
||||
}
|
||||
|
||||
TEST_CASE("AMOXOR.W", "[rv32a]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.AMOXOR_W(Ordering::None, x31, x7, x15);
|
||||
REQUIRE(value == 0x2077AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOXOR_W(Ordering::AQ, x31, x7, x15);
|
||||
REQUIRE(value == 0x2477AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOXOR_W(Ordering::RL, x31, x7, x15);
|
||||
REQUIRE(value == 0x2277AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOXOR_W(Ordering::AQRL, x31, x7, x15);
|
||||
REQUIRE(value == 0x2677AFAF);
|
||||
}
|
||||
|
||||
TEST_CASE("LR.D", "[rv64a]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.LR_D(Ordering::None, x31, x15);
|
||||
REQUIRE(value == 0x1007BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.LR_D(Ordering::AQ, x31, x15);
|
||||
REQUIRE(value == 0x1407BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.LR_D(Ordering::RL, x31, x15);
|
||||
REQUIRE(value == 0x1207BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.LR_D(Ordering::AQRL, x31, x15);
|
||||
REQUIRE(value == 0x1607BFAF);
|
||||
}
|
||||
|
||||
TEST_CASE("LR.W", "[rv32a]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.LR_W(Ordering::None, x31, x15);
|
||||
REQUIRE(value == 0x1007AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.LR_W(Ordering::AQ, x31, x15);
|
||||
REQUIRE(value == 0x1407AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.LR_W(Ordering::RL, x31, x15);
|
||||
REQUIRE(value == 0x1207AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.LR_W(Ordering::AQRL, x31, x15);
|
||||
REQUIRE(value == 0x1607AFAF);
|
||||
}
|
||||
|
||||
TEST_CASE("SC.D", "[rv64a]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SC_D(Ordering::None, x31, x7, x15);
|
||||
REQUIRE(value == 0x1877BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SC_D(Ordering::AQ, x31, x7, x15);
|
||||
REQUIRE(value == 0x1C77BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SC_D(Ordering::RL, x31, x7, x15);
|
||||
REQUIRE(value == 0x1A77BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SC_D(Ordering::AQRL, x31, x7, x15);
|
||||
REQUIRE(value == 0x1E77BFAF);
|
||||
}
|
||||
|
||||
TEST_CASE("SC.W", "[rv32a]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SC_W(Ordering::None, x31, x7, x15);
|
||||
REQUIRE(value == 0x1877AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SC_W(Ordering::AQ, x31, x7, x15);
|
||||
REQUIRE(value == 0x1C77AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SC_W(Ordering::RL, x31, x7, x15);
|
||||
REQUIRE(value == 0x1A77AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SC_W(Ordering::AQRL, x31, x7, x15);
|
||||
REQUIRE(value == 0x1E77AFAF);
|
||||
}
|
@ -1,610 +0,0 @@
|
||||
#include <catch/catch.hpp>
|
||||
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include "assembler_test_utils.hpp"
|
||||
|
||||
using namespace biscuit;
|
||||
|
||||
TEST_CASE("ADD.UW", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.ADDUW(x31, x7, x15);
|
||||
REQUIRE(value == 0x08F38FBB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
// Pseudo instruction
|
||||
|
||||
as.ZEXTW(x31, x7);
|
||||
REQUIRE(value == 0x08038FBB);
|
||||
}
|
||||
|
||||
TEST_CASE("ANDN", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.ANDN(x31, x7, x15);
|
||||
REQUIRE(value == 0x40F3FFB3);
|
||||
}
|
||||
|
||||
TEST_CASE("BCLR", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.BCLR(x31, x7, x15);
|
||||
REQUIRE(value == 0x48F39FB3);
|
||||
}
|
||||
|
||||
TEST_CASE("BCLRI", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.BCLRI(x31, x7, 0);
|
||||
REQUIRE(value == 0x48039F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BCLRI(x31, x7, 15);
|
||||
REQUIRE(value == 0x48F39F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BCLRI(x31, x7, 31);
|
||||
REQUIRE(value == 0x49F39F93);
|
||||
}
|
||||
|
||||
TEST_CASE("BCLRI (RV64)", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.BCLRI(x31, x7, 0);
|
||||
REQUIRE(value == 0x48039F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BCLRI(x31, x7, 15);
|
||||
REQUIRE(value == 0x48F39F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BCLRI(x31, x7, 31);
|
||||
REQUIRE(value == 0x49F39F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BCLRI(x31, x7, 63);
|
||||
REQUIRE(value == 0x4BF39F93);
|
||||
}
|
||||
|
||||
TEST_CASE("BEXT", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.BEXT(x31, x7, x15);
|
||||
REQUIRE(value == 0x48F3DFB3);
|
||||
}
|
||||
|
||||
TEST_CASE("BEXTI", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.BEXTI(x31, x7, 0);
|
||||
REQUIRE(value == 0x4803DF93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BEXTI(x31, x7, 15);
|
||||
REQUIRE(value == 0x48F3DF93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BEXTI(x31, x7, 31);
|
||||
REQUIRE(value == 0x49F3DF93);
|
||||
}
|
||||
|
||||
TEST_CASE("BEXTI (RV64)", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.BEXTI(x31, x7, 0);
|
||||
REQUIRE(value == 0x4803DF93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BEXTI(x31, x7, 15);
|
||||
REQUIRE(value == 0x48F3DF93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BEXTI(x31, x7, 31);
|
||||
REQUIRE(value == 0x49F3DF93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BEXTI(x31, x7, 63);
|
||||
REQUIRE(value == 0x4BF3DF93);
|
||||
}
|
||||
|
||||
TEST_CASE("BINV", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.BINV(x31, x7, x15);
|
||||
REQUIRE(value == 0x68F39FB3);
|
||||
}
|
||||
|
||||
TEST_CASE("BINVI", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.BINVI(x31, x7, 0);
|
||||
REQUIRE(value == 0x68039F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BINVI(x31, x7, 15);
|
||||
REQUIRE(value == 0x68F39F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BINVI(x31, x7, 31);
|
||||
REQUIRE(value == 0x69F39F93);
|
||||
}
|
||||
|
||||
TEST_CASE("BINVI (RV64)", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.BINVI(x31, x7, 0);
|
||||
REQUIRE(value == 0x68039F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BINVI(x31, x7, 15);
|
||||
REQUIRE(value == 0x68F39F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BINVI(x31, x7, 31);
|
||||
REQUIRE(value == 0x69F39F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BINVI(x31, x7, 63);
|
||||
REQUIRE(value == 0x6BF39F93);
|
||||
}
|
||||
|
||||
TEST_CASE("BREV8", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.BREV8(x31, x31);
|
||||
REQUIRE(value == 0x687FDF93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BREV8(x1, x2);
|
||||
REQUIRE(value == 0x68715093);
|
||||
}
|
||||
|
||||
TEST_CASE("BSET", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.BSET(x31, x7, x15);
|
||||
REQUIRE(value == 0x28F39FB3);
|
||||
}
|
||||
|
||||
TEST_CASE("BSETI", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.BSETI(x31, x7, 0);
|
||||
REQUIRE(value == 0x28039FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BSETI(x31, x7, 15);
|
||||
REQUIRE(value == 0x28F39FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BSETI(x31, x7, 31);
|
||||
REQUIRE(value == 0x29F39FB3);
|
||||
}
|
||||
|
||||
TEST_CASE("BSETI (RV64)", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.BSETI(x31, x7, 0);
|
||||
REQUIRE(value == 0x28039FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BSETI(x31, x7, 15);
|
||||
REQUIRE(value == 0x28F39FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BSETI(x31, x7, 31);
|
||||
REQUIRE(value == 0x29F39FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.BSETI(x31, x7, 63);
|
||||
REQUIRE(value == 0x2BF39FB3);
|
||||
}
|
||||
|
||||
TEST_CASE("CLMUL", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.CLMUL(x31, x7, x15);
|
||||
REQUIRE(value == 0x0AF39FB3);
|
||||
}
|
||||
|
||||
TEST_CASE("CLMULH", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.CLMULH(x31, x7, x15);
|
||||
REQUIRE(value == 0x0AF3BFB3);
|
||||
}
|
||||
|
||||
TEST_CASE("CLMULR", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.CLMULR(x31, x7, x15);
|
||||
REQUIRE(value == 0x0AF3AFB3);
|
||||
}
|
||||
|
||||
TEST_CASE("CLZ", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.CLZ(x31, x7);
|
||||
REQUIRE(value == 0x60039F93);
|
||||
}
|
||||
|
||||
TEST_CASE("CLZW", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.CLZW(x31, x7);
|
||||
REQUIRE(value == 0x60039F9B);
|
||||
}
|
||||
|
||||
TEST_CASE("CPOP", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.CPOP(x31, x7);
|
||||
REQUIRE(value == 0x60239F93);
|
||||
}
|
||||
|
||||
TEST_CASE("CPOPW", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.CPOPW(x31, x7);
|
||||
REQUIRE(value == 0x60239F9B);
|
||||
}
|
||||
|
||||
TEST_CASE("CTZ", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.CTZ(x31, x7);
|
||||
REQUIRE(value == 0x60139F93);
|
||||
}
|
||||
|
||||
TEST_CASE("CTZW", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.CTZW(x31, x7);
|
||||
REQUIRE(value == 0x60139F9B);
|
||||
}
|
||||
|
||||
TEST_CASE("MAX", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.MAX(x31, x7, x15);
|
||||
REQUIRE(value == 0x0AF3EFB3);
|
||||
}
|
||||
|
||||
TEST_CASE("MAXU", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.MAXU(x31, x7, x15);
|
||||
REQUIRE(value == 0x0AF3FFB3);
|
||||
}
|
||||
|
||||
TEST_CASE("MIN", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.MIN(x31, x7, x15);
|
||||
REQUIRE(value == 0x0AF3CFB3);
|
||||
}
|
||||
|
||||
TEST_CASE("MINU", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.MINU(x31, x7, x15);
|
||||
REQUIRE(value == 0x0AF3DFB3);
|
||||
}
|
||||
|
||||
TEST_CASE("ORC.B", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.ORCB(x31, x7);
|
||||
REQUIRE(value == 0x2873DF93);
|
||||
}
|
||||
|
||||
TEST_CASE("ORN", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.ORN(x31, x7, x15);
|
||||
REQUIRE(value == 0x40F3EFB3);
|
||||
}
|
||||
|
||||
TEST_CASE("PACK", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.PACK(x31, x7, x2);
|
||||
REQUIRE(value == 0x0823CFB3);
|
||||
}
|
||||
|
||||
TEST_CASE("PACKH", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.PACKH(x31, x7, x2);
|
||||
REQUIRE(value == 0x0823FFB3);
|
||||
}
|
||||
|
||||
TEST_CASE("PACKW", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.PACKW(x31, x7, x2);
|
||||
REQUIRE(value == 0x0823CFBB);
|
||||
}
|
||||
|
||||
TEST_CASE("REV8", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.REV8(x31, x7);
|
||||
REQUIRE(value == 0x6983DF93);
|
||||
}
|
||||
|
||||
TEST_CASE("REV8 (RV64)", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.REV8(x31, x7);
|
||||
REQUIRE(value == 0x6B83DF93);
|
||||
}
|
||||
|
||||
TEST_CASE("ROL", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.ROL(x31, x7, x15);
|
||||
REQUIRE(value == 0x60F39FB3);
|
||||
}
|
||||
|
||||
TEST_CASE("ROLW", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.ROLW(x31, x7, x15);
|
||||
REQUIRE(value == 0x60F39FBB);
|
||||
}
|
||||
|
||||
TEST_CASE("ROR", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.ROR(x31, x7, x15);
|
||||
REQUIRE(value == 0x60F3DFB3);
|
||||
}
|
||||
|
||||
TEST_CASE("RORW", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.RORW(x31, x7, x15);
|
||||
REQUIRE(value == 0x60F3DFBB);
|
||||
}
|
||||
|
||||
TEST_CASE("RORI", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.RORI(x31, x7, 0);
|
||||
REQUIRE(value == 0x6003DF93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.RORI(x31, x7, 63);
|
||||
REQUIRE(value == 0x63F3DF93);
|
||||
}
|
||||
|
||||
TEST_CASE("RORIW", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.RORIW(x31, x7, 0);
|
||||
REQUIRE(value == 0x6003DF9B);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.RORIW(x31, x7, 63);
|
||||
REQUIRE(value == 0x63F3DF9B);
|
||||
}
|
||||
|
||||
TEST_CASE("SEXT.B", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SEXTB(x31, x7);
|
||||
REQUIRE(value == 0x60439F93);
|
||||
}
|
||||
|
||||
TEST_CASE("SEXT.H", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SEXTH(x31, x7);
|
||||
REQUIRE(value == 0x60539F93);
|
||||
}
|
||||
|
||||
TEST_CASE("SH1ADD", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SH1ADD(x31, x7, x15);
|
||||
REQUIRE(value == 0x20F3AFB3);
|
||||
}
|
||||
|
||||
TEST_CASE("SH1ADD.UW", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SH1ADDUW(x31, x7, x15);
|
||||
REQUIRE(value == 0x20F3AFBB);
|
||||
}
|
||||
|
||||
TEST_CASE("SH2ADD", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SH2ADD(x31, x7, x15);
|
||||
REQUIRE(value == 0x20F3CFB3);
|
||||
}
|
||||
|
||||
TEST_CASE("SH2ADD.UW", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SH2ADDUW(x31, x7, x15);
|
||||
REQUIRE(value == 0x20F3CFBB);
|
||||
}
|
||||
|
||||
TEST_CASE("SH3ADD", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SH3ADD(x31, x7, x15);
|
||||
REQUIRE(value == 0x20F3EFB3);
|
||||
}
|
||||
|
||||
TEST_CASE("SH3ADD.UW", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SH3ADDUW(x31, x7, x15);
|
||||
REQUIRE(value == 0x20F3EFBB);
|
||||
}
|
||||
|
||||
TEST_CASE("SLLI.UW", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SLLIUW(x31, x7, 0);
|
||||
REQUIRE(value == 0x08039F9B);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SLLIUW(x31, x7, 63);
|
||||
REQUIRE(value == 0x0BF39F9B);
|
||||
}
|
||||
|
||||
TEST_CASE("UNZIP", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.UNZIP(x31, x31);
|
||||
REQUIRE(value == 0x09FFDF93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.UNZIP(x1, x2);
|
||||
REQUIRE(value == 0x09F15093);
|
||||
}
|
||||
|
||||
TEST_CASE("XNOR", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.XNOR(x31, x7, x15);
|
||||
REQUIRE(value == 0x40F3CFB3);
|
||||
}
|
||||
|
||||
TEST_CASE("XPERM4", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.XPERM4(x31, x31, x31);
|
||||
REQUIRE(value == 0x29FFAFB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.XPERM4(x1, x2, x3);
|
||||
REQUIRE(value == 0x283120B3);
|
||||
}
|
||||
|
||||
TEST_CASE("XPERM8", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.XPERM8(x31, x31, x31);
|
||||
REQUIRE(value == 0x29FFCFB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.XPERM8(x1, x2, x3);
|
||||
REQUIRE(value == 0x283140B3);
|
||||
}
|
||||
|
||||
TEST_CASE("ZEXT.H", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.ZEXTH(x31, x7);
|
||||
REQUIRE(value == 0x0803CFB3);
|
||||
}
|
||||
|
||||
TEST_CASE("ZEXT.H (RV64)", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.ZEXTH(x31, x7);
|
||||
REQUIRE(value == 0x0803CFBB);
|
||||
}
|
||||
|
||||
TEST_CASE("ZIP", "[rvb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.ZIP(x31, x31);
|
||||
REQUIRE(value == 0x09EF9F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.ZIP(x1, x2);
|
||||
REQUIRE(value == 0x09E11093);
|
||||
}
|
@ -1,595 +0,0 @@
|
||||
#include <catch/catch.hpp>
|
||||
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include "assembler_test_utils.hpp"
|
||||
|
||||
using namespace biscuit;
|
||||
|
||||
TEST_CASE("C.ADD", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_ADD(x31, x31);
|
||||
REQUIRE(value == 0x9FFE);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_ADD(x15, x8);
|
||||
REQUIRE(value == 0x97A2);
|
||||
}
|
||||
|
||||
TEST_CASE("C.ADDI", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_ADDI(x15, -1);
|
||||
REQUIRE(value == 0x17FD);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_ADDI(x15, -32);
|
||||
REQUIRE(value == 0x1781);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_ADDI(x15, 31);
|
||||
REQUIRE(value == 0x07FD);
|
||||
}
|
||||
|
||||
TEST_CASE("C.ADDIW", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.C_ADDIW(x15, -1);
|
||||
REQUIRE(value == 0x37FD);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_ADDIW(x15, -32);
|
||||
REQUIRE(value == 0x3781);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_ADDIW(x15, 31);
|
||||
REQUIRE(value == 0x27FD);
|
||||
}
|
||||
|
||||
TEST_CASE("C.ADDI4SPN", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_ADDI4SPN(x15, 252);
|
||||
REQUIRE(value == 0x19FC);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_ADDI4SPN(x8, 1020);
|
||||
REQUIRE(value == 0x1FE0);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_ADDI4SPN(x15, 1020);
|
||||
REQUIRE(value == 0x1FFC);
|
||||
}
|
||||
|
||||
TEST_CASE("C.ADDI16SP", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_ADDI16SP(16);
|
||||
REQUIRE(value == 0x6141);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_ADDI16SP(64);
|
||||
REQUIRE(value == 0x6121);
|
||||
}
|
||||
|
||||
TEST_CASE("C.ADDW", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.C_ADDW(x15, x15);
|
||||
REQUIRE(value == 0x9FBD);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_ADDW(x15, x8);
|
||||
REQUIRE(value == 0x9FA1);
|
||||
}
|
||||
|
||||
TEST_CASE("C.AND", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_AND(x15, x15);
|
||||
REQUIRE(value == 0x8FFD);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_AND(x15, x8);
|
||||
REQUIRE(value == 0x8FE1);
|
||||
}
|
||||
|
||||
TEST_CASE("C.ANDI", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_ANDI(x15, 16);
|
||||
REQUIRE(value == 0x8BC1);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_ANDI(x15, 31);
|
||||
REQUIRE(value == 0x8BFD);
|
||||
}
|
||||
|
||||
TEST_CASE("C.EBREAK", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_EBREAK();
|
||||
REQUIRE(value == 0x9002);
|
||||
}
|
||||
|
||||
TEST_CASE("C.FLD", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_FLD(f15, 8, x15);
|
||||
REQUIRE(value == 0x279C);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_FLD(f15, 24, x15);
|
||||
REQUIRE(value == 0x2F9C);
|
||||
}
|
||||
|
||||
TEST_CASE("C.FLDSP", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_FLDSP(f15, 8);
|
||||
REQUIRE(value == 0x27A2);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_FLDSP(f15, 24);
|
||||
REQUIRE(value == 0x27E2);
|
||||
}
|
||||
|
||||
TEST_CASE("C.FLW", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_FLW(f15, 16, x15);
|
||||
REQUIRE(value == 0x6B9C);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_FLW(f15, 24, x15);
|
||||
REQUIRE(value == 0x6F9C);
|
||||
}
|
||||
|
||||
TEST_CASE("C.FLWSP", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_FLWSP(f15, 16);
|
||||
REQUIRE(value == 0x67C2);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_FLWSP(f15, 24);
|
||||
REQUIRE(value == 0x67E2);
|
||||
}
|
||||
|
||||
TEST_CASE("C.FSD", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_FSD(f15, 8, x15);
|
||||
REQUIRE(value == 0xA79C);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_FSD(f15, 24, x15);
|
||||
REQUIRE(value == 0xAF9C);
|
||||
}
|
||||
|
||||
TEST_CASE("C.FSDSP", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_FSDSP(f15, 8);
|
||||
REQUIRE(value == 0xA43E);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_FSDSP(f15, 24);
|
||||
REQUIRE(value == 0xAC3E);
|
||||
}
|
||||
|
||||
TEST_CASE("C.FSW", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_FSW(f15, 16, x15);
|
||||
REQUIRE(value == 0xEB9C);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_FSW(f15, 24, x15);
|
||||
REQUIRE(value == 0xEF9C);
|
||||
}
|
||||
|
||||
TEST_CASE("C.FSWSP", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_FSWSP(f15, 16);
|
||||
REQUIRE(value == 0xE83E);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_FSWSP(f15, 24);
|
||||
REQUIRE(value == 0xEC3E);
|
||||
}
|
||||
|
||||
TEST_CASE("C.JALR", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_JALR(x31);
|
||||
REQUIRE(value == 0x9F82);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_JALR(x15);
|
||||
REQUIRE(value == 0x9782);
|
||||
}
|
||||
|
||||
TEST_CASE("C.JR", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_JR(x31);
|
||||
REQUIRE(value == 0x8F82);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_JR(x15);
|
||||
REQUIRE(value == 0x8782);
|
||||
}
|
||||
|
||||
TEST_CASE("C.LD", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.C_LD(x15, 8, x15);
|
||||
REQUIRE(value == 0x679C);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_LD(x15, 24, x15);
|
||||
REQUIRE(value == 0x6F9C);
|
||||
}
|
||||
|
||||
TEST_CASE("C.LDSP", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.C_LDSP(x15, 8);
|
||||
REQUIRE(value == 0x67A2);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_LDSP(x15, 24);
|
||||
REQUIRE(value == 0x67E2);
|
||||
}
|
||||
|
||||
TEST_CASE("C.LI", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_LI(x15, -1);
|
||||
REQUIRE(value == 0x57FD);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_LI(x15, -32);
|
||||
REQUIRE(value == 0x5781);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_LI(x15, 31);
|
||||
REQUIRE(value == 0x47FD);
|
||||
}
|
||||
|
||||
TEST_CASE("C.LQ", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler128(value);
|
||||
|
||||
as.C_LQ(x15, 16, x15);
|
||||
REQUIRE(value == 0x2B9C);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_LQ(x15, 256, x15);
|
||||
REQUIRE(value == 0x279C);
|
||||
}
|
||||
|
||||
TEST_CASE("C.LQSP", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler128(value);
|
||||
|
||||
as.C_LQSP(x15, 16);
|
||||
REQUIRE(value == 0x27C2);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_LQSP(x15, 256);
|
||||
REQUIRE(value == 0x2792);
|
||||
}
|
||||
|
||||
TEST_CASE("C.LUI", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_LUI(x15, 0x3F000);
|
||||
REQUIRE(value == 0x77FD);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_LUI(x15, 0x0F000);
|
||||
REQUIRE(value == 0x67BD);
|
||||
}
|
||||
|
||||
TEST_CASE("C.LW", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_LW(x15, 16, x15);
|
||||
REQUIRE(value == 0x4B9C);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_LW(x15, 24, x15);
|
||||
REQUIRE(value == 0x4F9C);
|
||||
}
|
||||
|
||||
TEST_CASE("C.LWSP", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_LWSP(x15, 16);
|
||||
REQUIRE(value == 0x47C2);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_LWSP(x15, 24);
|
||||
REQUIRE(value == 0x47E2);
|
||||
}
|
||||
|
||||
TEST_CASE("C.MV", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_MV(x31, x31);
|
||||
REQUIRE(value == 0x8FFE);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_MV(x15, x8);
|
||||
REQUIRE(value == 0x87A2);
|
||||
}
|
||||
|
||||
TEST_CASE("C.NOP", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_NOP();
|
||||
REQUIRE(value == 0x0001);
|
||||
}
|
||||
|
||||
TEST_CASE("C.OR", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_OR(x15, x15);
|
||||
REQUIRE(value == 0x8FDD);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_OR(x15, x8);
|
||||
REQUIRE(value == 0x8FC1);
|
||||
}
|
||||
|
||||
TEST_CASE("C.SD", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.C_SD(x15, 8, x15);
|
||||
REQUIRE(value == 0xE79C);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_SD(x15, 24, x15);
|
||||
REQUIRE(value == 0xEF9C);
|
||||
}
|
||||
|
||||
TEST_CASE("C.SDSP", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.C_SDSP(x15, 8);
|
||||
REQUIRE(value == 0xE43E);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_SDSP(x15, 24);
|
||||
REQUIRE(value == 0xEC3E);
|
||||
}
|
||||
|
||||
TEST_CASE("C.SLLI", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_SLLI(x15, 15);
|
||||
REQUIRE(value == 0x07BE);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_SLLI(x15, 31);
|
||||
REQUIRE(value == 0x07FE);
|
||||
}
|
||||
|
||||
TEST_CASE("C.SLLI (RV128)", "[rv128c]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler128(value);
|
||||
|
||||
as.C_SLLI(x15, 64);
|
||||
REQUIRE(value == 0x0782);
|
||||
}
|
||||
|
||||
TEST_CASE("C.SQ", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler128(value);
|
||||
|
||||
as.C_SQ(x15, 16, x15);
|
||||
REQUIRE(value == 0xAB9C);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_SQ(x15, 256, x15);
|
||||
REQUIRE(value == 0xA79C);
|
||||
}
|
||||
|
||||
TEST_CASE("C.SQSP", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler128(value);
|
||||
|
||||
as.C_SQSP(x15, 16);
|
||||
REQUIRE(value == 0xA83E);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_SQSP(x15, 256);
|
||||
REQUIRE(value == 0xA23E);
|
||||
}
|
||||
|
||||
TEST_CASE("C.SRAI", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_SRAI(x15, 16);
|
||||
REQUIRE(value == 0x87C1);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_SRAI(x15, 31);
|
||||
REQUIRE(value == 0x87FD);
|
||||
}
|
||||
|
||||
TEST_CASE("C.SRAI (RV128)", "[rv128c]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler128(value);
|
||||
|
||||
as.C_SRAI(x15, 64);
|
||||
REQUIRE(value == 0x8781);
|
||||
}
|
||||
|
||||
TEST_CASE("C.SRLI", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_SRLI(x15, 16);
|
||||
REQUIRE(value == 0x83C1);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_SRLI(x15, 31);
|
||||
REQUIRE(value == 0x83FD);
|
||||
}
|
||||
|
||||
TEST_CASE("C.SRLI (RV128)", "[rv128c]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler128(value);
|
||||
|
||||
as.C_SRLI(x15, 64);
|
||||
REQUIRE(value == 0x8381);
|
||||
}
|
||||
|
||||
TEST_CASE("C.SUB", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_SUB(x15, x15);
|
||||
REQUIRE(value == 0x8F9D);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_SUB(x15, x8);
|
||||
REQUIRE(value == 0x8F81);
|
||||
}
|
||||
|
||||
TEST_CASE("C.SUBW", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.C_SUBW(x15, x15);
|
||||
REQUIRE(value == 0x9F9D);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_SUBW(x15, x8);
|
||||
REQUIRE(value == 0x9F81);
|
||||
}
|
||||
|
||||
TEST_CASE("C.SW", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_SW(x15, 16, x15);
|
||||
REQUIRE(value == 0xCB9C);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_SW(x15, 24, x15);
|
||||
REQUIRE(value == 0xCF9C);
|
||||
}
|
||||
|
||||
TEST_CASE("C.SWSP", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_SWSP(x15, 16);
|
||||
REQUIRE(value == 0xC83E);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_SWSP(x15, 24);
|
||||
REQUIRE(value == 0xCC3E);
|
||||
}
|
||||
|
||||
TEST_CASE("C.UNDEF", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_UNDEF();
|
||||
REQUIRE(value == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("C.XOR", "[rvc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.C_XOR(x15, x15);
|
||||
REQUIRE(value == 0x8FBD);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_XOR(x15, x8);
|
||||
REQUIRE(value == 0x8FA1);
|
||||
}
|
@ -1,528 +0,0 @@
|
||||
#include <catch/catch.hpp>
|
||||
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include "assembler_test_utils.hpp"
|
||||
|
||||
using namespace biscuit;
|
||||
|
||||
TEST_CASE("FADD.D", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FADD_D(f31, f7, f26, RMode::RNE);
|
||||
REQUIRE(value == 0x03A38FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FADD_D(f31, f7, f26, RMode::RMM);
|
||||
REQUIRE(value == 0x03A3CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FADD_D(f31, f7, f26, RMode::DYN);
|
||||
REQUIRE(value == 0x03A3FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCLASS.D", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FCLASS_D(x31, f7);
|
||||
REQUIRE(value == 0xE2039FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCLASS_D(x7, f31);
|
||||
REQUIRE(value == 0xE20F93D3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVT.D.S", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FCVT_D_S(f31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0x42038FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_D_S(f31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0x4203CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_D_S(f31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0x4203FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVT.D.W", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FCVT_D_W(f31, x7, RMode::RNE);
|
||||
REQUIRE(value == 0xD2038FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_D_W(f31, x7, RMode::RMM);
|
||||
REQUIRE(value == 0xD203CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_D_W(f31, x7, RMode::DYN);
|
||||
REQUIRE(value == 0xD203FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVT.D.WU", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FCVT_D_WU(f31, x7, RMode::RNE);
|
||||
REQUIRE(value == 0xD2138FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_D_WU(f31, x7, RMode::RMM);
|
||||
REQUIRE(value == 0xD213CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_D_WU(f31, x7, RMode::DYN);
|
||||
REQUIRE(value == 0xD213FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVT.L.D", "[rv64d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FCVT_L_D(x31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0xC2238FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_L_D(x31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0xC223CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_L_D(x31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0xC223FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVT.LU.D", "[rv64d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FCVT_LU_D(x31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0xC2338FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_LU_D(x31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0xC233CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_LU_D(x31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0xC233FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVT.D.L", "[rv64d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FCVT_D_L(f31, x7, RMode::RNE);
|
||||
REQUIRE(value == 0xD2238FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_D_L(f31, x7, RMode::RMM);
|
||||
REQUIRE(value == 0xD223CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_D_L(f31, x7, RMode::DYN);
|
||||
REQUIRE(value == 0xD223FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVT.D.LU", "[rv64d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FCVT_D_LU(f31, x7, RMode::RNE);
|
||||
REQUIRE(value == 0xD2338FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_D_LU(f31, x7, RMode::RMM);
|
||||
REQUIRE(value == 0xD233CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_D_LU(f31, x7, RMode::DYN);
|
||||
REQUIRE(value == 0xD233FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVT.W.D", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FCVT_W_D(x31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0xC2038FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_W_D(x31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0xC203CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_W_D(x31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0xC203FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVT.WU.D", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FCVT_WU_D(x31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0xC2138FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_WU_D(x31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0xC213CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_WU_D(x31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0xC213FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVT.S.D", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FCVT_S_D(f31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0x40138FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_S_D(f31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0x4013CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_S_D(f31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0x4013FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FDIV.D", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FDIV_D(f31, f7, f26, RMode::RNE);
|
||||
REQUIRE(value == 0x1BA38FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FDIV_D(f31, f7, f26, RMode::RMM);
|
||||
REQUIRE(value == 0x1BA3CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FDIV_D(f31, f7, f26, RMode::DYN);
|
||||
REQUIRE(value == 0x1BA3FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FEQ.D", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FEQ_D(x31, f7, f26);
|
||||
REQUIRE(value == 0xA3A3AFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FEQ_D(x31, f26, f7);
|
||||
REQUIRE(value == 0xA27D2FD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FLE.D", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FLE_D(x31, f7, f26);
|
||||
REQUIRE(value == 0xA3A38FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FLE_D(x31, f26, f7);
|
||||
REQUIRE(value == 0xA27D0FD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FLT.D", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FLT_D(x31, f7, f26);
|
||||
REQUIRE(value == 0xA3A39FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FLT_D(x31, f26, f7);
|
||||
REQUIRE(value == 0xA27D1FD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FLD", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FLD(f15, 1024, x31);
|
||||
REQUIRE(value == 0x400FB787);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FLD(f15, 1536, x31);
|
||||
REQUIRE(value == 0x600FB787);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FLD(f15, -1, x31);
|
||||
REQUIRE(value == 0xFFFFB787);
|
||||
}
|
||||
|
||||
TEST_CASE("FMADD.D", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FMADD_D(f15, f31, f7, f26, RMode::RNE);
|
||||
REQUIRE(value == 0xD27F87C3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FMADD_D(f15, f31, f7, f26, RMode::RMM);
|
||||
REQUIRE(value == 0xD27FC7C3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FMADD_D(f15, f31, f7, f26, RMode::DYN);
|
||||
REQUIRE(value == 0xD27FF7C3);
|
||||
}
|
||||
|
||||
TEST_CASE("FMAX.D", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FMAX_D(f31, f7, f26);
|
||||
REQUIRE(value == 0x2BA39FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FMAX_D(f31, f31, f31);
|
||||
REQUIRE(value == 0x2BFF9FD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FMIN.D", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FMIN_D(f31, f7, f26);
|
||||
REQUIRE(value == 0x2BA38FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FMIN_D(f31, f31, f31);
|
||||
REQUIRE(value == 0x2BFF8FD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FMSUB.D", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FMSUB_D(f15, f31, f7, f26, RMode::RNE);
|
||||
REQUIRE(value == 0xD27F87C7);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FMSUB_D(f15, f31, f7, f26, RMode::RMM);
|
||||
REQUIRE(value == 0xD27FC7C7);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FMSUB_D(f15, f31, f7, f26, RMode::DYN);
|
||||
REQUIRE(value == 0xD27FF7C7);
|
||||
}
|
||||
|
||||
TEST_CASE("FMUL.D", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FMUL_D(f31, f7, f26, RMode::RNE);
|
||||
REQUIRE(value == 0x13A38FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FMUL_D(f31, f7, f26, RMode::RMM);
|
||||
REQUIRE(value == 0x13A3CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FMUL_D(f31, f7, f26, RMode::DYN);
|
||||
REQUIRE(value == 0x13A3FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FMV.D.X", "[rv64d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FMV_D_X(f31, x7);
|
||||
REQUIRE(value == 0xF2038FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FMV_D_X(f7, x31);
|
||||
REQUIRE(value == 0xF20F83D3);
|
||||
}
|
||||
|
||||
TEST_CASE("FMV.X.D", "[rv64d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FMV_X_D(x31, f7);
|
||||
REQUIRE(value == 0xE2038FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FMV_X_D(x7, f31);
|
||||
REQUIRE(value == 0xE20F83D3);
|
||||
}
|
||||
|
||||
TEST_CASE("FNMADD.D", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FNMADD_D(f15, f31, f7, f26, RMode::RNE);
|
||||
REQUIRE(value == 0xD27F87CF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FNMADD_D(f15, f31, f7, f26, RMode::RMM);
|
||||
REQUIRE(value == 0xD27FC7CF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FNMADD_D(f15, f31, f7, f26, RMode::DYN);
|
||||
REQUIRE(value == 0xD27FF7CF);
|
||||
}
|
||||
|
||||
TEST_CASE("FNMSUB.D", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FNMSUB_D(f15, f31, f7, f26, RMode::RNE);
|
||||
REQUIRE(value == 0xD27F87CB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FNMSUB_D(f15, f31, f7, f26, RMode::RMM);
|
||||
REQUIRE(value == 0xD27FC7CB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FNMSUB_D(f15, f31, f7, f26, RMode::DYN);
|
||||
REQUIRE(value == 0xD27FF7CB);
|
||||
}
|
||||
|
||||
TEST_CASE("FSGNJ.D", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FSGNJ_D(f31, f7, f26);
|
||||
REQUIRE(value == 0x23A38FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FSGNJ_D(f31, f31, f31);
|
||||
REQUIRE(value == 0x23FF8FD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FSGNJN.D", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FSGNJN_D(f31, f7, f26);
|
||||
REQUIRE(value == 0x23A39FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FSGNJN_D(f31, f31, f31);
|
||||
REQUIRE(value == 0x23FF9FD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FSGNJX.D", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FSGNJX_D(f31, f7, f26);
|
||||
REQUIRE(value == 0x23A3AFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FSGNJX_D(f31, f31, f31);
|
||||
REQUIRE(value == 0x23FFAFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FSQRT.D", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FSQRT_D(f31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0x5A038FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FSQRT_D(f31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0x5A03CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FSQRT_D(f31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0x5A03FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FSUB.D", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FSUB_D(f31, f7, f26, RMode::RNE);
|
||||
REQUIRE(value == 0x0BA38FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FSUB_D(f31, f7, f26, RMode::RMM);
|
||||
REQUIRE(value == 0x0BA3CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FSUB_D(f31, f7, f26, RMode::DYN);
|
||||
REQUIRE(value == 0x0BA3FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FSD", "[rv32d]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FSD(f31, 1024, x15);
|
||||
REQUIRE(value == 0x41F7B027);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FSD(f31, 1536, x15);
|
||||
REQUIRE(value == 0x61F7B027);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FSD(f31, -1, x15);
|
||||
REQUIRE(value == 0xFFF7BFA7);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,384 +0,0 @@
|
||||
#include <catch/catch.hpp>
|
||||
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include "assembler_test_utils.hpp"
|
||||
|
||||
using namespace biscuit;
|
||||
|
||||
TEST_CASE("AES32DSI", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.AES32DSI(x31, x31, x31, 0b11);
|
||||
REQUIRE(value == 0xEBFF8FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AES32DSI(x1, x2, x3, 0b10);
|
||||
REQUIRE(value == 0xAA3100B3);
|
||||
}
|
||||
|
||||
TEST_CASE("AES32DSMI", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.AES32DSMI(x31, x31, x31, 0b11);
|
||||
REQUIRE(value == 0xEFFF8FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AES32DSMI(x1, x2, x3, 0b10);
|
||||
REQUIRE(value == 0xAE3100B3);
|
||||
}
|
||||
|
||||
TEST_CASE("AES32ESI", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.AES32ESI(x31, x31, x31, 0b11);
|
||||
REQUIRE(value == 0xE3FF8FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AES32ESI(x1, x2, x3, 0b10);
|
||||
REQUIRE(value == 0xA23100B3);
|
||||
}
|
||||
|
||||
TEST_CASE("AES32ESMI", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.AES32ESMI(x31, x31, x31, 0b11);
|
||||
REQUIRE(value == 0xE7FF8FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AES32ESMI(x1, x2, x3, 0b10);
|
||||
REQUIRE(value == 0xA63100B3);
|
||||
}
|
||||
|
||||
TEST_CASE("AES64DS", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.AES64DS(x31, x31, x31);
|
||||
REQUIRE(value == 0x3BFF8FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AES64DS(x1, x2, x3);
|
||||
REQUIRE(value == 0x3A3100B3);
|
||||
}
|
||||
|
||||
TEST_CASE("AES64DSM", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.AES64DSM(x31, x31, x31);
|
||||
REQUIRE(value == 0x3FFF8FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AES64DSM(x1, x2, x3);
|
||||
REQUIRE(value == 0x3E3100B3);
|
||||
}
|
||||
|
||||
TEST_CASE("AES64ES", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.AES64ES(x31, x31, x31);
|
||||
REQUIRE(value == 0x33FF8FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AES64ES(x1, x2, x3);
|
||||
REQUIRE(value == 0x323100B3);
|
||||
}
|
||||
|
||||
TEST_CASE("AES64ESM", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.AES64ESM(x31, x31, x31);
|
||||
REQUIRE(value == 0x37FF8FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AES64ESM(x1, x2, x3);
|
||||
REQUIRE(value == 0x363100B3);
|
||||
}
|
||||
|
||||
TEST_CASE("AES64IM", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.AES64IM(x31, x31);
|
||||
REQUIRE(value == 0x300F9F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AES64IM(x1, x2);
|
||||
REQUIRE(value == 0x30011093);
|
||||
}
|
||||
|
||||
TEST_CASE("AES64KS1I", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.AES64KS1I(x31, x31, 0xA);
|
||||
REQUIRE(value == 0x31AF9F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AES64KS1I(x1, x2, 0x5);
|
||||
REQUIRE(value == 0x31511093);
|
||||
}
|
||||
|
||||
TEST_CASE("AES64KS2", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.AES64KS2(x31, x31, x31);
|
||||
REQUIRE(value == 0x7FFF8FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AES64KS2(x1, x2, x3);
|
||||
REQUIRE(value == 0x7E3100B3);
|
||||
}
|
||||
|
||||
TEST_CASE("SHA256SIG0", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SHA256SIG0(x31, x31);
|
||||
REQUIRE(value == 0x102F9F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SHA256SIG0(x1, x2);
|
||||
REQUIRE(value == 0x10211093);
|
||||
}
|
||||
|
||||
TEST_CASE("SHA256SIG1", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SHA256SIG1(x31, x31);
|
||||
REQUIRE(value == 0x103F9F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SHA256SIG1(x1, x2);
|
||||
REQUIRE(value == 0x10311093);
|
||||
}
|
||||
|
||||
TEST_CASE("SHA256SUM0", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SHA256SUM0(x31, x31);
|
||||
REQUIRE(value == 0x100F9F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SHA256SUM0(x1, x2);
|
||||
REQUIRE(value == 0x10011093);
|
||||
}
|
||||
|
||||
TEST_CASE("SHA256SUM1", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SHA256SUM1(x31, x31);
|
||||
REQUIRE(value == 0x101F9F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SHA256SUM1(x1, x2);
|
||||
REQUIRE(value == 0x10111093);
|
||||
}
|
||||
|
||||
TEST_CASE("SHA512SIG0", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SHA512SIG0(x31, x31);
|
||||
REQUIRE(value == 0x106F9F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SHA512SIG0(x1, x2);
|
||||
REQUIRE(value == 0x10611093);
|
||||
}
|
||||
|
||||
TEST_CASE("SHA512SIG0H", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SHA512SIG0H(x31, x31, x31);
|
||||
REQUIRE(value == 0x5DFF8FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SHA512SIG0H(x1, x2, x3);
|
||||
REQUIRE(value == 0x5C3100B3);
|
||||
}
|
||||
|
||||
TEST_CASE("SHA512SIG0L", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SHA512SIG0L(x31, x31, x31);
|
||||
REQUIRE(value == 0x55FF8FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SHA512SIG0L(x1, x2, x3);
|
||||
REQUIRE(value == 0x543100B3);
|
||||
}
|
||||
|
||||
TEST_CASE("SHA512SIG1", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SHA512SIG1(x31, x31);
|
||||
REQUIRE(value == 0x107F9F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SHA512SIG1(x1, x2);
|
||||
REQUIRE(value == 0x10711093);
|
||||
}
|
||||
|
||||
TEST_CASE("SHA512SIG1H", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SHA512SIG1H(x31, x31, x31);
|
||||
REQUIRE(value == 0x5FFF8FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SHA512SIG1H(x1, x2, x3);
|
||||
REQUIRE(value == 0x5E3100B3);
|
||||
}
|
||||
|
||||
TEST_CASE("SHA512SIG1L", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SHA512SIG1L(x31, x31, x31);
|
||||
REQUIRE(value == 0x57FF8FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SHA512SIG1L(x1, x2, x3);
|
||||
REQUIRE(value == 0x563100B3);
|
||||
}
|
||||
|
||||
TEST_CASE("SHA512SUM0", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SHA512SUM0(x31, x31);
|
||||
REQUIRE(value == 0x104F9F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SHA512SUM0(x1, x2);
|
||||
REQUIRE(value == 0x10411093);
|
||||
}
|
||||
|
||||
TEST_CASE("SHA512SUM0R", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SHA512SUM0R(x31, x31, x31);
|
||||
REQUIRE(value == 0x51FF8FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SHA512SUM0R(x1, x2, x3);
|
||||
REQUIRE(value == 0x503100B3);
|
||||
}
|
||||
|
||||
TEST_CASE("SHA512SUM1", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SHA512SUM1(x31, x31);
|
||||
REQUIRE(value == 0x105F9F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SHA512SUM1(x1, x2);
|
||||
REQUIRE(value == 0x10511093);
|
||||
}
|
||||
|
||||
TEST_CASE("SHA512SUM1R", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.SHA512SUM1R(x31, x31, x31);
|
||||
REQUIRE(value == 0x53FF8FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SHA512SUM1R(x1, x2, x3);
|
||||
REQUIRE(value == 0x523100B3);
|
||||
}
|
||||
|
||||
TEST_CASE("SM3P0", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SM3P0(x31, x31);
|
||||
REQUIRE(value == 0x108F9F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SM3P0(x1, x2);
|
||||
REQUIRE(value == 0x10811093);
|
||||
}
|
||||
|
||||
TEST_CASE("SM3P1", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SM3P1(x31, x31);
|
||||
REQUIRE(value == 0x109F9F93);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SM3P1(x1, x2);
|
||||
REQUIRE(value == 0x10911093);
|
||||
}
|
||||
|
||||
TEST_CASE("SM4ED", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SM4ED(x31, x31, x31, 0b11);
|
||||
REQUIRE(value == 0xF1FF8FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SM4ED(x1, x2, x3, 0b10);
|
||||
REQUIRE(value == 0xB03100B3);
|
||||
}
|
||||
|
||||
TEST_CASE("SM4KS", "[rvk]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.SM4KS(x31, x31, x31, 0b11);
|
||||
REQUIRE(value == 0xF5FF8FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.SM4KS(x1, x2, x3, 0b10);
|
||||
REQUIRE(value == 0xB43100B3);
|
||||
}
|
@ -1,241 +0,0 @@
|
||||
#include <catch/catch.hpp>
|
||||
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include "assembler_test_utils.hpp"
|
||||
|
||||
using namespace biscuit;
|
||||
|
||||
TEST_CASE("DIV", "[rv32m]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.DIV(x31, x15, x20);
|
||||
REQUIRE(value == 0x0347CFB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.DIV(x31, x20, x15);
|
||||
REQUIRE(value == 0x02FA4FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.DIV(x20, x31, x15);
|
||||
REQUIRE(value == 0x02FFCA33);
|
||||
}
|
||||
|
||||
TEST_CASE("DIVW", "[rv64m]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.DIVW(x31, x15, x20);
|
||||
REQUIRE(value == 0x0347CFBB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.DIVW(x31, x20, x15);
|
||||
REQUIRE(value == 0x02FA4FBB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.DIVW(x20, x31, x15);
|
||||
REQUIRE(value == 0x02FFCA3B);
|
||||
}
|
||||
|
||||
TEST_CASE("DIVU", "[rv32m]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.DIVU(x31, x15, x20);
|
||||
REQUIRE(value == 0x0347DFB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.DIVU(x31, x20, x15);
|
||||
REQUIRE(value == 0x02FA5FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.DIVU(x20, x31, x15);
|
||||
REQUIRE(value == 0x02FFDA33);
|
||||
}
|
||||
|
||||
TEST_CASE("DIVUW", "[rv64m]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.DIVUW(x31, x15, x20);
|
||||
REQUIRE(value == 0x0347DFBB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.DIVUW(x31, x20, x15);
|
||||
REQUIRE(value == 0x02FA5FBB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.DIVUW(x20, x31, x15);
|
||||
REQUIRE(value == 0x02FFDA3B);
|
||||
}
|
||||
|
||||
TEST_CASE("MUL", "[rv32m]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.MUL(x31, x15, x20);
|
||||
REQUIRE(value == 0x03478FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.MUL(x31, x20, x15);
|
||||
REQUIRE(value == 0x02FA0FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.MUL(x20, x31, x15);
|
||||
REQUIRE(value == 0x02FF8A33);
|
||||
}
|
||||
|
||||
TEST_CASE("MULH", "[rv32m]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.MULH(x31, x15, x20);
|
||||
REQUIRE(value == 0x03479FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.MULH(x31, x20, x15);
|
||||
REQUIRE(value == 0x02FA1FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.MULH(x20, x31, x15);
|
||||
REQUIRE(value == 0x02FF9A33);
|
||||
}
|
||||
|
||||
TEST_CASE("MULW", "[rv64m]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.MULW(x31, x15, x20);
|
||||
REQUIRE(value == 0x03478FBB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.MULW(x31, x20, x15);
|
||||
REQUIRE(value == 0x02FA0FBB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.MULW(x20, x31, x15);
|
||||
REQUIRE(value == 0x02FF8A3B);
|
||||
}
|
||||
|
||||
TEST_CASE("MULHSU", "[rv32m]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.MULHSU(x31, x15, x20);
|
||||
REQUIRE(value == 0x0347AFB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.MULHSU(x31, x20, x15);
|
||||
REQUIRE(value == 0x02FA2FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.MULHSU(x20, x31, x15);
|
||||
REQUIRE(value == 0x02FFAA33);
|
||||
}
|
||||
|
||||
TEST_CASE("MULHU", "[rv32m]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.MULHU(x31, x15, x20);
|
||||
REQUIRE(value == 0x0347BFB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.MULHU(x31, x20, x15);
|
||||
REQUIRE(value == 0x02FA3FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.MULHU(x20, x31, x15);
|
||||
REQUIRE(value == 0x02FFBA33);
|
||||
}
|
||||
|
||||
TEST_CASE("REM", "[rv32m]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.REM(x31, x15, x20);
|
||||
REQUIRE(value == 0x0347EFB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.REM(x31, x20, x15);
|
||||
REQUIRE(value == 0x02FA6FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.REM(x20, x31, x15);
|
||||
REQUIRE(value == 0x02FFEA33);
|
||||
}
|
||||
|
||||
TEST_CASE("REMW", "[rv64m]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.REMW(x31, x15, x20);
|
||||
REQUIRE(value == 0x0347EFBB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.REMW(x31, x20, x15);
|
||||
REQUIRE(value == 0x02FA6FBB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.REMW(x20, x31, x15);
|
||||
REQUIRE(value == 0x02FFEA3B);
|
||||
}
|
||||
|
||||
TEST_CASE("REMU", "[rv32m]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.REMU(x31, x15, x20);
|
||||
REQUIRE(value == 0x0347FFB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.REMU(x31, x20, x15);
|
||||
REQUIRE(value == 0x02FA7FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.REMU(x20, x31, x15);
|
||||
REQUIRE(value == 0x02FFFA33);
|
||||
}
|
||||
|
||||
TEST_CASE("REMUW", "[rv64m]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.REMUW(x31, x15, x20);
|
||||
REQUIRE(value == 0x0347FFBB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.REMUW(x31, x20, x15);
|
||||
REQUIRE(value == 0x02FA7FBB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.REMUW(x20, x31, x15);
|
||||
REQUIRE(value == 0x02FFFA3B);
|
||||
}
|
@ -1,538 +0,0 @@
|
||||
#include <catch/catch.hpp>
|
||||
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include "assembler_test_utils.hpp"
|
||||
|
||||
using namespace biscuit;
|
||||
|
||||
TEST_CASE("FADD.Q", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FADD_Q(f31, f7, f26, RMode::RNE);
|
||||
REQUIRE(value == 0x07A38FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FADD_Q(f31, f7, f26, RMode::RMM);
|
||||
REQUIRE(value == 0x07A3CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FADD_Q(f31, f7, f26, RMode::DYN);
|
||||
REQUIRE(value == 0x07A3FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCLASS.Q", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FCLASS_Q(x31, f7);
|
||||
REQUIRE(value == 0xE6039FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCLASS_Q(x7, f31);
|
||||
REQUIRE(value == 0xE60F93D3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVT.Q.D", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FCVT_Q_D(f31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0x46138FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_Q_D(f31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0x4613CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_Q_D(f31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0x4613FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVT.Q.S", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FCVT_Q_S(f31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0x46038FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_Q_S(f31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0x4603CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_Q_S(f31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0x4603FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVT.Q.W", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FCVT_Q_W(f31, x7, RMode::RNE);
|
||||
REQUIRE(value == 0xD6038FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_Q_W(f31, x7, RMode::RMM);
|
||||
REQUIRE(value == 0xD603CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_Q_W(f31, x7, RMode::DYN);
|
||||
REQUIRE(value == 0xD603FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVT.Q.WU", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FCVT_Q_WU(f31, x7, RMode::RNE);
|
||||
REQUIRE(value == 0xD6138FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_Q_WU(f31, x7, RMode::RMM);
|
||||
REQUIRE(value == 0xD613CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_Q_WU(f31, x7, RMode::DYN);
|
||||
REQUIRE(value == 0xD613FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVT.L.Q", "[rv64q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FCVT_L_Q(x31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0xC6238FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_L_Q(x31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0xC623CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_L_Q(x31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0xC623FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVT.LU.Q", "[rv64q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FCVT_LU_Q(x31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0xC6338FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_LU_Q(x31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0xC633CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_LU_Q(x31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0xC633FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVT.Q.L", "[rv64q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FCVT_Q_L(f31, x7, RMode::RNE);
|
||||
REQUIRE(value == 0xD6238FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_Q_L(f31, x7, RMode::RMM);
|
||||
REQUIRE(value == 0xD623CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_Q_L(f31, x7, RMode::DYN);
|
||||
REQUIRE(value == 0xD623FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVT.Q.LU", "[rv64q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FCVT_Q_LU(f31, x7, RMode::RNE);
|
||||
REQUIRE(value == 0xD6338FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_Q_LU(f31, x7, RMode::RMM);
|
||||
REQUIRE(value == 0xD633CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_Q_LU(f31, x7, RMode::DYN);
|
||||
REQUIRE(value == 0xD633FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVT.W.Q", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FCVT_W_Q(x31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0xC6038FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_W_Q(x31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0xC603CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_W_Q(x31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0xC603FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVT.WU.Q", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FCVT_WU_Q(x31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0xC6138FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_WU_Q(x31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0xC613CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_WU_Q(x31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0xC613FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVT.D.Q", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FCVT_D_Q(f31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0x42338FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_D_Q(f31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0x4233CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_D_Q(f31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0x4233FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVT.S.Q", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FCVT_S_Q(f31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0x40338FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_S_Q(f31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0x4033CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FCVT_S_Q(f31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0x4033FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FDIV.Q", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FDIV_Q(f31, f7, f26, RMode::RNE);
|
||||
REQUIRE(value == 0x1FA38FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FDIV_Q(f31, f7, f26, RMode::RMM);
|
||||
REQUIRE(value == 0x1FA3CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FDIV_Q(f31, f7, f26, RMode::DYN);
|
||||
REQUIRE(value == 0x1FA3FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FEQ.Q", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FEQ_Q(x31, f7, f26);
|
||||
REQUIRE(value == 0xA7A3AFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FEQ_Q(x31, f26, f7);
|
||||
REQUIRE(value == 0xA67D2FD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FLE.Q", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FLE_Q(x31, f7, f26);
|
||||
REQUIRE(value == 0xA7A38FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FLE_Q(x31, f26, f7);
|
||||
REQUIRE(value == 0xA67D0FD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FLT.Q", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FLT_Q(x31, f7, f26);
|
||||
REQUIRE(value == 0xA7A39FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FLT_Q(x31, f26, f7);
|
||||
REQUIRE(value == 0xA67D1FD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FLQ", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FLQ(f15, 1024, x31);
|
||||
REQUIRE(value == 0x400FC787);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FLQ(f15, 1536, x31);
|
||||
REQUIRE(value == 0x600FC787);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FLQ(f15, -1, x31);
|
||||
REQUIRE(value == 0xFFFFC787);
|
||||
}
|
||||
|
||||
TEST_CASE("FMADD.Q", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FMADD_Q(f15, f31, f7, f26, RMode::RNE);
|
||||
REQUIRE(value == 0xD67F87C3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FMADD_Q(f15, f31, f7, f26, RMode::RMM);
|
||||
REQUIRE(value == 0xD67FC7C3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FMADD_Q(f15, f31, f7, f26, RMode::DYN);
|
||||
REQUIRE(value == 0xD67FF7C3);
|
||||
}
|
||||
|
||||
TEST_CASE("FMAX.Q", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FMAX_Q(f31, f7, f26);
|
||||
REQUIRE(value == 0x2FA39FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FMAX_Q(f31, f31, f31);
|
||||
REQUIRE(value == 0x2FFF9FD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FMIN.Q", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FMIN_Q(f31, f7, f26);
|
||||
REQUIRE(value == 0x2FA38FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FMIN_Q(f31, f31, f31);
|
||||
REQUIRE(value == 0x2FFF8FD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FMSUB.Q", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FMSUB_Q(f15, f31, f7, f26, RMode::RNE);
|
||||
REQUIRE(value == 0xD67F87C7);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FMSUB_Q(f15, f31, f7, f26, RMode::RMM);
|
||||
REQUIRE(value == 0xD67FC7C7);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FMSUB_Q(f15, f31, f7, f26, RMode::DYN);
|
||||
REQUIRE(value == 0xD67FF7C7);
|
||||
}
|
||||
|
||||
TEST_CASE("FMUL.Q", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FMUL_Q(f31, f7, f26, RMode::RNE);
|
||||
REQUIRE(value == 0x17A38FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FMUL_Q(f31, f7, f26, RMode::RMM);
|
||||
REQUIRE(value == 0x17A3CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FMUL_Q(f31, f7, f26, RMode::DYN);
|
||||
REQUIRE(value == 0x17A3FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FNMADD.Q", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FNMADD_Q(f15, f31, f7, f26, RMode::RNE);
|
||||
REQUIRE(value == 0xD67F87CF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FNMADD_Q(f15, f31, f7, f26, RMode::RMM);
|
||||
REQUIRE(value == 0xD67FC7CF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FNMADD_Q(f15, f31, f7, f26, RMode::DYN);
|
||||
REQUIRE(value == 0xD67FF7CF);
|
||||
}
|
||||
|
||||
TEST_CASE("FNMSUB.Q", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FNMSUB_Q(f15, f31, f7, f26, RMode::RNE);
|
||||
REQUIRE(value == 0xD67F87CB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FNMSUB_Q(f15, f31, f7, f26, RMode::RMM);
|
||||
REQUIRE(value == 0xD67FC7CB);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FNMSUB_Q(f15, f31, f7, f26, RMode::DYN);
|
||||
REQUIRE(value == 0xD67FF7CB);
|
||||
}
|
||||
|
||||
TEST_CASE("FSGNJ.Q", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FSGNJ_Q(f31, f7, f26);
|
||||
REQUIRE(value == 0x27A38FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FSGNJ_Q(f31, f31, f31);
|
||||
REQUIRE(value == 0x27FF8FD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FSGNJN.Q", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FSGNJN_Q(f31, f7, f26);
|
||||
REQUIRE(value == 0x27A39FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FSGNJN_Q(f31, f31, f31);
|
||||
REQUIRE(value == 0x27FF9FD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FSGNJX.Q", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FSGNJX_Q(f31, f7, f26);
|
||||
REQUIRE(value == 0x27A3AFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FSGNJX_Q(f31, f31, f31);
|
||||
REQUIRE(value == 0x27FFAFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FSQRT.Q", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FSQRT_Q(f31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0x5E038FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FSQRT_Q(f31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0x5E03CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FSQRT_Q(f31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0x5E03FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FSUB.Q", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FSUB_Q(f31, f7, f26, RMode::RNE);
|
||||
REQUIRE(value == 0x0FA38FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FSUB_Q(f31, f7, f26, RMode::RMM);
|
||||
REQUIRE(value == 0x0FA3CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FSUB_Q(f31, f7, f26, RMode::DYN);
|
||||
REQUIRE(value == 0x0FA3FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FSQ", "[rv32q]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FSQ(f31, 1024, x15);
|
||||
REQUIRE(value == 0x41F7C027);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FSQ(f31, 1536, x15);
|
||||
REQUIRE(value == 0x61F7C027);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FSQ(f31, -1, x15);
|
||||
REQUIRE(value == 0xFFF7CFA7);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,23 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <biscuit/assembler.hpp>
|
||||
#include <cstdint>
|
||||
|
||||
namespace biscuit {
|
||||
|
||||
template <typename T>
|
||||
inline Assembler MakeAssembler32(T& buffer) {
|
||||
return Assembler{reinterpret_cast<uint8_t*>(&buffer), sizeof(buffer), ArchFeature::RV32};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Assembler MakeAssembler64(T& buffer) {
|
||||
return Assembler{reinterpret_cast<uint8_t*>(&buffer), sizeof(buffer), ArchFeature::RV64};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Assembler MakeAssembler128(T& buffer) {
|
||||
return Assembler{reinterpret_cast<uint8_t*>(&buffer), sizeof(buffer), ArchFeature::RV128};
|
||||
}
|
||||
|
||||
} // namespace biscuit
|
@ -1,495 +0,0 @@
|
||||
#include <catch/catch.hpp>
|
||||
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include "assembler_test_utils.hpp"
|
||||
|
||||
using namespace biscuit;
|
||||
|
||||
TEST_CASE("VANDN.VV", "[Zvbb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VANDN(v20, v12, v10, VecMask::Yes);
|
||||
REQUIRE(value == 0x04C50A57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VANDN(v20, v12, v10, VecMask::No);
|
||||
REQUIRE(value == 0x06C50A57);
|
||||
}
|
||||
|
||||
TEST_CASE("VANDN.VX", "[Zvbb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VANDN(v20, v12, x10, VecMask::Yes);
|
||||
REQUIRE(value == 0x04C54A57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VANDN(v20, v12, x10, VecMask::No);
|
||||
REQUIRE(value == 0x06C54A57);
|
||||
}
|
||||
|
||||
TEST_CASE("VBREV.V", "[Zvbb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VBREV(v20, v12, VecMask::Yes);
|
||||
REQUIRE(value == 0x48C52A57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VBREV(v20, v12, VecMask::No);
|
||||
REQUIRE(value == 0x4AC52A57);
|
||||
}
|
||||
|
||||
TEST_CASE("VBREV8.V", "[Zvbb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VBREV8(v20, v12, VecMask::Yes);
|
||||
REQUIRE(value == 0x48C42A57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VBREV8(v20, v12, VecMask::No);
|
||||
REQUIRE(value == 0x4AC42A57);
|
||||
}
|
||||
|
||||
TEST_CASE("VREV8.V", "[Zvbb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VREV8(v20, v12, VecMask::Yes);
|
||||
REQUIRE(value == 0x48C4AA57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VREV8(v20, v12, VecMask::No);
|
||||
REQUIRE(value == 0x4AC4AA57);
|
||||
}
|
||||
|
||||
TEST_CASE("VCLZ.V", "[Zvbb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VCLZ(v20, v12, VecMask::Yes);
|
||||
REQUIRE(value == 0x48C62A57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VCLZ(v20, v12, VecMask::No);
|
||||
REQUIRE(value == 0x4AC62A57);
|
||||
}
|
||||
|
||||
TEST_CASE("VCTZ.V", "[Zvbb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VCTZ(v20, v12, VecMask::Yes);
|
||||
REQUIRE(value == 0x48C6AA57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VCTZ(v20, v12, VecMask::No);
|
||||
REQUIRE(value == 0x4AC6AA57);
|
||||
}
|
||||
|
||||
TEST_CASE("VCPOP.V", "[Zvbb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VCPOP(v20, v12, VecMask::Yes);
|
||||
REQUIRE(value == 0x48C72A57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VCPOP(v20, v12, VecMask::No);
|
||||
REQUIRE(value == 0x4AC72A57);
|
||||
}
|
||||
|
||||
TEST_CASE("VROL.VV", "[Zvbb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VROL(v20, v12, v10, VecMask::Yes);
|
||||
REQUIRE(value == 0x54C50A57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VROL(v20, v12, v10, VecMask::No);
|
||||
REQUIRE(value == 0x56C50A57);
|
||||
}
|
||||
|
||||
TEST_CASE("VROL.VX", "[Zvbb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VROL(v20, v12, x10, VecMask::Yes);
|
||||
REQUIRE(value == 0x54C54A57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VROL(v20, v12, x10, VecMask::No);
|
||||
REQUIRE(value == 0x56C54A57);
|
||||
}
|
||||
|
||||
TEST_CASE("VROR.VV", "[Zvbb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VROR(v20, v12, v10, VecMask::Yes);
|
||||
REQUIRE(value == 0x50C50A57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VROR(v20, v12, v10, VecMask::No);
|
||||
REQUIRE(value == 0x52C50A57);
|
||||
}
|
||||
|
||||
TEST_CASE("VROR.VX", "[Zvbb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VROR(v20, v12, x10, VecMask::Yes);
|
||||
REQUIRE(value == 0x50C54A57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VROR(v20, v12, x10, VecMask::No);
|
||||
REQUIRE(value == 0x52C54A57);
|
||||
}
|
||||
|
||||
TEST_CASE("VROR.VI", "[Zvbb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VROR(v20, v12, 63, VecMask::Yes);
|
||||
REQUIRE(value == 0x54CFBA57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VROR(v20, v12, 31, VecMask::Yes);
|
||||
REQUIRE(value == 0x50CFBA57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VROR(v20, v12, 63, VecMask::No);
|
||||
REQUIRE(value == 0x56CFBA57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VROR(v20, v12, 31, VecMask::No);
|
||||
REQUIRE(value == 0x52CFBA57);
|
||||
}
|
||||
|
||||
TEST_CASE("VWSLL.VV", "[Zvbb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VWSLL(v20, v12, v10, VecMask::Yes);
|
||||
REQUIRE(value == 0xD4C50A57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VWSLL(v20, v12, v10, VecMask::No);
|
||||
REQUIRE(value == 0xD6C50A57);
|
||||
}
|
||||
|
||||
TEST_CASE("VWSLL.VX", "[Zvbb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VWSLL(v20, v12, x10, VecMask::Yes);
|
||||
REQUIRE(value == 0xD4C54A57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VWSLL(v20, v12, x10, VecMask::No);
|
||||
REQUIRE(value == 0xD6C54A57);
|
||||
}
|
||||
|
||||
TEST_CASE("VWSLL.VI", "[Zvbb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VWSLL(v20, v12, 31, VecMask::Yes);
|
||||
REQUIRE(value == 0xD4CFBA57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VWSLL(v20, v12, 15, VecMask::Yes);
|
||||
REQUIRE(value == 0xD4C7BA57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VWSLL(v20, v12, 31, VecMask::No);
|
||||
REQUIRE(value == 0xD6CFBA57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VWSLL(v20, v12, 15, VecMask::No);
|
||||
REQUIRE(value == 0xD6C7BA57);
|
||||
}
|
||||
|
||||
TEST_CASE("VCLMUL.VV", "[Zvbc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VCLMUL(v20, v12, v10, VecMask::Yes);
|
||||
REQUIRE(value == 0x30C52A57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VCLMUL(v20, v12, v10, VecMask::No);
|
||||
REQUIRE(value == 0x32C52A57);
|
||||
}
|
||||
|
||||
TEST_CASE("VCLMUL.VX", "[Zvbc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VCLMUL(v20, v12, x10, VecMask::Yes);
|
||||
REQUIRE(value == 0x30C56A57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VCLMUL(v20, v12, x10, VecMask::No);
|
||||
REQUIRE(value == 0x32C56A57);
|
||||
}
|
||||
|
||||
TEST_CASE("VCLMULH.VV", "[Zvbc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VCLMULH(v20, v12, v10, VecMask::Yes);
|
||||
REQUIRE(value == 0x34C52A57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VCLMULH(v20, v12, v10, VecMask::No);
|
||||
REQUIRE(value == 0x36C52A57);
|
||||
}
|
||||
|
||||
TEST_CASE("VCLMULH.VX", "[Zvbc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VCLMULH(v20, v12, x10, VecMask::Yes);
|
||||
REQUIRE(value == 0x34C56A57);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.VCLMULH(v20, v12, x10, VecMask::No);
|
||||
REQUIRE(value == 0x36C56A57);
|
||||
}
|
||||
|
||||
TEST_CASE("VGHSH.VV", "[Zvkg]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VGHSH(v20, v12, v10);
|
||||
REQUIRE(value == 0xB2C52A77);
|
||||
}
|
||||
|
||||
TEST_CASE("VGMUL.VV", "[Zvkg]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VGMUL(v20, v12);
|
||||
REQUIRE(value == 0xA2C8AA77);
|
||||
}
|
||||
|
||||
TEST_CASE("VAESDF.VV", "[Zvkned]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VAESDF_VV(v20, v12);
|
||||
REQUIRE(value == 0xA2C0AA77);
|
||||
}
|
||||
|
||||
TEST_CASE("VAESDF.VS", "[Zvkned]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VAESDF_VS(v20, v12);
|
||||
REQUIRE(value == 0xA6C0AA77);
|
||||
}
|
||||
|
||||
TEST_CASE("VAESDM.VV", "[Zvkned]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VAESDM_VV(v20, v12);
|
||||
REQUIRE(value == 0xA2C02A77);
|
||||
}
|
||||
|
||||
TEST_CASE("VAESDM.VS", "[Zvkned]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VAESDM_VS(v20, v12);
|
||||
REQUIRE(value == 0xA6C02A77);
|
||||
}
|
||||
|
||||
TEST_CASE("VAESEF.VV", "[Zvkned]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VAESEF_VV(v20, v12);
|
||||
REQUIRE(value == 0xA2C1AA77);
|
||||
}
|
||||
|
||||
TEST_CASE("VAESEF.VS", "[Zvkned]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VAESEF_VS(v20, v12);
|
||||
REQUIRE(value == 0xA6C1AA77);
|
||||
}
|
||||
|
||||
TEST_CASE("VAESEM.VV", "[Zvkned]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VAESEM_VV(v20, v12);
|
||||
REQUIRE(value == 0xA2C12A77);
|
||||
}
|
||||
|
||||
TEST_CASE("VAESEM.VS", "[Zvkned]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VAESEM_VS(v20, v12);
|
||||
REQUIRE(value == 0xA6C12A77);
|
||||
}
|
||||
|
||||
TEST_CASE("VAESKF1.VI", "[Zvkned]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
// Test mapping of out of range indices
|
||||
for (const uint32_t idx : {0U, 11U, 12U, 13U, 14U, 15U}) {
|
||||
as.VAESKF1(v20, v12, idx);
|
||||
|
||||
const auto op_base = 0x8AC02A77U;
|
||||
const auto inverted_b3 = idx ^ 0b1000;
|
||||
const auto verify = op_base | (inverted_b3 << 15);
|
||||
|
||||
REQUIRE(value == verify);
|
||||
|
||||
as.RewindBuffer();
|
||||
}
|
||||
|
||||
as.VAESKF1(v20, v12, 8);
|
||||
REQUIRE(value == 0x8AC42A77);
|
||||
}
|
||||
|
||||
TEST_CASE("VAESKF2.VI", "[Zvkned]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
// Test mapping of out of range indices
|
||||
for (const uint32_t idx : {0U, 1U, 15U}) {
|
||||
as.VAESKF2(v20, v12, idx);
|
||||
|
||||
const auto op_base = 0xAAC02A77;
|
||||
const auto inverted_b3 = idx ^ 0b1000;
|
||||
const auto verify = op_base | (inverted_b3 << 15);
|
||||
|
||||
REQUIRE(value == verify);
|
||||
|
||||
as.RewindBuffer();
|
||||
}
|
||||
|
||||
as.VAESKF2(v20, v12, 8);
|
||||
REQUIRE(value == 0xAAC42A77);
|
||||
}
|
||||
|
||||
TEST_CASE("VAESZ.VS", "[Zvkned]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VAESZ(v20, v12);
|
||||
REQUIRE(value == 0xA6C3AA77);
|
||||
}
|
||||
|
||||
TEST_CASE("VSHA2MS.VV", "[Zvknhb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VSHA2MS(v20, v12, v10);
|
||||
REQUIRE(value == 0xB6C52A77);
|
||||
}
|
||||
|
||||
TEST_CASE("VSHA2CH.VV", "[Zvknhb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VSHA2CH(v20, v12, v10);
|
||||
REQUIRE(value == 0xBAC52A77);
|
||||
}
|
||||
|
||||
TEST_CASE("VSHA2CL.VV", "[Zvknhb]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VSHA2CL(v20, v12, v10);
|
||||
REQUIRE(value == 0xBEC52A77);
|
||||
}
|
||||
|
||||
TEST_CASE("VSM4K.VI", "[Zvksed]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
for (uint32_t i = 0; i <= 7; i++) {
|
||||
as.VSM4K(v20, v12, i);
|
||||
|
||||
const auto op_base = 0x86C02A77U;
|
||||
const auto verify = op_base | (i << 15);
|
||||
REQUIRE(value == verify);
|
||||
|
||||
as.RewindBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("VSM4R.VV", "[Zvksed]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VSM4R_VV(v20, v12);
|
||||
REQUIRE(value == 0xA2C82A77);
|
||||
}
|
||||
|
||||
TEST_CASE("VSM4R.VS", "[Zvksed]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VSM4R_VS(v20, v12);
|
||||
REQUIRE(value == 0xA6C82A77);
|
||||
}
|
||||
|
||||
TEST_CASE("VSM3C.VI", "[Zvksh]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
for (uint32_t i = 0; i <= 31; i++) {
|
||||
as.VSM3C(v20, v12, i);
|
||||
|
||||
const auto op_base = 0xAEC02A77U;
|
||||
const auto verify = op_base | (i << 15);
|
||||
REQUIRE(value == verify);
|
||||
|
||||
as.RewindBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("VSM3ME.VV", "[Zvksh]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.VSM3ME(v20, v12, v10);
|
||||
REQUIRE(value == 0x82C52A77);
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
#include <catch/catch.hpp>
|
||||
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include "assembler_test_utils.hpp"
|
||||
|
||||
using namespace biscuit;
|
||||
|
||||
TEST_CASE("AMOCAS.D", "[Zacas]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.AMOCAS_D(Ordering::None, x31, x7, x15);
|
||||
REQUIRE(value == 0x2877BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOCAS_D(Ordering::AQ, x31, x7, x15);
|
||||
REQUIRE(value == 0x2C77BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOCAS_D(Ordering::RL, x31, x7, x15);
|
||||
REQUIRE(value == 0x2A77BFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOCAS_D(Ordering::AQRL, x31, x7, x15);
|
||||
REQUIRE(value == 0x2E77BFAF);
|
||||
}
|
||||
|
||||
TEST_CASE("AMOCAS.Q", "[Zacas]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.AMOCAS_Q(Ordering::None, x30, x6, x14);
|
||||
REQUIRE(value == 0x28674F2F);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOCAS_Q(Ordering::AQ, x30, x6, x14);
|
||||
REQUIRE(value == 0x2C674F2F);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOCAS_Q(Ordering::RL, x30, x6, x14);
|
||||
REQUIRE(value == 0x2A674F2F);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOCAS_Q(Ordering::AQRL, x30, x6, x14);
|
||||
REQUIRE(value == 0x2E674F2F);
|
||||
}
|
||||
|
||||
TEST_CASE("AMOCAS.W", "[Zacas]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.AMOCAS_W(Ordering::None, x31, x7, x15);
|
||||
REQUIRE(value == 0x2877AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOCAS_W(Ordering::AQ, x31, x7, x15);
|
||||
REQUIRE(value == 0x2C77AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOCAS_W(Ordering::RL, x31, x7, x15);
|
||||
REQUIRE(value == 0x2A77AFAF);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.AMOCAS_W(Ordering::AQRL, x31, x7, x15);
|
||||
REQUIRE(value == 0x2E77AFAF);
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
#include <catch/catch.hpp>
|
||||
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include "assembler_test_utils.hpp"
|
||||
|
||||
using namespace biscuit;
|
||||
|
||||
TEST_CASE("WRS.NTO", "[Zawrs]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.WRS_NTO();
|
||||
REQUIRE(value == 0x00D00073);
|
||||
}
|
||||
|
||||
TEST_CASE("WRS.STO", "[Zawrs]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.WRS_STO();
|
||||
REQUIRE(value == 0x01D00073);
|
||||
}
|
@ -1,457 +0,0 @@
|
||||
#include <catch/catch.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include "assembler_test_utils.hpp"
|
||||
|
||||
using namespace biscuit;
|
||||
|
||||
TEST_CASE("C.LBU", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.C_LBU(x12, 0, x15);
|
||||
REQUIRE(value == 0x8390U);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_LBU(x12, 1, x15);
|
||||
REQUIRE(value == 0x83D0U);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_LBU(x12, 2, x15);
|
||||
REQUIRE(value == 0x83B0U);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_LBU(x12, 3, x15);
|
||||
REQUIRE(value == 0x83F0U);
|
||||
}
|
||||
|
||||
TEST_CASE("C.LH", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.C_LH(x12, 0, x15);
|
||||
REQUIRE(value == 0x87D0U);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_LH(x12, 2, x15);
|
||||
REQUIRE(value == 0x87F0U);
|
||||
}
|
||||
|
||||
TEST_CASE("C.LHU", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.C_LHU(x12, 0, x15);
|
||||
REQUIRE(value == 0x8790U);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_LHU(x12, 2, x15);
|
||||
REQUIRE(value == 0x87B0U);
|
||||
}
|
||||
|
||||
TEST_CASE("C.SB", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.C_SB(x12, 0, x15);
|
||||
REQUIRE(value == 0x8B90U);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_SB(x12, 1, x15);
|
||||
REQUIRE(value == 0x8BD0U);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_SB(x12, 2, x15);
|
||||
REQUIRE(value == 0x8BB0U);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_SB(x12, 3, x15);
|
||||
REQUIRE(value == 0x8BF0U);
|
||||
}
|
||||
|
||||
TEST_CASE("C.SH", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.C_SH(x12, 0, x15);
|
||||
REQUIRE(value == 0x8F90U);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_SH(x12, 2, x15);
|
||||
REQUIRE(value == 0x8FB0U);
|
||||
}
|
||||
|
||||
TEST_CASE("C.SEXT.B", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.C_SEXT_B(x12);
|
||||
REQUIRE(value == 0x9E65);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_SEXT_B(x15);
|
||||
REQUIRE(value == 0x9FE5);
|
||||
}
|
||||
|
||||
TEST_CASE("C.SEXT.H", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.C_SEXT_H(x12);
|
||||
REQUIRE(value == 0x9E6D);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_SEXT_H(x15);
|
||||
REQUIRE(value == 0x9FED);
|
||||
}
|
||||
|
||||
TEST_CASE("C.ZEXT.B", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.C_ZEXT_B(x12);
|
||||
REQUIRE(value == 0x9E61);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_ZEXT_B(x15);
|
||||
REQUIRE(value == 0x9FE1);
|
||||
}
|
||||
|
||||
TEST_CASE("C.ZEXT.H", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.C_ZEXT_H(x12);
|
||||
REQUIRE(value == 0x9E69);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_ZEXT_H(x15);
|
||||
REQUIRE(value == 0x9FE9);
|
||||
}
|
||||
|
||||
TEST_CASE("C.ZEXT.W", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.C_ZEXT_W(x12);
|
||||
REQUIRE(value == 0x9E71);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_ZEXT_W(x15);
|
||||
REQUIRE(value == 0x9FF1);
|
||||
}
|
||||
|
||||
TEST_CASE("C.MUL", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.C_MUL(x12, x15);
|
||||
REQUIRE(value == 0x9E5D);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_MUL(x15, x12);
|
||||
REQUIRE(value == 0x9FD1);
|
||||
}
|
||||
|
||||
TEST_CASE("C.NOT", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.C_NOT(x12);
|
||||
REQUIRE(value == 0x9E75);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.C_NOT(x15);
|
||||
REQUIRE(value == 0x9FF5);
|
||||
}
|
||||
|
||||
TEST_CASE("CM.MVA01S", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.CM_MVA01S(s7, s6);
|
||||
REQUIRE(value == 0xAFFA);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.CM_MVA01S(s3, s4);
|
||||
REQUIRE(value == 0xADF2);
|
||||
}
|
||||
|
||||
TEST_CASE("CM.MVSA01", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.CM_MVSA01(s7, s6);
|
||||
REQUIRE(value == 0xAFBA);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.CM_MVSA01(s3, s4);
|
||||
REQUIRE(value == 0xADB2);
|
||||
}
|
||||
|
||||
TEST_CASE("CM.JALT", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
for (uint32_t i = 32; i <= 255; i++) {
|
||||
const uint32_t op_base = 0xA002;
|
||||
const uint32_t op = op_base | (i << 2);
|
||||
|
||||
as.CM_JALT(i);
|
||||
REQUIRE(value == op);
|
||||
|
||||
as.RewindBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("CM.JT", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
for (uint32_t i = 0; i <= 31; i++) {
|
||||
const uint32_t op_base = 0xA002;
|
||||
const uint32_t op = op_base | (i << 2);
|
||||
|
||||
as.CM_JT(i);
|
||||
REQUIRE(value == op);
|
||||
|
||||
as.RewindBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
constexpr std::array stack_adj_bases_rv32{
|
||||
0, 0, 0, 0, 16, 16, 16, 16,
|
||||
32, 32, 32, 32, 48, 48, 48, 64,
|
||||
};
|
||||
constexpr std::array stack_adj_bases_rv64{
|
||||
0, 0, 0, 0, 16, 16, 32, 32,
|
||||
48, 48, 64, 64, 80, 80, 96, 112,
|
||||
};
|
||||
|
||||
TEST_CASE("CM.POP", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.CM_POP({ra}, 16);
|
||||
REQUIRE(value == 0xBA42);
|
||||
as.RewindBuffer();
|
||||
|
||||
// s10 intentionally omitted, since no direct encoding for it exists.
|
||||
uint32_t rlist = 5;
|
||||
for (const GPR sreg : {s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s11}) {
|
||||
const auto op_base = 0xBA02U;
|
||||
const auto stack_adj_base = stack_adj_bases_rv64[rlist];
|
||||
|
||||
for (int32_t i = 0; i <= 3; i++) {
|
||||
const auto op = op_base | (rlist << 4) | uint32_t(i) << 2;
|
||||
|
||||
as.CM_POP({ra, {s0, sreg}}, stack_adj_base + (16 * i));
|
||||
REQUIRE(value == op);
|
||||
as.RewindBuffer();
|
||||
}
|
||||
|
||||
rlist++;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("CM.POP (RV32)", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.CM_POP({ra}, 16);
|
||||
REQUIRE(value == 0xBA42);
|
||||
as.RewindBuffer();
|
||||
|
||||
// s10 intentionally omitted, since no direct encoding for it exists.
|
||||
uint32_t rlist = 5;
|
||||
for (const GPR sreg : {s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s11}) {
|
||||
const auto op_base = 0xBA02U;
|
||||
const auto stack_adj_base = stack_adj_bases_rv32[rlist];
|
||||
|
||||
for (int32_t i = 0; i <= 3; i++) {
|
||||
const auto op = op_base | (rlist << 4) | uint32_t(i) << 2;
|
||||
|
||||
as.CM_POP({ra, {s0, sreg}}, stack_adj_base + (16 * i));
|
||||
REQUIRE(value == op);
|
||||
as.RewindBuffer();
|
||||
}
|
||||
|
||||
rlist++;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("CM.POPRET", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.CM_POPRET({ra}, 16);
|
||||
REQUIRE(value == 0xBE42);
|
||||
as.RewindBuffer();
|
||||
|
||||
// s10 intentionally omitted, since no direct encoding for it exists.
|
||||
uint32_t rlist = 5;
|
||||
for (const GPR sreg : {s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s11}) {
|
||||
const auto op_base = 0xBE02U;
|
||||
const auto stack_adj_base = stack_adj_bases_rv64[rlist];
|
||||
|
||||
for (int32_t i = 0; i <= 3; i++) {
|
||||
const auto op = op_base | (rlist << 4) | uint32_t(i) << 2;
|
||||
|
||||
as.CM_POPRET({ra, {s0, sreg}}, stack_adj_base + (16 * i));
|
||||
REQUIRE(value == op);
|
||||
as.RewindBuffer();
|
||||
}
|
||||
|
||||
rlist++;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("CM.POPRET (RV32)", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.CM_POPRET({ra}, 16);
|
||||
REQUIRE(value == 0xBE42);
|
||||
as.RewindBuffer();
|
||||
|
||||
// s10 intentionally omitted, since no direct encoding for it exists.
|
||||
uint32_t rlist = 5;
|
||||
for (const GPR sreg : {s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s11}) {
|
||||
const auto op_base = 0xBE02U;
|
||||
const auto stack_adj_base = stack_adj_bases_rv32[rlist];
|
||||
|
||||
for (int32_t i = 0; i <= 3; i++) {
|
||||
const auto op = op_base | (rlist << 4) | uint32_t(i) << 2;
|
||||
|
||||
as.CM_POPRET({ra, {s0, sreg}}, stack_adj_base + (16 * i));
|
||||
REQUIRE(value == op);
|
||||
as.RewindBuffer();
|
||||
}
|
||||
|
||||
rlist++;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("CM.POPRETZ", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.CM_POPRETZ({ra}, 16);
|
||||
REQUIRE(value == 0xBC42);
|
||||
as.RewindBuffer();
|
||||
|
||||
// s10 intentionally omitted, since no direct encoding for it exists.
|
||||
uint32_t rlist = 5;
|
||||
for (const GPR sreg : {s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s11}) {
|
||||
const auto op_base = 0xBC02U;
|
||||
const auto stack_adj_base = stack_adj_bases_rv64[rlist];
|
||||
|
||||
for (int32_t i = 0; i <= 3; i++) {
|
||||
const auto op = op_base | (rlist << 4) | uint32_t(i) << 2;
|
||||
|
||||
as.CM_POPRETZ({ra, {s0, sreg}}, stack_adj_base + (16 * i));
|
||||
REQUIRE(value == op);
|
||||
as.RewindBuffer();
|
||||
}
|
||||
|
||||
rlist++;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("CM.POPRETZ (RV32)", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.CM_POPRETZ({ra}, 16);
|
||||
REQUIRE(value == 0xBC42);
|
||||
as.RewindBuffer();
|
||||
|
||||
// s10 intentionally omitted, since no direct encoding for it exists.
|
||||
uint32_t rlist = 5;
|
||||
for (const GPR sreg : {s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s11}) {
|
||||
const auto op_base = 0xBC02U;
|
||||
const auto stack_adj_base = stack_adj_bases_rv32[rlist];
|
||||
|
||||
for (int32_t i = 0; i <= 3; i++) {
|
||||
const auto op = op_base | (rlist << 4) | uint32_t(i) << 2;
|
||||
|
||||
as.CM_POPRETZ({ra, {s0, sreg}}, stack_adj_base + (16 * i));
|
||||
REQUIRE(value == op);
|
||||
as.RewindBuffer();
|
||||
}
|
||||
|
||||
rlist++;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("CM.PUSH", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.CM_PUSH({ra}, -16);
|
||||
REQUIRE(value == 0xB842);
|
||||
as.RewindBuffer();
|
||||
|
||||
// s10 intentionally omitted, since no direct encoding for it exists.
|
||||
uint32_t rlist = 5;
|
||||
for (const GPR sreg : {s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s11}) {
|
||||
const auto op_base = 0xB802U;
|
||||
const auto stack_adj_base = stack_adj_bases_rv64[rlist];
|
||||
|
||||
for (int32_t i = 0; i <= 3; i++) {
|
||||
const auto op = op_base | (rlist << 4) | uint32_t(i) << 2;
|
||||
|
||||
as.CM_PUSH({ra, {s0, sreg}}, -stack_adj_base + (-16 * i));
|
||||
REQUIRE(value == op);
|
||||
as.RewindBuffer();
|
||||
}
|
||||
|
||||
rlist++;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("CM.PUSH (RV32)", "[Zc]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.CM_PUSH({ra}, -16);
|
||||
REQUIRE(value == 0xB842);
|
||||
as.RewindBuffer();
|
||||
|
||||
// s10 intentionally omitted, since no direct encoding for it exists.
|
||||
uint32_t rlist = 5;
|
||||
for (const GPR sreg : {s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s11}) {
|
||||
const auto op_base = 0xB802U;
|
||||
const auto stack_adj_base = stack_adj_bases_rv32[rlist];
|
||||
|
||||
for (int32_t i = 0; i <= 3; i++) {
|
||||
const auto op = op_base | (rlist << 4) | uint32_t(i) << 2;
|
||||
|
||||
as.CM_PUSH({ra, {s0, sreg}}, -stack_adj_base + (-16 * i));
|
||||
REQUIRE(value == op);
|
||||
as.RewindBuffer();
|
||||
}
|
||||
|
||||
rlist++;
|
||||
}
|
||||
}
|
@ -1,414 +0,0 @@
|
||||
#include <catch/catch.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include "assembler_test_utils.hpp"
|
||||
|
||||
using namespace biscuit;
|
||||
|
||||
static constexpr std::array fli_constants{
|
||||
0xBFF0000000000000ULL, // -1.0
|
||||
0x0010000000000000ULL, // Minimum positive normal
|
||||
0x3EF0000000000000ULL, // 1.0 * 2^-16
|
||||
0x3F00000000000000ULL, // 1.0 * 2^-15
|
||||
0x3F70000000000000ULL, // 1.0 * 2^-8
|
||||
0x3F80000000000000ULL, // 1.0 * 2^-7
|
||||
0x3FB0000000000000ULL, // 1.0 * 2^-4
|
||||
0x3FC0000000000000ULL, // 1.0 * 2^-3
|
||||
0x3FD0000000000000ULL, // 0.25
|
||||
0x3FD4000000000000ULL, // 0.3125
|
||||
0x3FD8000000000000ULL, // 0.375
|
||||
0x3FDC000000000000ULL, // 0.4375
|
||||
0x3FE0000000000000ULL, // 0.5
|
||||
0x3FE4000000000000ULL, // 0.625
|
||||
0x3FE8000000000000ULL, // 0.75
|
||||
0x3FEC000000000000ULL, // 0.875
|
||||
0x3FF0000000000000ULL, // 1.0
|
||||
0x3FF4000000000000ULL, // 1.25
|
||||
0x3FF8000000000000ULL, // 1.5
|
||||
0x3FFC000000000000ULL, // 1.75
|
||||
0x4000000000000000ULL, // 2.0
|
||||
0x4004000000000000ULL, // 2.5
|
||||
0x4008000000000000ULL, // 3
|
||||
0x4010000000000000ULL, // 4
|
||||
0x4020000000000000ULL, // 8
|
||||
0x4030000000000000ULL, // 16
|
||||
0x4060000000000000ULL, // 2^7
|
||||
0x4070000000000000ULL, // 2^8
|
||||
0x40E0000000000000ULL, // 2^15
|
||||
0x40F0000000000000ULL, // 2^16
|
||||
0x7FF0000000000000ULL, // +inf
|
||||
0x7FF8000000000000ULL, // Canonical NaN
|
||||
};
|
||||
|
||||
TEST_CASE("FLI.D", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
for (size_t i = 0; i < fli_constants.size(); i++) {
|
||||
const auto constant = fli_constants[i];
|
||||
double fconstant{};
|
||||
std::memcpy(&fconstant, &constant, sizeof(fconstant));
|
||||
|
||||
as.FLI_D(f10, fconstant);
|
||||
|
||||
const auto op_base = 0xF2100553;
|
||||
const auto verify = op_base | (i << 15);
|
||||
REQUIRE(value == verify);
|
||||
|
||||
as.RewindBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("FLI.H", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
for (size_t i = 0; i < fli_constants.size(); i++) {
|
||||
const auto constant = fli_constants[i];
|
||||
double fconstant{};
|
||||
std::memcpy(&fconstant, &constant, sizeof(fconstant));
|
||||
|
||||
as.FLI_H(f10, fconstant);
|
||||
|
||||
const auto op_base = 0xF4100553;
|
||||
const auto verify = op_base | (i << 15);
|
||||
REQUIRE(value == verify);
|
||||
|
||||
as.RewindBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("FLI.S", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
for (size_t i = 0; i < fli_constants.size(); i++) {
|
||||
const auto constant = fli_constants[i];
|
||||
double fconstant{};
|
||||
std::memcpy(&fconstant, &constant, sizeof(fconstant));
|
||||
|
||||
as.FLI_S(f10, fconstant);
|
||||
|
||||
const auto op_base = 0xF0100553;
|
||||
const auto verify = op_base | (i << 15);
|
||||
REQUIRE(value == verify);
|
||||
|
||||
as.RewindBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("FMINM.D", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FMINM_D(f20, f12, f10);
|
||||
REQUIRE(value == 0x2AA62A53);
|
||||
}
|
||||
|
||||
TEST_CASE("FMINM.H", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FMINM_H(f20, f12, f10);
|
||||
REQUIRE(value == 0x2CA62A53);
|
||||
}
|
||||
|
||||
TEST_CASE("FMINM.Q", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FMINM_Q(f20, f12, f10);
|
||||
REQUIRE(value == 0x2EA62A53);
|
||||
}
|
||||
|
||||
TEST_CASE("FMINM.S", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FMINM_S(f20, f12, f10);
|
||||
REQUIRE(value == 0x28A62A53);
|
||||
}
|
||||
|
||||
TEST_CASE("FMAXM.D", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FMAXM_D(f20, f12, f10);
|
||||
REQUIRE(value == 0x2AA63A53);
|
||||
}
|
||||
|
||||
TEST_CASE("FMAXM.H", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FMAXM_H(f20, f12, f10);
|
||||
REQUIRE(value == 0x2CA63A53);
|
||||
}
|
||||
|
||||
TEST_CASE("FMAXM.Q", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FMAXM_Q(f20, f12, f10);
|
||||
REQUIRE(value == 0x2EA63A53);
|
||||
}
|
||||
|
||||
TEST_CASE("FMAXM.S", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FMAXM_S(f20, f12, f10);
|
||||
REQUIRE(value == 0x28A63A53);
|
||||
}
|
||||
|
||||
TEST_CASE("FROUND.D", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FROUND_D(f31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0x42438FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FROUND_D(f31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0x4243CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FROUND_D(f31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0x4243FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FROUND.H", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FROUND_H(f31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0x44438FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FROUND_H(f31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0x4443CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FROUND_H(f31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0x4443FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FROUND.Q", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FROUND_Q(f31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0x46438FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FROUND_Q(f31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0x4643CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FROUND_Q(f31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0x4643FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FROUND.S", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FROUND_S(f31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0x40438FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FROUND_S(f31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0x4043CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FROUND_S(f31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0x4043FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FROUNDNX.D", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FROUNDNX_D(f31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0x42538FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FROUNDNX_D(f31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0x4253CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FROUNDNX_D(f31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0x4253FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FROUNDNX.H", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FROUNDNX_H(f31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0x44538FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FROUNDNX_H(f31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0x4453CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FROUNDNX_H(f31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0x4453FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FROUNDNX.Q", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FROUNDNX_Q(f31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0x46538FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FROUNDNX_Q(f31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0x4653CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FROUNDNX_Q(f31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0x4653FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FROUNDNX.S", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FROUNDNX_S(f31, f7, RMode::RNE);
|
||||
REQUIRE(value == 0x40538FD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FROUNDNX_S(f31, f7, RMode::RMM);
|
||||
REQUIRE(value == 0x4053CFD3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.FROUNDNX_S(f31, f7, RMode::DYN);
|
||||
REQUIRE(value == 0x4053FFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FCVTMOD.W.D", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FCVTMOD_W_D(x31, f7);
|
||||
REQUIRE(value == 0xC2839FD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FMVH.X.D", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FMVH_X_D(x31, f7);
|
||||
REQUIRE(value == 0xE2138FD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FMVH.X.Q", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FMVH_X_Q(x31, f7);
|
||||
REQUIRE(value == 0xE6138FD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FMVP.D.X", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler32(value);
|
||||
|
||||
as.FMVP_D_X(f31, x7, x8);
|
||||
REQUIRE(value == 0xB2838FD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FMVP.Q.X", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FMVP_Q_X(f31, x7, x8);
|
||||
REQUIRE(value == 0xB6838FD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FLEQ.D", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FLEQ_D(x31, f7, f15);
|
||||
REQUIRE(value == 0xA2F3CFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FLTQ.D", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FLTQ_D(x31, f7, f15);
|
||||
REQUIRE(value == 0xA2F3DFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FLEQ.H", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FLEQ_H(x31, f7, f15);
|
||||
REQUIRE(value == 0xA4F3CFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FLTQ.H", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FLTQ_H(x31, f7, f15);
|
||||
REQUIRE(value == 0xA4F3DFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FLEQ.Q", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FLEQ_Q(x31, f7, f15);
|
||||
REQUIRE(value == 0xA6F3CFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FLTQ.Q", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FLTQ_Q(x31, f7, f15);
|
||||
REQUIRE(value == 0xA6F3DFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FLEQ.S", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FLEQ_S(x31, f7, f15);
|
||||
REQUIRE(value == 0xA0F3CFD3);
|
||||
}
|
||||
|
||||
TEST_CASE("FLTQ.S", "[Zfa]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.FLTQ_S(x31, f7, f15);
|
||||
REQUIRE(value == 0xA0F3DFD3);
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
#include <catch/catch.hpp>
|
||||
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include "assembler_test_utils.hpp"
|
||||
|
||||
using namespace biscuit;
|
||||
|
||||
TEST_CASE("CZERO.EQZ", "[Zicond]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.CZERO_EQZ(x31, x30, x29);
|
||||
REQUIRE(value == 0x0FDF5FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.CZERO_EQZ(x1, x2, x3);
|
||||
REQUIRE(value == 0x0E3150B3);
|
||||
}
|
||||
|
||||
TEST_CASE("CZERO.NEZ", "[Zicond]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.CZERO_NEZ(x31, x30, x29);
|
||||
REQUIRE(value == 0x0FDF7FB3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.CZERO_NEZ(x1, x2, x3);
|
||||
REQUIRE(value == 0x0E3170B3);
|
||||
}
|
@ -1,130 +0,0 @@
|
||||
#include <catch/catch.hpp>
|
||||
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include "assembler_test_utils.hpp"
|
||||
|
||||
using namespace biscuit;
|
||||
|
||||
TEST_CASE("CSRRC", "[Zicsr]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.CSRRC(x31, CSR::Cycle, x15);
|
||||
REQUIRE(value == 0xC007BFF3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.CSRRC(x31, CSR::FFlags, x15);
|
||||
REQUIRE(value == 0x0017BFF3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.CSRRC(x31, CSR::FRM, x15);
|
||||
REQUIRE(value == 0x0027BFF3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.CSRRC(x31, CSR::FCSR, x15);
|
||||
REQUIRE(value == 0x0037BFF3);
|
||||
}
|
||||
|
||||
TEST_CASE("CSRRCI", "[Zicsr]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.CSRRCI(x31, CSR::Cycle, 0);
|
||||
REQUIRE(value == 0xC0007FF3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.CSRRCI(x31, CSR::FFlags, 0x1F);
|
||||
REQUIRE(value == 0x001FFFF3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.CSRRCI(x31, CSR::FRM, 0x7);
|
||||
REQUIRE(value == 0x0023FFF3);
|
||||
}
|
||||
|
||||
TEST_CASE("CSRRS", "[Zicsr]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.CSRRS(x31, CSR::Cycle, x15);
|
||||
REQUIRE(value == 0xC007AFF3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.CSRRS(x31, CSR::FFlags, x15);
|
||||
REQUIRE(value == 0x0017AFF3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.CSRRS(x31, CSR::FRM, x15);
|
||||
REQUIRE(value == 0x0027AFF3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.CSRRS(x31, CSR::FCSR, x15);
|
||||
REQUIRE(value == 0x0037AFF3);
|
||||
}
|
||||
|
||||
TEST_CASE("CSRRSI", "[Zicsr]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.CSRRSI(x31, CSR::Cycle, 0);
|
||||
REQUIRE(value == 0xC0006FF3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.CSRRSI(x31, CSR::FFlags, 0x1F);
|
||||
REQUIRE(value == 0x001FEFF3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.CSRRSI(x31, CSR::FRM, 0x7);
|
||||
REQUIRE(value == 0x0023EFF3);
|
||||
}
|
||||
|
||||
TEST_CASE("CSRRW", "[Zicsr]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.CSRRW(x31, CSR::Cycle, x15);
|
||||
REQUIRE(value == 0xC0079FF3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.CSRRW(x31, CSR::FFlags, x15);
|
||||
REQUIRE(value == 0x00179FF3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.CSRRW(x31, CSR::FRM, x15);
|
||||
REQUIRE(value == 0x00279FF3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.CSRRW(x31, CSR::FCSR, x15);
|
||||
REQUIRE(value == 0x00379FF3);
|
||||
}
|
||||
|
||||
TEST_CASE("CSRRWI", "[Zicsr]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.CSRRWI(x31, CSR::Cycle, 0);
|
||||
REQUIRE(value == 0xC0005FF3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.CSRRWI(x31, CSR::FFlags, 0x1F);
|
||||
REQUIRE(value == 0x001FDFF3);
|
||||
|
||||
as.RewindBuffer();
|
||||
|
||||
as.CSRRWI(x31, CSR::FRM, 0x7);
|
||||
REQUIRE(value == 0x0023DFF3);
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
#include <catch/catch.hpp>
|
||||
|
||||
#include <biscuit/assembler.hpp>
|
||||
|
||||
#include "assembler_test_utils.hpp"
|
||||
|
||||
using namespace biscuit;
|
||||
|
||||
TEST_CASE("C.NTL.ALL", "[Zihintntl]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.C_NTL_ALL();
|
||||
REQUIRE(value == 0x9016);
|
||||
}
|
||||
|
||||
TEST_CASE("C.NTL.S1", "[Zihintntl]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.C_NTL_S1();
|
||||
REQUIRE(value == 0x9012);
|
||||
}
|
||||
|
||||
TEST_CASE("C.NTL.P1", "[Zihintntl]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.C_NTL_P1();
|
||||
REQUIRE(value == 0x900A);
|
||||
}
|
||||
|
||||
TEST_CASE("C.NTL.PALL", "[Zihintntl]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.C_NTL_PALL();
|
||||
REQUIRE(value == 0x900E);
|
||||
}
|
||||
|
||||
TEST_CASE("NTL.ALL", "[Zihintntl]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.NTL_ALL();
|
||||
REQUIRE(value == 0x00500033);
|
||||
}
|
||||
|
||||
TEST_CASE("NTL.S1", "[Zihintntl]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.NTL_S1();
|
||||
REQUIRE(value == 0x00400033);
|
||||
}
|
||||
|
||||
TEST_CASE("NTL.P1", "[Zihintntl]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.NTL_P1();
|
||||
REQUIRE(value == 0x00200033);
|
||||
}
|
||||
|
||||
TEST_CASE("NTL.PALL", "[Zihintntl]") {
|
||||
uint32_t value = 0;
|
||||
auto as = MakeAssembler64(value);
|
||||
|
||||
as.NTL_PALL();
|
||||
REQUIRE(value == 0x00300033);
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include <catch/catch.hpp>
|
10
externals/dynarmic/externals/catch/.bazelrc
vendored
10
externals/dynarmic/externals/catch/.bazelrc
vendored
@ -1,10 +0,0 @@
|
||||
build --enable_platform_specific_config
|
||||
|
||||
build:gcc9 --cxxopt=-std=c++2a
|
||||
build:gcc11 --cxxopt=-std=c++2a
|
||||
build:clang13 --cxxopt=-std=c++17
|
||||
build:vs2019 --cxxopt=/std:c++17
|
||||
build:vs2022 --cxxopt=/std:c++17
|
||||
|
||||
build:windows --config=vs2022
|
||||
build:linux --config=gcc11
|
45
externals/dynarmic/externals/catch/.clang-format
vendored
45
externals/dynarmic/externals/catch/.clang-format
vendored
@ -1,45 +0,0 @@
|
||||
---
|
||||
Language: Cpp
|
||||
Standard: c++14
|
||||
|
||||
# Note that we cannot use IncludeIsMainRegex functionality, because it
|
||||
# does not support includes in angle brackets (<>)
|
||||
SortIncludes: true
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: <catch2/.*\.hpp>
|
||||
Priority: 1
|
||||
- Regex: <.*/.*\.hpp>
|
||||
Priority: 2
|
||||
- Regex: <.*>
|
||||
Priority: 3
|
||||
|
||||
AllowShortBlocksOnASingleLine: Always
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
AllowShortLambdasOnASingleLine: Inline
|
||||
|
||||
AccessModifierOffset: "-4"
|
||||
AlignEscapedNewlines: Left
|
||||
AllowAllConstructorInitializersOnNextLine: "true"
|
||||
BinPackArguments: "false"
|
||||
BinPackParameters: "false"
|
||||
BreakConstructorInitializers: AfterColon
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: "true"
|
||||
DerivePointerAlignment: "false"
|
||||
FixNamespaceComments: "true"
|
||||
IndentCaseLabels: "false"
|
||||
IndentPPDirectives: AfterHash
|
||||
IndentWidth: "4"
|
||||
NamespaceIndentation: All
|
||||
PointerAlignment: Left
|
||||
SpaceBeforeCtorInitializerColon: "false"
|
||||
SpaceInEmptyParentheses: "false"
|
||||
SpacesInParentheses: "true"
|
||||
TabWidth: "4"
|
||||
UseTab: Never
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SortUsingDeclarations: true
|
||||
ReflowComments: true
|
@ -1,94 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import re
|
||||
from cpt.packager import ConanMultiPackager
|
||||
from cpt.ci_manager import CIManager
|
||||
from cpt.printer import Printer
|
||||
|
||||
|
||||
class BuilderSettings(object):
|
||||
@property
|
||||
def username(self):
|
||||
""" Set catchorg as package's owner
|
||||
"""
|
||||
return os.getenv("CONAN_USERNAME", "catchorg")
|
||||
|
||||
@property
|
||||
def login_username(self):
|
||||
""" Set Bintray login username
|
||||
"""
|
||||
return os.getenv("CONAN_LOGIN_USERNAME", "horenmar")
|
||||
|
||||
@property
|
||||
def upload(self):
|
||||
""" Set Catch2 repository to be used on upload.
|
||||
The upload server address could be customized by env var
|
||||
CONAN_UPLOAD. If not defined, the method will check the branch name.
|
||||
Only devel or CONAN_STABLE_BRANCH_PATTERN will be accepted.
|
||||
The devel branch will be pushed to testing channel, because it does
|
||||
not match the stable pattern. Otherwise it will upload to stable
|
||||
channel.
|
||||
"""
|
||||
return os.getenv("CONAN_UPLOAD", "https://api.bintray.com/conan/catchorg/catch2")
|
||||
|
||||
@property
|
||||
def upload_only_when_stable(self):
|
||||
""" Force to upload when running over tag branch
|
||||
"""
|
||||
return os.getenv("CONAN_UPLOAD_ONLY_WHEN_STABLE", "True").lower() in ["true", "1", "yes"]
|
||||
|
||||
@property
|
||||
def stable_branch_pattern(self):
|
||||
""" Only upload the package the branch name is like a tag
|
||||
"""
|
||||
return os.getenv("CONAN_STABLE_BRANCH_PATTERN", r"v\d+\.\d+\.\d+")
|
||||
|
||||
@property
|
||||
def reference(self):
|
||||
""" Read project version from branch create Conan reference
|
||||
"""
|
||||
return os.getenv("CONAN_REFERENCE", "catch2/{}".format(self._version))
|
||||
|
||||
@property
|
||||
def channel(self):
|
||||
""" Default Conan package channel when not stable
|
||||
"""
|
||||
return os.getenv("CONAN_CHANNEL", "testing")
|
||||
|
||||
@property
|
||||
def _version(self):
|
||||
""" Get version name from cmake file
|
||||
"""
|
||||
pattern = re.compile(r"project\(Catch2 LANGUAGES CXX VERSION (\d+\.\d+\.\d+)\)")
|
||||
version = "latest"
|
||||
with open("CMakeLists.txt") as file:
|
||||
for line in file:
|
||||
result = pattern.search(line)
|
||||
if result:
|
||||
version = result.group(1)
|
||||
return version
|
||||
|
||||
@property
|
||||
def _branch(self):
|
||||
""" Get branch name from CI manager
|
||||
"""
|
||||
printer = Printer(None)
|
||||
ci_manager = CIManager(printer)
|
||||
return ci_manager.get_branch()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
settings = BuilderSettings()
|
||||
builder = ConanMultiPackager(
|
||||
reference=settings.reference,
|
||||
channel=settings.channel,
|
||||
upload=settings.upload,
|
||||
upload_only_when_stable=False,
|
||||
stable_branch_pattern=settings.stable_branch_pattern,
|
||||
login_username=settings.login_username,
|
||||
username=settings.username,
|
||||
test_folder=os.path.join(".conan", "test_package"))
|
||||
builder.add()
|
||||
builder.run()
|
@ -1,12 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.2.0)
|
||||
project(test_package CXX)
|
||||
|
||||
include("${CMAKE_BINARY_DIR}/conanbuildinfo.cmake")
|
||||
conan_basic_setup()
|
||||
|
||||
find_package(Catch2 REQUIRED CONFIG)
|
||||
|
||||
add_executable(${PROJECT_NAME} test_package.cpp)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} Catch2::Catch2WithMain)
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 14)
|
@ -1,20 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from conans import ConanFile, CMake
|
||||
import os
|
||||
|
||||
|
||||
class TestPackageConan(ConanFile):
|
||||
settings = "os", "compiler", "build_type", "arch"
|
||||
generators = "cmake_find_package_multi", "cmake"
|
||||
|
||||
def build(self):
|
||||
cmake = CMake(self)
|
||||
cmake.configure()
|
||||
cmake.build()
|
||||
|
||||
def test(self):
|
||||
assert os.path.isfile(os.path.join(
|
||||
self.deps_cpp_info["catch2"].rootpath, "licenses", "LICENSE.txt"))
|
||||
bin_path = os.path.join("bin", "test_package")
|
||||
self.run("%s -s" % bin_path, run_environment=True)
|
@ -1,13 +0,0 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
int Factorial( int number ) {
|
||||
return number <= 1 ? 1 : Factorial( number - 1 ) * number;
|
||||
}
|
||||
|
||||
TEST_CASE( "Factorial Tests", "[single-file]" ) {
|
||||
REQUIRE( Factorial(0) == 1 );
|
||||
REQUIRE( Factorial(1) == 1 );
|
||||
REQUIRE( Factorial(2) == 2 );
|
||||
REQUIRE( Factorial(3) == 6 );
|
||||
REQUIRE( Factorial(10) == 3628800 );
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
# This sets the default behaviour, overriding core.autocrlf
|
||||
* text=auto
|
||||
|
||||
# All source files should have unix line-endings in the repository,
|
||||
# but convert to native line-endings on checkout
|
||||
*.cpp text
|
||||
*.h text
|
||||
*.hpp text
|
||||
|
||||
# Windows specific files should retain windows line-endings
|
||||
*.sln text eol=crlf
|
||||
|
||||
# Keep executable scripts with LFs so they can be run after being
|
||||
# checked out on Windows
|
||||
*.py text eol=lf
|
||||
|
||||
|
||||
# Keep the single include header with LFs to make sure it is uploaded,
|
||||
# hashed etc with LF
|
||||
single_include/**/*.hpp eol=lf
|
||||
# Also keep the LICENCE file with LFs for the same reason
|
||||
LICENCE.txt eol=lf
|
@ -1,2 +0,0 @@
|
||||
github: "horenmar"
|
||||
custom: "https://www.paypal.me/horenmar"
|
@ -1,29 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create an issue that documents a bug
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Reproduction steps**
|
||||
Steps to reproduce the bug.
|
||||
<!-- Usually this means a small and self-contained piece of code that uses Catch and specifying compiler flags if relevant. -->
|
||||
|
||||
|
||||
**Platform information:**
|
||||
<!-- Fill in any extra information that might be important for your issue. -->
|
||||
- OS: **Windows NT**
|
||||
- Compiler+version: **GCC v2.9.5**
|
||||
- Catch version: **v1.2.3**
|
||||
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
@ -1,14 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Create an issue that requests a feature or other improvement
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Description**
|
||||
Describe the feature/change you request and why do you want it.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
@ -1,28 +0,0 @@
|
||||
<!--
|
||||
Please do not submit pull requests changing the `version.hpp`
|
||||
or the single-include `catch.hpp` file, these are changed
|
||||
only when a new release is made.
|
||||
|
||||
Before submitting a PR you should probably read the contributor documentation
|
||||
at docs/contributing.md. It will tell you how to properly test your changes.
|
||||
-->
|
||||
|
||||
|
||||
## Description
|
||||
<!--
|
||||
Describe the what and the why of your pull request. Remember that these two
|
||||
are usually a bit different. As an example, if you have made various changes
|
||||
to decrease the number of new strings allocated, that's what. The why probably
|
||||
was that you have a large set of tests and found that this speeds them up.
|
||||
-->
|
||||
|
||||
## GitHub Issues
|
||||
<!--
|
||||
If this PR was motivated by some existing issues, reference them here.
|
||||
|
||||
If it is a simple bug-fix, please also add a line like 'Closes #123'
|
||||
to your commit message, so that it is automatically closed.
|
||||
If it is not, don't, as it might take several iterations for a feature
|
||||
to be done properly. If in doubt, leave it open and reference it in the
|
||||
PR itself, so that maintainers can decide.
|
||||
-->
|
@ -1,24 +0,0 @@
|
||||
name: Bazel build
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build_and_test_ubuntu:
|
||||
name: Linux Ubuntu 22.04 Bazel build <GCC 11.2.0>
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
matrix:
|
||||
compilation_mode: [fastbuild, dbg, opt]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Mount bazel cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: "/home/runner/.cache/bazel"
|
||||
key: bazel-ubuntu22-gcc11
|
||||
|
||||
- name: Build Catch2
|
||||
run: |
|
||||
bazelisk build --compilation_mode=${{matrix.compilation_mode}} //...
|
@ -1,45 +0,0 @@
|
||||
name: Linux builds (meson)
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: meson ${{matrix.cxx}}, C++${{matrix.std}}, ${{matrix.build_type}}
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
matrix:
|
||||
cxx:
|
||||
- g++-11
|
||||
- clang++-11
|
||||
build_type: [debug, release]
|
||||
std: [14, 17]
|
||||
include:
|
||||
- cxx: clang++-11
|
||||
other_pkgs: clang-11
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Prepare environment
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y meson ninja-build ${{matrix.other_pkgs}}
|
||||
|
||||
- name: Configure build
|
||||
env:
|
||||
CXX: ${{matrix.cxx}}
|
||||
CXXFLAGS: -std=c++${{matrix.std}} ${{matrix.cxxflags}}
|
||||
# Note: $GITHUB_WORKSPACE is distinct from ${{runner.workspace}}.
|
||||
# This is important
|
||||
run: |
|
||||
meson -Dbuildtype=${{matrix.build_type}} ${{runner.workspace}}/meson-build
|
||||
|
||||
- name: Build tests + lib
|
||||
working-directory: ${{runner.workspace}}/meson-build
|
||||
run: ninja
|
||||
|
||||
- name: Run tests
|
||||
working-directory: ${{runner.workspace}}/meson-build
|
||||
# Hardcode 2 cores we know are there
|
||||
run: |
|
||||
meson test --verbose
|
@ -1,106 +0,0 @@
|
||||
# The builds in this file are more complex (e.g. they need custom CMake
|
||||
# configuration) and thus are unsuitable to the simple build matrix
|
||||
# approach used in simple-builds
|
||||
name: Linux builds (complex)
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: ${{matrix.build_description}}, ${{matrix.cxx}}, C++${{matrix.std}} ${{matrix.build_type}}
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
# We add builds one by one in this case, because there are no
|
||||
# dimensions that are shared across the builds
|
||||
include:
|
||||
|
||||
# Single surrogate header build
|
||||
- cxx: clang++-10
|
||||
build_description: Surrogates build
|
||||
build_type: Debug
|
||||
std: 14
|
||||
other_pkgs: clang-10
|
||||
cmake_configurations: -DCATCH_BUILD_SURROGATES=ON
|
||||
|
||||
# Extras and examples with gcc-7
|
||||
- cxx: g++-7
|
||||
build_description: Extras + Examples
|
||||
build_type: Debug
|
||||
std: 14
|
||||
other_pkgs: g++-7
|
||||
cmake_configurations: -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_BUILD_EXAMPLES=ON -DCATCH_ENABLE_CMAKE_HELPER_TESTS=ON
|
||||
- cxx: g++-7
|
||||
build_description: Extras + Examples
|
||||
build_type: Release
|
||||
std: 14
|
||||
other_pkgs: g++-7
|
||||
cmake_configurations: -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_BUILD_EXAMPLES=ON -DCATCH_ENABLE_CMAKE_HELPER_TESTS=ON
|
||||
|
||||
# Extras and examples with Clang-10
|
||||
- cxx: clang++-10
|
||||
build_description: Extras + Examples
|
||||
build_type: Debug
|
||||
std: 17
|
||||
other_pkgs: clang-10
|
||||
cmake_configurations: -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_BUILD_EXAMPLES=ON -DCATCH_ENABLE_CMAKE_HELPER_TESTS=ON
|
||||
- cxx: clang++-10
|
||||
build_description: Extras + Examples
|
||||
build_type: Release
|
||||
std: 17
|
||||
other_pkgs: clang-10
|
||||
cmake_configurations: -DCATCH_BUILD_EXTRA_TESTS=ON -DCATCH_BUILD_EXAMPLES=ON -DCATCH_ENABLE_CMAKE_HELPER_TESTS=ON
|
||||
|
||||
# Configure tests with Clang-10
|
||||
- cxx: clang++-10
|
||||
build_description: CMake configuration tests
|
||||
build_type: Debug
|
||||
std: 14
|
||||
other_pkgs: clang-10
|
||||
cmake_configurations: -DCATCH_ENABLE_CONFIGURE_TESTS=ON
|
||||
|
||||
# Valgrind test Clang-10
|
||||
- cxx: clang++-10
|
||||
build_description: Valgrind tests
|
||||
build_type: Debug
|
||||
std: 14
|
||||
other_pkgs: clang-10 valgrind
|
||||
cmake_configurations: -DMEMORYCHECK_COMMAND=`which valgrind` -DMEMORYCHECK_COMMAND_OPTIONS="-q --track-origins=yes --leak-check=full --num-callers=50 --show-leak-kinds=definite --error-exitcode=1"
|
||||
other_ctest_args: -T memcheck -LE uses-python
|
||||
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Prepare environment
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y ninja-build ${{matrix.other_pkgs}}
|
||||
|
||||
- name: Configure build
|
||||
working-directory: ${{runner.workspace}}
|
||||
env:
|
||||
CXX: ${{matrix.cxx}}
|
||||
CXXFLAGS: ${{matrix.cxxflags}}
|
||||
# Note: $GITHUB_WORKSPACE is distinct from ${{runner.workspace}}.
|
||||
# This is important
|
||||
run: |
|
||||
cmake -Bbuild -H$GITHUB_WORKSPACE \
|
||||
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
|
||||
-DCMAKE_CXX_STANDARD=${{matrix.std}} \
|
||||
-DCMAKE_CXX_STANDARD_REQUIRED=ON \
|
||||
-DCMAKE_CXX_EXTENSIONS=OFF \
|
||||
-DCATCH_DEVELOPMENT_BUILD=ON \
|
||||
${{matrix.cmake_configurations}} \
|
||||
-G Ninja
|
||||
|
||||
- name: Build tests + lib
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: ninja
|
||||
|
||||
- name: Run tests
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
# Hardcode 2 cores we know are there
|
||||
run: ctest -C ${{matrix.build_type}} -j 2 ${{matrix.other_ctest_args}}
|
@ -1,124 +0,0 @@
|
||||
name: Linux builds (basic)
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: ${{matrix.cxx}}, C++${{matrix.std}}, ${{matrix.build_type}}
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
cxx:
|
||||
- g++-5
|
||||
- g++-6
|
||||
- g++-7
|
||||
- g++-8
|
||||
- g++-9
|
||||
- g++-10
|
||||
- clang++-6.0
|
||||
- clang++-7
|
||||
- clang++-8
|
||||
- clang++-9
|
||||
- clang++-10
|
||||
build_type: [Debug, Release]
|
||||
std: [14]
|
||||
include:
|
||||
- cxx: g++-5
|
||||
other_pkgs: g++-5
|
||||
- cxx: g++-6
|
||||
other_pkgs: g++-6
|
||||
- cxx: g++-7
|
||||
other_pkgs: g++-7
|
||||
- cxx: g++-8
|
||||
other_pkgs: g++-8
|
||||
- cxx: g++-9
|
||||
other_pkgs: g++-9
|
||||
- cxx: g++-10
|
||||
other_pkgs: g++-10
|
||||
- cxx: clang++-6.0
|
||||
other_pkgs: clang-6.0
|
||||
- cxx: clang++-7
|
||||
other_pkgs: clang-7
|
||||
- cxx: clang++-8
|
||||
other_pkgs: clang-8
|
||||
- cxx: clang++-9
|
||||
other_pkgs: clang-9
|
||||
- cxx: clang++-10
|
||||
other_pkgs: clang-10
|
||||
# Clang 6 + C++17
|
||||
# does not work with the default libstdc++ version thanks
|
||||
# to a disagreement on variant implementation.
|
||||
# - cxx: clang++-6.0
|
||||
# build_type: Debug
|
||||
# std: 17
|
||||
# other_pkgs: clang-6.0
|
||||
# - cxx: clang++-6.0
|
||||
# build_type: Release
|
||||
# std: 17
|
||||
# other_pkgs: clang-6.0
|
||||
# Clang 10 + C++17
|
||||
- cxx: clang++-10
|
||||
build_type: Debug
|
||||
std: 17
|
||||
other_pkgs: clang-10
|
||||
- cxx: clang++-10
|
||||
build_type: Release
|
||||
std: 17
|
||||
other_pkgs: clang-10
|
||||
- cxx: clang++-10
|
||||
build_type: Debug
|
||||
std: 20
|
||||
other_pkgs: clang-10
|
||||
- cxx: clang++-10
|
||||
build_type: Release
|
||||
std: 20
|
||||
other_pkgs: clang-10
|
||||
- cxx: g++-10
|
||||
build_type: Debug
|
||||
std: 20
|
||||
other_pkgs: g++-10
|
||||
- cxx: g++-10
|
||||
build_type: Release
|
||||
std: 20
|
||||
other_pkgs: g++-10
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Add repositories for older GCC
|
||||
run: |
|
||||
sudo apt-add-repository 'deb http://azure.archive.ubuntu.com/ubuntu/ bionic main'
|
||||
sudo apt-add-repository 'deb http://azure.archive.ubuntu.com/ubuntu/ bionic universe'
|
||||
if: ${{ matrix.cxx == 'g++-5' || matrix.cxx == 'g++-6' }}
|
||||
|
||||
- name: Prepare environment
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y ninja-build ${{matrix.other_pkgs}}
|
||||
|
||||
- name: Configure build
|
||||
working-directory: ${{runner.workspace}}
|
||||
env:
|
||||
CXX: ${{matrix.cxx}}
|
||||
CXXFLAGS: ${{matrix.cxxflags}}
|
||||
# Note: $GITHUB_WORKSPACE is distinct from ${{runner.workspace}}.
|
||||
# This is important
|
||||
run: |
|
||||
cmake -Bbuild -H$GITHUB_WORKSPACE \
|
||||
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
|
||||
-DCMAKE_CXX_STANDARD=${{matrix.std}} \
|
||||
-DCMAKE_CXX_STANDARD_REQUIRED=ON \
|
||||
-DCMAKE_CXX_EXTENSIONS=OFF \
|
||||
-DCATCH_DEVELOPMENT_BUILD=ON \
|
||||
-G Ninja
|
||||
|
||||
- name: Build tests + lib
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: ninja
|
||||
|
||||
- name: Run tests
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
# Hardcode 2 cores we know are there
|
||||
run: ctest -C ${{matrix.build_type}} -j 2
|
@ -1,51 +0,0 @@
|
||||
name: Mac builds
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
# macos-12 updated to a toolchain that crashes when linking the
|
||||
# test binary. This seems to be a known bug in that version,
|
||||
# and will eventually get fixed in an update. After that, we can go
|
||||
# back to newer macos images.
|
||||
runs-on: macos-11
|
||||
strategy:
|
||||
matrix:
|
||||
cxx:
|
||||
- g++-11
|
||||
- clang++
|
||||
build_type: [Debug, Release]
|
||||
std: [14, 17]
|
||||
include:
|
||||
- build_type: Debug
|
||||
examples: ON
|
||||
extra_tests: ON
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Configure build
|
||||
working-directory: ${{runner.workspace}}
|
||||
env:
|
||||
CXX: ${{matrix.cxx}}
|
||||
CXXFLAGS: ${{matrix.cxxflags}}
|
||||
# Note: $GITHUB_WORKSPACE is distinct from ${{runner.workspace}}.
|
||||
# This is important
|
||||
run: |
|
||||
cmake -Bbuild -H$GITHUB_WORKSPACE \
|
||||
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
|
||||
-DCMAKE_CXX_STANDARD=${{matrix.std}} \
|
||||
-DCMAKE_CXX_STANDARD_REQUIRED=ON \
|
||||
-DCATCH_DEVELOPMENT_BUILD=ON \
|
||||
-DCATCH_BUILD_EXAMPLES=${{matrix.examples}} \
|
||||
-DCATCH_BUILD_EXTRA_TESTS=${{matrix.examples}}
|
||||
|
||||
- name: Build tests + lib
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: make -j `sysctl -n hw.ncpu`
|
||||
|
||||
- name: Run tests
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: ctest -C ${{matrix.build_type}} -j `sysctl -n hw.ncpu`
|
@ -1,36 +0,0 @@
|
||||
name: Check header guards
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
# Set the type of machine to run on
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Dependencies
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.7'
|
||||
- name: Install checkguard
|
||||
run: pip install guardonce
|
||||
|
||||
- name: Check that include guards are properly named
|
||||
run: |
|
||||
wrong_files=$(checkguard -r src/catch2/ -p "name | append _INCLUDED | upper")
|
||||
if [[ $wrong_files ]]; then
|
||||
echo "Files with wrong header guard:"
|
||||
echo $wrong_files
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Check that there are no duplicated filenames
|
||||
run: |
|
||||
./tools/scripts/checkDuplicateFilenames.py
|
||||
|
||||
- name: Check that all source files have the correct license header
|
||||
run: |
|
||||
./tools/scripts/checkLicense.py
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user