externals: Add biscuit
Merge commit 'e4a733d5b2e02e7095847892f29ed8288d55d91e' as 'externals/biscuit'
This commit is contained in:
commit
8125738fa2
55 changed files with 40248 additions and 0 deletions
45
externals/biscuit/.github/workflows/build-and-test.yml
vendored
Normal file
45
externals/biscuit/.github/workflows/build-and-test.yml
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
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}}
|
3
externals/biscuit/.gitignore
vendored
Normal file
3
externals/biscuit/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Built files
|
||||
build/
|
||||
build-*/
|
17
externals/biscuit/CMakeLists.txt
vendored
Normal file
17
externals/biscuit/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
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/biscuit/LICENSE.md
vendored
Normal file
12
externals/biscuit/LICENSE.md
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
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/biscuit/README.md
vendored
Normal file
157
externals/biscuit/README.md
vendored
Normal file
|
@ -0,0 +1,157 @@
|
|||
# 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();
|
||||
}
|
||||
```
|
88
externals/biscuit/clang-format
vendored
Normal file
88
externals/biscuit/clang-format
vendored
Normal file
|
@ -0,0 +1,88 @@
|
|||
---
|
||||
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
|
||||
...
|
5
externals/biscuit/cmake/biscuit-config.cmake.in
vendored
Normal file
5
externals/biscuit/cmake/biscuit-config.cmake.in
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
@PACKAGE_INIT@
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake")
|
||||
|
||||
check_required_components(@PROJECT_NAME@)
|
1
externals/biscuit/examples/CMakeLists.txt
vendored
Normal file
1
externals/biscuit/examples/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
add_subdirectory(cpuinfo)
|
3
externals/biscuit/examples/cpuinfo/CMakeLists.txt
vendored
Normal file
3
externals/biscuit/examples/cpuinfo/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
add_executable(cpuinfo cpuinfo.cpp)
|
||||
target_link_libraries(cpuinfo biscuit)
|
||||
set_property(TARGET cpuinfo PROPERTY CXX_STANDARD 20)
|
31
externals/biscuit/examples/cpuinfo/cpuinfo.cpp
vendored
Normal file
31
externals/biscuit/examples/cpuinfo/cpuinfo.cpp
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
// 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;
|
||||
}
|
1475
externals/biscuit/include/biscuit/assembler.hpp
vendored
Normal file
1475
externals/biscuit/include/biscuit/assembler.hpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
14
externals/biscuit/include/biscuit/assert.hpp
vendored
Normal file
14
externals/biscuit/include/biscuit/assert.hpp
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
#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)
|
211
externals/biscuit/include/biscuit/code_buffer.hpp
vendored
Normal file
211
externals/biscuit/include/biscuit/code_buffer.hpp
vendored
Normal file
|
@ -0,0 +1,211 @@
|
|||
#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
|
101
externals/biscuit/include/biscuit/cpuinfo.hpp
vendored
Normal file
101
externals/biscuit/include/biscuit/cpuinfo.hpp
vendored
Normal file
|
@ -0,0 +1,101 @@
|
|||
// 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
|
443
externals/biscuit/include/biscuit/csr.hpp
vendored
Normal file
443
externals/biscuit/include/biscuit/csr.hpp
vendored
Normal file
|
@ -0,0 +1,443 @@
|
|||
#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
|
49
externals/biscuit/include/biscuit/isa.hpp
vendored
Normal file
49
externals/biscuit/include/biscuit/isa.hpp
vendored
Normal file
|
@ -0,0 +1,49 @@
|
|||
#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
|
173
externals/biscuit/include/biscuit/label.hpp
vendored
Normal file
173
externals/biscuit/include/biscuit/label.hpp
vendored
Normal file
|
@ -0,0 +1,173 @@
|
|||
#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
|
315
externals/biscuit/include/biscuit/registers.hpp
vendored
Normal file
315
externals/biscuit/include/biscuit/registers.hpp
vendored
Normal file
|
@ -0,0 +1,315 @@
|
|||
#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
|
88
externals/biscuit/include/biscuit/vector.hpp
vendored
Normal file
88
externals/biscuit/include/biscuit/vector.hpp
vendored
Normal file
|
@ -0,0 +1,88 @@
|
|||
#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
|
156
externals/biscuit/src/CMakeLists.txt
vendored
Normal file
156
externals/biscuit/src/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,156 @@
|
|||
# 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/biscuit/src/assembler.cpp
vendored
Normal file
1401
externals/biscuit/src/assembler.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
696
externals/biscuit/src/assembler_compressed.cpp
vendored
Normal file
696
externals/biscuit/src/assembler_compressed.cpp
vendored
Normal file
|
@ -0,0 +1,696 @@
|
|||
#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
|
172
externals/biscuit/src/assembler_crypto.cpp
vendored
Normal file
172
externals/biscuit/src/assembler_crypto.cpp
vendored
Normal file
|
@ -0,0 +1,172 @@
|
|||
#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
|
648
externals/biscuit/src/assembler_floating_point.cpp
vendored
Normal file
648
externals/biscuit/src/assembler_floating_point.cpp
vendored
Normal file
|
@ -0,0 +1,648 @@
|
|||
#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
|
224
externals/biscuit/src/assembler_util.hpp
vendored
Normal file
224
externals/biscuit/src/assembler_util.hpp
vendored
Normal file
|
@ -0,0 +1,224 @@
|
|||
#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
|
2146
externals/biscuit/src/assembler_vector.cpp
vendored
Normal file
2146
externals/biscuit/src/assembler_vector.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
111
externals/biscuit/src/code_buffer.cpp
vendored
Normal file
111
externals/biscuit/src/code_buffer.cpp
vendored
Normal file
|
@ -0,0 +1,111 @@
|
|||
#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
|
39
externals/biscuit/src/cpuinfo.cpp
vendored
Normal file
39
externals/biscuit/src/cpuinfo.cpp
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
// 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
|
76
externals/biscuit/tests/CMakeLists.txt
vendored
Normal file
76
externals/biscuit/tests/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,76 @@
|
|||
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})
|
17976
externals/biscuit/tests/externals/catch/catch.hpp
vendored
Normal file
17976
externals/biscuit/tests/externals/catch/catch.hpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
95
externals/biscuit/tests/src/assembler_bfloat_tests.cpp
vendored
Normal file
95
externals/biscuit/tests/src/assembler_bfloat_tests.cpp
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
#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);
|
||||
}
|
105
externals/biscuit/tests/src/assembler_branch_tests.cpp
vendored
Normal file
105
externals/biscuit/tests/src/assembler_branch_tests.cpp
vendored
Normal file
|
@ -0,0 +1,105 @@
|
|||
#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);
|
||||
}
|
||||
}
|
113
externals/biscuit/tests/src/assembler_cmo_tests.cpp
vendored
Normal file
113
externals/biscuit/tests/src/assembler_cmo_tests.cpp
vendored
Normal file
|
@ -0,0 +1,113 @@
|
|||
#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);
|
||||
}
|
302
externals/biscuit/tests/src/assembler_privileged_tests.cpp
vendored
Normal file
302
externals/biscuit/tests/src/assembler_privileged_tests.cpp
vendored
Normal file
|
@ -0,0 +1,302 @@
|
|||
#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);
|
||||
}
|
769
externals/biscuit/tests/src/assembler_rv32i_tests.cpp
vendored
Normal file
769
externals/biscuit/tests/src/assembler_rv32i_tests.cpp
vendored
Normal file
|
@ -0,0 +1,769 @@
|
|||
#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);
|
||||
}
|
436
externals/biscuit/tests/src/assembler_rv64i_tests.cpp
vendored
Normal file
436
externals/biscuit/tests/src/assembler_rv64i_tests.cpp
vendored
Normal file
|
@ -0,0 +1,436 @@
|
|||
#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);
|
||||
}
|
513
externals/biscuit/tests/src/assembler_rva_tests.cpp
vendored
Normal file
513
externals/biscuit/tests/src/assembler_rva_tests.cpp
vendored
Normal file
|
@ -0,0 +1,513 @@
|
|||
#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);
|
||||
}
|
610
externals/biscuit/tests/src/assembler_rvb_tests.cpp
vendored
Normal file
610
externals/biscuit/tests/src/assembler_rvb_tests.cpp
vendored
Normal file
|
@ -0,0 +1,610 @@
|
|||
#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);
|
||||
}
|
595
externals/biscuit/tests/src/assembler_rvc_tests.cpp
vendored
Normal file
595
externals/biscuit/tests/src/assembler_rvc_tests.cpp
vendored
Normal file
|
@ -0,0 +1,595 @@
|
|||
#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);
|
||||
}
|
528
externals/biscuit/tests/src/assembler_rvd_tests.cpp
vendored
Normal file
528
externals/biscuit/tests/src/assembler_rvd_tests.cpp
vendored
Normal file
|
@ -0,0 +1,528 @@
|
|||
#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);
|
||||
}
|
1085
externals/biscuit/tests/src/assembler_rvf_tests.cpp
vendored
Normal file
1085
externals/biscuit/tests/src/assembler_rvf_tests.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
384
externals/biscuit/tests/src/assembler_rvk_tests.cpp
vendored
Normal file
384
externals/biscuit/tests/src/assembler_rvk_tests.cpp
vendored
Normal file
|
@ -0,0 +1,384 @@
|
|||
#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);
|
||||
}
|
241
externals/biscuit/tests/src/assembler_rvm_tests.cpp
vendored
Normal file
241
externals/biscuit/tests/src/assembler_rvm_tests.cpp
vendored
Normal file
|
@ -0,0 +1,241 @@
|
|||
#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);
|
||||
}
|
538
externals/biscuit/tests/src/assembler_rvq_tests.cpp
vendored
Normal file
538
externals/biscuit/tests/src/assembler_rvq_tests.cpp
vendored
Normal file
|
@ -0,0 +1,538 @@
|
|||
#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);
|
||||
}
|
5334
externals/biscuit/tests/src/assembler_rvv_tests.cpp
vendored
Normal file
5334
externals/biscuit/tests/src/assembler_rvv_tests.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
23
externals/biscuit/tests/src/assembler_test_utils.hpp
vendored
Normal file
23
externals/biscuit/tests/src/assembler_test_utils.hpp
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
#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
|
495
externals/biscuit/tests/src/assembler_vector_crypto_tests.cpp
vendored
Normal file
495
externals/biscuit/tests/src/assembler_vector_crypto_tests.cpp
vendored
Normal file
|
@ -0,0 +1,495 @@
|
|||
#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);
|
||||
}
|
76
externals/biscuit/tests/src/assembler_zacas_tests.cpp
vendored
Normal file
76
externals/biscuit/tests/src/assembler_zacas_tests.cpp
vendored
Normal file
|
@ -0,0 +1,76 @@
|
|||
#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);
|
||||
}
|
23
externals/biscuit/tests/src/assembler_zawrs_tests.cpp
vendored
Normal file
23
externals/biscuit/tests/src/assembler_zawrs_tests.cpp
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
#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);
|
||||
}
|
457
externals/biscuit/tests/src/assembler_zc_tests.cpp
vendored
Normal file
457
externals/biscuit/tests/src/assembler_zc_tests.cpp
vendored
Normal file
|
@ -0,0 +1,457 @@
|
|||
#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++;
|
||||
}
|
||||
}
|
414
externals/biscuit/tests/src/assembler_zfa_tests.cpp
vendored
Normal file
414
externals/biscuit/tests/src/assembler_zfa_tests.cpp
vendored
Normal file
|
@ -0,0 +1,414 @@
|
|||
#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);
|
||||
}
|
33
externals/biscuit/tests/src/assembler_zicond_tests.cpp
vendored
Normal file
33
externals/biscuit/tests/src/assembler_zicond_tests.cpp
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
#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);
|
||||
}
|
130
externals/biscuit/tests/src/assembler_zicsr_tests.cpp
vendored
Normal file
130
externals/biscuit/tests/src/assembler_zicsr_tests.cpp
vendored
Normal file
|
@ -0,0 +1,130 @@
|
|||
#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);
|
||||
}
|
71
externals/biscuit/tests/src/assembler_zihintntl_tests.cpp
vendored
Normal file
71
externals/biscuit/tests/src/assembler_zihintntl_tests.cpp
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
#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);
|
||||
}
|
2
externals/biscuit/tests/src/main.cpp
vendored
Normal file
2
externals/biscuit/tests/src/main.cpp
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
#define CATCH_CONFIG_MAIN
|
||||
#include <catch/catch.hpp>
|
Loading…
Reference in a new issue