dep: Add biscuit and riscv-disas
This commit is contained in:
parent
c561400a47
commit
49a4901c78
|
@ -35,3 +35,7 @@ if(${CPU_ARCH} STREQUAL "aarch32" OR ${CPU_ARCH} STREQUAL "aarch64")
|
||||||
add_subdirectory(vixl)
|
add_subdirectory(vixl)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(${CPU_ARCH} STREQUAL "riscv64")
|
||||||
|
add_subdirectory(biscuit)
|
||||||
|
add_subdirectory(riscv-disas)
|
||||||
|
endif()
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
cmake_minimum_required(VERSION 3.15)
|
||||||
|
project(biscuit VERSION 0.9.1)
|
||||||
|
|
||||||
|
#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()
|
|
@ -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.
|
|
@ -0,0 +1,144 @@
|
||||||
|
# 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 RC |
|
||||||
|
| 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 |
|
||||||
|
| Zfh | 1.0 |
|
||||||
|
| Zfhmin | 1.0 |
|
||||||
|
| Zicbom | 1.0 |
|
||||||
|
| Zicbop | 1.0 |
|
||||||
|
| Zicboz | 1.0 |
|
||||||
|
| Zicsr | 2.0 |
|
||||||
|
| Zifencei | 2.0 |
|
||||||
|
| Zihintntl | 0.2 |
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
```
|
|
@ -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
|
||||||
|
...
|
|
@ -0,0 +1,5 @@
|
||||||
|
@PACKAGE_INIT@
|
||||||
|
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake")
|
||||||
|
|
||||||
|
check_required_components(@PROJECT_NAME@)
|
File diff suppressed because it is too large
Load Diff
|
@ -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)
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,390 @@
|
||||||
|
#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)
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
HTVal = 0x643, // Hypervisor bad guest physical address
|
||||||
|
HIP = 0x644, // Hypervisor interrupt pending
|
||||||
|
HVIP = 0x645, // Hypervisor virtual interrupt pending
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
MStatusH = 0x310, // Additional machine status register, RV32 only
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,276 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines whether or not this register is a general-purpose register.
|
||||||
|
[[nodiscard]] constexpr bool IsGPR() const noexcept {
|
||||||
|
return m_type == Type::GPR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines whether or not this register is a floating-point register.
|
||||||
|
[[nodiscard]] constexpr bool IsFPR() const noexcept {
|
||||||
|
return m_type == Type::FPR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines whether or not this register is a vector register.
|
||||||
|
[[nodiscard]] constexpr bool IsVector() const noexcept {
|
||||||
|
return m_type == Type::Vector;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
enum class Type {
|
||||||
|
GPR, // General purpose register
|
||||||
|
FPR, // Floating-point register
|
||||||
|
Vector, // Vector register
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr Register(uint32_t index, Type type) noexcept
|
||||||
|
: m_index{index}, m_type{type} {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t m_index{};
|
||||||
|
Type m_type{};
|
||||||
|
};
|
||||||
|
|
||||||
|
/// General purpose register.
|
||||||
|
class GPR final : public Register {
|
||||||
|
public:
|
||||||
|
constexpr GPR() noexcept : Register{0, Type::GPR} {}
|
||||||
|
constexpr explicit GPR(uint32_t index) noexcept : Register{index, Type::GPR} {}
|
||||||
|
|
||||||
|
friend constexpr bool operator==(GPR lhs, GPR rhs) noexcept {
|
||||||
|
return lhs.Index() == rhs.Index();
|
||||||
|
}
|
||||||
|
friend constexpr bool operator!=(GPR lhs, GPR rhs) noexcept {
|
||||||
|
return !operator==(lhs, rhs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Floating point register.
|
||||||
|
class FPR final : public Register {
|
||||||
|
public:
|
||||||
|
constexpr FPR() noexcept : Register{0, Type::FPR} {}
|
||||||
|
constexpr explicit FPR(uint32_t index) noexcept : Register{index, Type::FPR} {}
|
||||||
|
|
||||||
|
friend constexpr bool operator==(FPR lhs, FPR rhs) noexcept {
|
||||||
|
return lhs.Index() == rhs.Index();
|
||||||
|
}
|
||||||
|
friend constexpr bool operator!=(FPR lhs, FPR rhs) noexcept {
|
||||||
|
return !operator==(lhs, rhs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Vector register.
|
||||||
|
class Vec final : public Register {
|
||||||
|
public:
|
||||||
|
constexpr Vec() noexcept : Register{0, Type::Vector} {}
|
||||||
|
constexpr explicit Vec(uint32_t index) noexcept : Register{index, Type::Vector} {}
|
||||||
|
|
||||||
|
friend constexpr bool operator==(Vec lhs, Vec rhs) noexcept {
|
||||||
|
return lhs.Index() == rhs.Index();
|
||||||
|
}
|
||||||
|
friend constexpr bool operator!=(Vec lhs, Vec rhs) noexcept {
|
||||||
|
return !operator==(lhs, rhs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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};
|
||||||
|
|
||||||
|
} // namespace biscuit
|
|
@ -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
|
|
@ -0,0 +1,153 @@
|
||||||
|
# Main library
|
||||||
|
|
||||||
|
add_library(biscuit
|
||||||
|
# Source files
|
||||||
|
assembler.cpp
|
||||||
|
assembler_crypto.cpp
|
||||||
|
assembler_vector.cpp
|
||||||
|
code_buffer.cpp
|
||||||
|
cpuinfo.cpp
|
||||||
|
|
||||||
|
# Headers
|
||||||
|
"${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)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,149 @@
|
||||||
|
#include <biscuit/assert.hpp>
|
||||||
|
#include <biscuit/assembler.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 {
|
||||||
|
EmitAES32Instruction(m_buffer, 0x2A000033, rd, rs1, rs2, bs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::AES32DSMI(GPR rd, GPR rs1, GPR rs2, uint32_t bs) noexcept {
|
||||||
|
EmitAES32Instruction(m_buffer, 0x2E000033, rd, rs1, rs2, bs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::AES32ESI(GPR rd, GPR rs1, GPR rs2, uint32_t bs) noexcept {
|
||||||
|
EmitAES32Instruction(m_buffer, 0x22000033, rd, rs1, rs2, bs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::AES32ESMI(GPR rd, GPR rs1, GPR rs2, uint32_t bs) noexcept {
|
||||||
|
EmitAES32Instruction(m_buffer, 0x26000033, rd, rs1, rs2, bs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::AES64DS(GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||||
|
EmitAES64Instruction(m_buffer, 0x3A000033, rd, rs1, rs2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::AES64DSM(GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||||
|
EmitAES64Instruction(m_buffer, 0x3E000033, rd, rs1, rs2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::AES64ES(GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||||
|
EmitAES64Instruction(m_buffer, 0x32000033, rd, rs1, rs2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::AES64ESM(GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||||
|
EmitAES64Instruction(m_buffer, 0x36000033, rd, rs1, rs2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::AES64IM(GPR rd, GPR rs) noexcept {
|
||||||
|
EmitAES64Instruction(m_buffer, 0x30001013, rd, rs, x0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::AES64KS1I(GPR rd, GPR rs, uint32_t rnum) noexcept {
|
||||||
|
// RVK spec states that 0xB to 0xF are reserved.
|
||||||
|
BISCUIT_ASSERT(rnum <= 0xA);
|
||||||
|
EmitAES64Instruction(m_buffer, 0x31001013, rd, rs, GPR{rnum});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::AES64KS2(GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||||
|
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 {
|
||||||
|
EmitSHAInstruction(m_buffer, 0x10601013, rd, rs, x0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::SHA512SIG0H(GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||||
|
EmitSHAInstruction(m_buffer, 0x5C000033, rd, rs1, rs2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::SHA512SIG0L(GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||||
|
EmitSHAInstruction(m_buffer, 0x54000033, rd, rs1, rs2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::SHA512SIG1(GPR rd, GPR rs) noexcept {
|
||||||
|
EmitSHAInstruction(m_buffer, 0x10701013, rd, rs, x0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::SHA512SIG1H(GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||||
|
EmitSHAInstruction(m_buffer, 0x5E000033, rd, rs1, rs2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::SHA512SIG1L(GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||||
|
EmitSHAInstruction(m_buffer, 0x56000033, rd, rs1, rs2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::SHA512SUM0(GPR rd, GPR rs) noexcept {
|
||||||
|
EmitSHAInstruction(m_buffer, 0x10401013, rd, rs, x0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::SHA512SUM0R(GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||||
|
EmitSHAInstruction(m_buffer, 0x50000033, rd, rs1, rs2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::SHA512SUM1(GPR rd, GPR rs) noexcept {
|
||||||
|
EmitSHAInstruction(m_buffer, 0x10501013, rd, rs, x0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::SHA512SUM1R(GPR rd, GPR rs1, GPR rs2) noexcept {
|
||||||
|
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
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
||||||
|
add_library(riscv-disas
|
||||||
|
include/riscv-disas.h
|
||||||
|
src/riscv-disas.c
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(riscv-disas PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
# RISC-V Disassembler
|
||||||
|
|
||||||
|
RISC-V Disassembler with support for RV32/RV64/RV128 IMAFDC
|
||||||
|
|
||||||
|
## Build instructions
|
||||||
|
|
||||||
|
```
|
||||||
|
cmake -B build
|
||||||
|
cmake --build build
|
||||||
|
```
|
|
@ -0,0 +1,520 @@
|
||||||
|
/*
|
||||||
|
* RISC-V Disassembler
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016-2017 Michael Clark <michaeljclark@mac.com>
|
||||||
|
* Copyright (c) 2017-2018 SiFive, Inc.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RISCV_DISASSEMBLER_H
|
||||||
|
#define RISCV_DISASSEMBLER_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* types */
|
||||||
|
|
||||||
|
typedef uint64_t rv_inst;
|
||||||
|
typedef uint16_t rv_opcode;
|
||||||
|
|
||||||
|
/* enums */
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
rv32,
|
||||||
|
rv64,
|
||||||
|
rv128
|
||||||
|
} rv_isa;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
rv_rm_rne = 0,
|
||||||
|
rv_rm_rtz = 1,
|
||||||
|
rv_rm_rdn = 2,
|
||||||
|
rv_rm_rup = 3,
|
||||||
|
rv_rm_rmm = 4,
|
||||||
|
rv_rm_dyn = 7,
|
||||||
|
} rv_rm;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
rv_fence_i = 8,
|
||||||
|
rv_fence_o = 4,
|
||||||
|
rv_fence_r = 2,
|
||||||
|
rv_fence_w = 1,
|
||||||
|
} rv_fence;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
rv_ireg_zero,
|
||||||
|
rv_ireg_ra,
|
||||||
|
rv_ireg_sp,
|
||||||
|
rv_ireg_gp,
|
||||||
|
rv_ireg_tp,
|
||||||
|
rv_ireg_t0,
|
||||||
|
rv_ireg_t1,
|
||||||
|
rv_ireg_t2,
|
||||||
|
rv_ireg_s0,
|
||||||
|
rv_ireg_s1,
|
||||||
|
rv_ireg_a0,
|
||||||
|
rv_ireg_a1,
|
||||||
|
rv_ireg_a2,
|
||||||
|
rv_ireg_a3,
|
||||||
|
rv_ireg_a4,
|
||||||
|
rv_ireg_a5,
|
||||||
|
rv_ireg_a6,
|
||||||
|
rv_ireg_a7,
|
||||||
|
rv_ireg_s2,
|
||||||
|
rv_ireg_s3,
|
||||||
|
rv_ireg_s4,
|
||||||
|
rv_ireg_s5,
|
||||||
|
rv_ireg_s6,
|
||||||
|
rv_ireg_s7,
|
||||||
|
rv_ireg_s8,
|
||||||
|
rv_ireg_s9,
|
||||||
|
rv_ireg_s10,
|
||||||
|
rv_ireg_s11,
|
||||||
|
rv_ireg_t3,
|
||||||
|
rv_ireg_t4,
|
||||||
|
rv_ireg_t5,
|
||||||
|
rv_ireg_t6,
|
||||||
|
} rv_ireg;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
rvc_end,
|
||||||
|
rvc_rd_eq_ra,
|
||||||
|
rvc_rd_eq_x0,
|
||||||
|
rvc_rs1_eq_x0,
|
||||||
|
rvc_rs2_eq_x0,
|
||||||
|
rvc_rs2_eq_rs1,
|
||||||
|
rvc_rs1_eq_ra,
|
||||||
|
rvc_imm_eq_zero,
|
||||||
|
rvc_imm_eq_n1,
|
||||||
|
rvc_imm_eq_p1,
|
||||||
|
rvc_csr_eq_0x001,
|
||||||
|
rvc_csr_eq_0x002,
|
||||||
|
rvc_csr_eq_0x003,
|
||||||
|
rvc_csr_eq_0xc00,
|
||||||
|
rvc_csr_eq_0xc01,
|
||||||
|
rvc_csr_eq_0xc02,
|
||||||
|
rvc_csr_eq_0xc80,
|
||||||
|
rvc_csr_eq_0xc81,
|
||||||
|
rvc_csr_eq_0xc82,
|
||||||
|
} rvc_constraint;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
rv_codec_illegal,
|
||||||
|
rv_codec_none,
|
||||||
|
rv_codec_u,
|
||||||
|
rv_codec_uj,
|
||||||
|
rv_codec_i,
|
||||||
|
rv_codec_i_sh5,
|
||||||
|
rv_codec_i_sh6,
|
||||||
|
rv_codec_i_sh7,
|
||||||
|
rv_codec_i_csr,
|
||||||
|
rv_codec_s,
|
||||||
|
rv_codec_sb,
|
||||||
|
rv_codec_r,
|
||||||
|
rv_codec_r_m,
|
||||||
|
rv_codec_r4_m,
|
||||||
|
rv_codec_r_a,
|
||||||
|
rv_codec_r_l,
|
||||||
|
rv_codec_r_f,
|
||||||
|
rv_codec_cb,
|
||||||
|
rv_codec_cb_imm,
|
||||||
|
rv_codec_cb_sh5,
|
||||||
|
rv_codec_cb_sh6,
|
||||||
|
rv_codec_ci,
|
||||||
|
rv_codec_ci_sh5,
|
||||||
|
rv_codec_ci_sh6,
|
||||||
|
rv_codec_ci_16sp,
|
||||||
|
rv_codec_ci_lwsp,
|
||||||
|
rv_codec_ci_ldsp,
|
||||||
|
rv_codec_ci_lqsp,
|
||||||
|
rv_codec_ci_li,
|
||||||
|
rv_codec_ci_lui,
|
||||||
|
rv_codec_ci_none,
|
||||||
|
rv_codec_ciw_4spn,
|
||||||
|
rv_codec_cj,
|
||||||
|
rv_codec_cj_jal,
|
||||||
|
rv_codec_cl_lw,
|
||||||
|
rv_codec_cl_ld,
|
||||||
|
rv_codec_cl_lq,
|
||||||
|
rv_codec_cr,
|
||||||
|
rv_codec_cr_mv,
|
||||||
|
rv_codec_cr_jalr,
|
||||||
|
rv_codec_cr_jr,
|
||||||
|
rv_codec_cs,
|
||||||
|
rv_codec_cs_sw,
|
||||||
|
rv_codec_cs_sd,
|
||||||
|
rv_codec_cs_sq,
|
||||||
|
rv_codec_css_swsp,
|
||||||
|
rv_codec_css_sdsp,
|
||||||
|
rv_codec_css_sqsp,
|
||||||
|
} rv_codec;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
rv_op_illegal,
|
||||||
|
rv_op_lui,
|
||||||
|
rv_op_auipc,
|
||||||
|
rv_op_jal,
|
||||||
|
rv_op_jalr,
|
||||||
|
rv_op_beq,
|
||||||
|
rv_op_bne,
|
||||||
|
rv_op_blt,
|
||||||
|
rv_op_bge,
|
||||||
|
rv_op_bltu,
|
||||||
|
rv_op_bgeu,
|
||||||
|
rv_op_lb,
|
||||||
|
rv_op_lh,
|
||||||
|
rv_op_lw,
|
||||||
|
rv_op_lbu,
|
||||||
|
rv_op_lhu,
|
||||||
|
rv_op_sb,
|
||||||
|
rv_op_sh,
|
||||||
|
rv_op_sw,
|
||||||
|
rv_op_addi,
|
||||||
|
rv_op_slti,
|
||||||
|
rv_op_sltiu,
|
||||||
|
rv_op_xori,
|
||||||
|
rv_op_ori,
|
||||||
|
rv_op_andi,
|
||||||
|
rv_op_slli,
|
||||||
|
rv_op_srli,
|
||||||
|
rv_op_srai,
|
||||||
|
rv_op_add,
|
||||||
|
rv_op_sub,
|
||||||
|
rv_op_sll,
|
||||||
|
rv_op_slt,
|
||||||
|
rv_op_sltu,
|
||||||
|
rv_op_xor,
|
||||||
|
rv_op_srl,
|
||||||
|
rv_op_sra,
|
||||||
|
rv_op_or,
|
||||||
|
rv_op_and,
|
||||||
|
rv_op_fence,
|
||||||
|
rv_op_fence_i,
|
||||||
|
rv_op_lwu,
|
||||||
|
rv_op_ld,
|
||||||
|
rv_op_sd,
|
||||||
|
rv_op_addiw,
|
||||||
|
rv_op_slliw,
|
||||||
|
rv_op_srliw,
|
||||||
|
rv_op_sraiw,
|
||||||
|
rv_op_addw,
|
||||||
|
rv_op_subw,
|
||||||
|
rv_op_sllw,
|
||||||
|
rv_op_srlw,
|
||||||
|
rv_op_sraw,
|
||||||
|
rv_op_ldu,
|
||||||
|
rv_op_lq,
|
||||||
|
rv_op_sq,
|
||||||
|
rv_op_addid,
|
||||||
|
rv_op_sllid,
|
||||||
|
rv_op_srlid,
|
||||||
|
rv_op_sraid,
|
||||||
|
rv_op_addd,
|
||||||
|
rv_op_subd,
|
||||||
|
rv_op_slld,
|
||||||
|
rv_op_srld,
|
||||||
|
rv_op_srad,
|
||||||
|
rv_op_mul,
|
||||||
|
rv_op_mulh,
|
||||||
|
rv_op_mulhsu,
|
||||||
|
rv_op_mulhu,
|
||||||
|
rv_op_div,
|
||||||
|
rv_op_divu,
|
||||||
|
rv_op_rem,
|
||||||
|
rv_op_remu,
|
||||||
|
rv_op_mulw,
|
||||||
|
rv_op_divw,
|
||||||
|
rv_op_divuw,
|
||||||
|
rv_op_remw,
|
||||||
|
rv_op_remuw,
|
||||||
|
rv_op_muld,
|
||||||
|
rv_op_divd,
|
||||||
|
rv_op_divud,
|
||||||
|
rv_op_remd,
|
||||||
|
rv_op_remud,
|
||||||
|
rv_op_lr_w,
|
||||||
|
rv_op_sc_w,
|
||||||
|
rv_op_amoswap_w,
|
||||||
|
rv_op_amoadd_w,
|
||||||
|
rv_op_amoxor_w,
|
||||||
|
rv_op_amoor_w,
|
||||||
|
rv_op_amoand_w,
|
||||||
|
rv_op_amomin_w,
|
||||||
|
rv_op_amomax_w,
|
||||||
|
rv_op_amominu_w,
|
||||||
|
rv_op_amomaxu_w,
|
||||||
|
rv_op_lr_d,
|
||||||
|
rv_op_sc_d,
|
||||||
|
rv_op_amoswap_d,
|
||||||
|
rv_op_amoadd_d,
|
||||||
|
rv_op_amoxor_d,
|
||||||
|
rv_op_amoor_d,
|
||||||
|
rv_op_amoand_d,
|
||||||
|
rv_op_amomin_d,
|
||||||
|
rv_op_amomax_d,
|
||||||
|
rv_op_amominu_d,
|
||||||
|
rv_op_amomaxu_d,
|
||||||
|
rv_op_lr_q,
|
||||||
|
rv_op_sc_q,
|
||||||
|
rv_op_amoswap_q,
|
||||||
|
rv_op_amoadd_q,
|
||||||
|
rv_op_amoxor_q,
|
||||||
|
rv_op_amoor_q,
|
||||||
|
rv_op_amoand_q,
|
||||||
|
rv_op_amomin_q,
|
||||||
|
rv_op_amomax_q,
|
||||||
|
rv_op_amominu_q,
|
||||||
|
rv_op_amomaxu_q,
|
||||||
|
rv_op_ecall,
|
||||||
|
rv_op_ebreak,
|
||||||
|
rv_op_uret,
|
||||||
|
rv_op_sret,
|
||||||
|
rv_op_hret,
|
||||||
|
rv_op_mret,
|
||||||
|
rv_op_dret,
|
||||||
|
rv_op_sfence_vm,
|
||||||
|
rv_op_sfence_vma,
|
||||||
|
rv_op_wfi,
|
||||||
|
rv_op_csrrw,
|
||||||
|
rv_op_csrrs,
|
||||||
|
rv_op_csrrc,
|
||||||
|
rv_op_csrrwi,
|
||||||
|
rv_op_csrrsi,
|
||||||
|
rv_op_csrrci,
|
||||||
|
rv_op_flw,
|
||||||
|
rv_op_fsw,
|
||||||
|
rv_op_fmadd_s,
|
||||||
|
rv_op_fmsub_s,
|
||||||
|
rv_op_fnmsub_s,
|
||||||
|
rv_op_fnmadd_s,
|
||||||
|
rv_op_fadd_s,
|
||||||
|
rv_op_fsub_s,
|
||||||
|
rv_op_fmul_s,
|
||||||
|
rv_op_fdiv_s,
|
||||||
|
rv_op_fsgnj_s,
|
||||||
|
rv_op_fsgnjn_s,
|
||||||
|
rv_op_fsgnjx_s,
|
||||||
|
rv_op_fmin_s,
|
||||||
|
rv_op_fmax_s,
|
||||||
|
rv_op_fsqrt_s,
|
||||||
|
rv_op_fle_s,
|
||||||
|
rv_op_flt_s,
|
||||||
|
rv_op_feq_s,
|
||||||
|
rv_op_fcvt_w_s,
|
||||||
|
rv_op_fcvt_wu_s,
|
||||||
|
rv_op_fcvt_s_w,
|
||||||
|
rv_op_fcvt_s_wu,
|
||||||
|
rv_op_fmv_x_s,
|
||||||
|
rv_op_fclass_s,
|
||||||
|
rv_op_fmv_s_x,
|
||||||
|
rv_op_fcvt_l_s,
|
||||||
|
rv_op_fcvt_lu_s,
|
||||||
|
rv_op_fcvt_s_l,
|
||||||
|
rv_op_fcvt_s_lu,
|
||||||
|
rv_op_fld,
|
||||||
|
rv_op_fsd,
|
||||||
|
rv_op_fmadd_d,
|
||||||
|
rv_op_fmsub_d,
|
||||||
|
rv_op_fnmsub_d,
|
||||||
|
rv_op_fnmadd_d,
|
||||||
|
rv_op_fadd_d,
|
||||||
|
rv_op_fsub_d,
|
||||||
|
rv_op_fmul_d,
|
||||||
|
rv_op_fdiv_d,
|
||||||
|
rv_op_fsgnj_d,
|
||||||
|
rv_op_fsgnjn_d,
|
||||||
|
rv_op_fsgnjx_d,
|
||||||
|
rv_op_fmin_d,
|
||||||
|
rv_op_fmax_d,
|
||||||
|
rv_op_fcvt_s_d,
|
||||||
|
rv_op_fcvt_d_s,
|
||||||
|
rv_op_fsqrt_d,
|
||||||
|
rv_op_fle_d,
|
||||||
|
rv_op_flt_d,
|
||||||
|
rv_op_feq_d,
|
||||||
|
rv_op_fcvt_w_d,
|
||||||
|
rv_op_fcvt_wu_d,
|
||||||
|
rv_op_fcvt_d_w,
|
||||||
|
rv_op_fcvt_d_wu,
|
||||||
|
rv_op_fclass_d,
|
||||||
|
rv_op_fcvt_l_d,
|
||||||
|
rv_op_fcvt_lu_d,
|
||||||
|
rv_op_fmv_x_d,
|
||||||
|
rv_op_fcvt_d_l,
|
||||||
|
rv_op_fcvt_d_lu,
|
||||||
|
rv_op_fmv_d_x,
|
||||||
|
rv_op_flq,
|
||||||
|
rv_op_fsq,
|
||||||
|
rv_op_fmadd_q,
|
||||||
|
rv_op_fmsub_q,
|
||||||
|
rv_op_fnmsub_q,
|
||||||
|
rv_op_fnmadd_q,
|
||||||
|
rv_op_fadd_q,
|
||||||
|
rv_op_fsub_q,
|
||||||
|
rv_op_fmul_q,
|
||||||
|
rv_op_fdiv_q,
|
||||||
|
rv_op_fsgnj_q,
|
||||||
|
rv_op_fsgnjn_q,
|
||||||
|
rv_op_fsgnjx_q,
|
||||||
|
rv_op_fmin_q,
|
||||||
|
rv_op_fmax_q,
|
||||||
|
rv_op_fcvt_s_q,
|
||||||
|
rv_op_fcvt_q_s,
|
||||||
|
rv_op_fcvt_d_q,
|
||||||
|
rv_op_fcvt_q_d,
|
||||||
|
rv_op_fsqrt_q,
|
||||||
|
rv_op_fle_q,
|
||||||
|
rv_op_flt_q,
|
||||||
|
rv_op_feq_q,
|
||||||
|
rv_op_fcvt_w_q,
|
||||||
|
rv_op_fcvt_wu_q,
|
||||||
|
rv_op_fcvt_q_w,
|
||||||
|
rv_op_fcvt_q_wu,
|
||||||
|
rv_op_fclass_q,
|
||||||
|
rv_op_fcvt_l_q,
|
||||||
|
rv_op_fcvt_lu_q,
|
||||||
|
rv_op_fcvt_q_l,
|
||||||
|
rv_op_fcvt_q_lu,
|
||||||
|
rv_op_fmv_x_q,
|
||||||
|
rv_op_fmv_q_x,
|
||||||
|
rv_op_c_addi4spn,
|
||||||
|
rv_op_c_fld,
|
||||||
|
rv_op_c_lw,
|
||||||
|
rv_op_c_flw,
|
||||||
|
rv_op_c_fsd,
|
||||||
|
rv_op_c_sw,
|
||||||
|
rv_op_c_fsw,
|
||||||
|
rv_op_c_nop,
|
||||||
|
rv_op_c_addi,
|
||||||
|
rv_op_c_jal,
|
||||||
|
rv_op_c_li,
|
||||||
|
rv_op_c_addi16sp,
|
||||||
|
rv_op_c_lui,
|
||||||
|
rv_op_c_srli,
|
||||||
|
rv_op_c_srai,
|
||||||
|
rv_op_c_andi,
|
||||||
|
rv_op_c_sub,
|
||||||
|
rv_op_c_xor,
|
||||||
|
rv_op_c_or,
|
||||||
|
rv_op_c_and,
|
||||||
|
rv_op_c_subw,
|
||||||
|
rv_op_c_addw,
|
||||||
|
rv_op_c_j,
|
||||||
|
rv_op_c_beqz,
|
||||||
|
rv_op_c_bnez,
|
||||||
|
rv_op_c_slli,
|
||||||
|
rv_op_c_fldsp,
|
||||||
|
rv_op_c_lwsp,
|
||||||
|
rv_op_c_flwsp,
|
||||||
|
rv_op_c_jr,
|
||||||
|
rv_op_c_mv,
|
||||||
|
rv_op_c_ebreak,
|
||||||
|
rv_op_c_jalr,
|
||||||
|
rv_op_c_add,
|
||||||
|
rv_op_c_fsdsp,
|
||||||
|
rv_op_c_swsp,
|
||||||
|
rv_op_c_fswsp,
|
||||||
|
rv_op_c_ld,
|
||||||
|
rv_op_c_sd,
|
||||||
|
rv_op_c_addiw,
|
||||||
|
rv_op_c_ldsp,
|
||||||
|
rv_op_c_sdsp,
|
||||||
|
rv_op_c_lq,
|
||||||
|
rv_op_c_sq,
|
||||||
|
rv_op_c_lqsp,
|
||||||
|
rv_op_c_sqsp,
|
||||||
|
rv_op_nop,
|
||||||
|
rv_op_mv,
|
||||||
|
rv_op_not,
|
||||||
|
rv_op_neg,
|
||||||
|
rv_op_negw,
|
||||||
|
rv_op_sext_w,
|
||||||
|
rv_op_seqz,
|
||||||
|
rv_op_snez,
|
||||||
|
rv_op_sltz,
|
||||||
|
rv_op_sgtz,
|
||||||
|
rv_op_fmv_s,
|
||||||
|
rv_op_fabs_s,
|
||||||
|
rv_op_fneg_s,
|
||||||
|
rv_op_fmv_d,
|
||||||
|
rv_op_fabs_d,
|
||||||
|
rv_op_fneg_d,
|
||||||
|
rv_op_fmv_q,
|
||||||
|
rv_op_fabs_q,
|
||||||
|
rv_op_fneg_q,
|
||||||
|
rv_op_beqz,
|
||||||
|
rv_op_bnez,
|
||||||
|
rv_op_blez,
|
||||||
|
rv_op_bgez,
|
||||||
|
rv_op_bltz,
|
||||||
|
rv_op_bgtz,
|
||||||
|
rv_op_ble,
|
||||||
|
rv_op_bleu,
|
||||||
|
rv_op_bgt,
|
||||||
|
rv_op_bgtu,
|
||||||
|
rv_op_j,
|
||||||
|
rv_op_ret,
|
||||||
|
rv_op_jr,
|
||||||
|
rv_op_rdcycle,
|
||||||
|
rv_op_rdtime,
|
||||||
|
rv_op_rdinstret,
|
||||||
|
rv_op_rdcycleh,
|
||||||
|
rv_op_rdtimeh,
|
||||||
|
rv_op_rdinstreth,
|
||||||
|
rv_op_frcsr,
|
||||||
|
rv_op_frrm,
|
||||||
|
rv_op_frflags,
|
||||||
|
rv_op_fscsr,
|
||||||
|
rv_op_fsrm,
|
||||||
|
rv_op_fsflags,
|
||||||
|
rv_op_fsrmi,
|
||||||
|
rv_op_fsflagsi,
|
||||||
|
} rv_op;
|
||||||
|
|
||||||
|
/* structures */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t pc;
|
||||||
|
uint64_t inst;
|
||||||
|
int32_t imm;
|
||||||
|
uint16_t op;
|
||||||
|
uint8_t codec;
|
||||||
|
uint8_t rd;
|
||||||
|
uint8_t rs1;
|
||||||
|
uint8_t rs2;
|
||||||
|
uint8_t rs3;
|
||||||
|
uint8_t rm;
|
||||||
|
uint8_t pred;
|
||||||
|
uint8_t succ;
|
||||||
|
uint8_t aq;
|
||||||
|
uint8_t rl;
|
||||||
|
} rv_decode;
|
||||||
|
|
||||||
|
/* functions */
|
||||||
|
|
||||||
|
size_t inst_length(rv_inst inst);
|
||||||
|
void inst_fetch(const uint8_t *data, rv_inst *instp, size_t *length);
|
||||||
|
void disasm_inst(char *buf, size_t buflen, rv_isa isa, uint64_t pc, rv_inst inst);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1 @@
|
||||||
|
https://github.com/michaeljclark/riscv-disassembler
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue