dep: Add biscuit and riscv-disas

This commit is contained in:
Stenzek
2023-05-30 00:11:06 +10:00
parent c561400a47
commit 49a4901c78
26 changed files with 10449 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
#pragma once
#include <cstdio>
#include <cstdlib>
#define BISCUIT_ASSERT(condition) \
do { \
if (!(condition)) { \
std::printf("Assertion failed (%s)\nin %s, function %s line %i\n", \
#condition, \
__FILE__, __func__, __LINE__); \
std::abort(); \
} \
} while (false)

View File

@ -0,0 +1,211 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <type_traits>
#include <biscuit/assert.hpp>
namespace biscuit {
/**
* An arbitrarily sized buffer that code is written into.
*
* Also contains other member functions for manipulating
* the data within the code buffer.
*/
class CodeBuffer {
public:
// Default capacity of 4KB.
static constexpr size_t default_capacity = 4096;
/**
* Constructor
*
* @param capacity The initial capacity of the code buffer in bytes.
*/
explicit CodeBuffer(size_t capacity = default_capacity);
/**
* Constructor
*
* @param buffer A non-null pointer to an allocated buffer of size `capacity`.
* @param capacity The capacity of the memory pointed to by `buffer`.
*
* @pre The given memory buffer must not be null.
* @pre The given memory buffer must be at minimum `capacity` bytes in size.
*
* @note The caller is responsible for managing the lifetime of the given memory.
* CodeBuffer will *not* free the memory once it goes out of scope.
*/
explicit CodeBuffer(uint8_t* buffer, size_t capacity);
// Copy constructor and assignment is deleted in order to prevent unintentional memory leaks.
CodeBuffer(const CodeBuffer&) = delete;
CodeBuffer& operator=(const CodeBuffer&) = delete;
// Move constructing or moving the buffer in general is allowed, as it's a transfer of control.
CodeBuffer(CodeBuffer&& other) noexcept;
CodeBuffer& operator=(CodeBuffer&& other) noexcept;
/**
* Destructor
*
* If a custom memory buffer is not given to the code buffer,
* then the code buffer will automatically free any memory
* it had allocated in order to be able to emit code.
*/
~CodeBuffer() noexcept;
/// Returns whether or not the memory is managed by the code buffer.
[[nodiscard]] bool IsManaged() const noexcept { return m_is_managed; }
/// Retrieves the current cursor position within the buffer.
[[nodiscard]] ptrdiff_t GetCursorOffset() const noexcept {
return m_cursor - m_buffer;
}
/// Retrieves the current address of the cursor within the buffer.
[[nodiscard]] uintptr_t GetCursorAddress() const noexcept {
return GetOffsetAddress(GetCursorOffset());
}
/// Retrieves the cursor pointer
[[nodiscard]] uint8_t* GetCursorPointer() noexcept {
return GetOffsetPointer(GetCursorOffset());
}
/// Retrieves the cursor pointer
[[nodiscard]] const uint8_t* GetCursorPointer() const noexcept {
return GetOffsetPointer(GetCursorOffset());
}
/// Retrieves the address of an arbitrary offset within the buffer.
[[nodiscard]] uintptr_t GetOffsetAddress(ptrdiff_t offset) const noexcept {
return reinterpret_cast<uintptr_t>(GetOffsetPointer(offset));
}
/// Retrieves the pointer to an arbitrary location within the buffer.
[[nodiscard]] uint8_t* GetOffsetPointer(ptrdiff_t offset) noexcept {
BISCUIT_ASSERT(offset >= 0 && offset <= GetCursorOffset());
return m_buffer + offset;
}
/// Retrieves the pointer to an arbitrary location within the buffer.
[[nodiscard]] const uint8_t* GetOffsetPointer(ptrdiff_t offset) const noexcept {
BISCUIT_ASSERT(offset >= 0 && offset <= GetCursorOffset());
return m_buffer + offset;
}
/**
* Allows rewinding of the code buffer cursor.
*
* @param offset The offset to rewind the cursor by.
*
* @note If no offset is provided, then this function rewinds the
* cursor to the beginning of the buffer.
*
* @note The offset may not be larger than the current cursor offset
* and may not be less than the current buffer starting address.
*/
void RewindCursor(ptrdiff_t offset = 0) noexcept {
auto* rewound = m_buffer + offset;
BISCUIT_ASSERT(m_buffer <= rewound && rewound <= m_cursor);
m_cursor = rewound;
}
/**
* Whether or not the underlying buffer has enough room for the
* given number of bytes.
*
* @param num_bytes The number of bytes to store in the buffer.
*/
[[nodiscard]] bool HasSpaceFor(size_t num_bytes) const noexcept {
return GetRemainingBytes() >= num_bytes;
}
/// Returns the size of the data written to the buffer in bytes.
[[nodiscard]] size_t GetSizeInBytes() const noexcept {
EnsureBufferRange();
return static_cast<size_t>(m_cursor - m_buffer);
}
/// Returns the total number of remaining bytes in the buffer.
[[nodiscard]] size_t GetRemainingBytes() const noexcept {
EnsureBufferRange();
return static_cast<size_t>((m_buffer + m_capacity) - m_cursor);
}
/**
* Grows the underlying memory of the code buffer
*
* @param new_capacity The new capacity of the code buffer in bytes.
*
* @pre The underlying memory of the code buffer *must* be managed
* by the code buffer itself. Attempts to grow the buffer
* with memory that is not managed by it will result in
* an assertion being hit.
*
* @note Calling this with a new capacity that is less than or equal
* to the current capacity of the buffer will result in
* this function doing nothing.
*/
void Grow(size_t new_capacity);
/**
* Emits a given value into the code buffer.
*
* @param value The value to emit into the code buffer.
* @tparam T A trivially-copyable type.
*/
template <typename T>
void Emit(T value) noexcept {
static_assert(std::is_trivially_copyable_v<T>,
"It's undefined behavior to memcpy a non-trivially-copyable type.");
BISCUIT_ASSERT(HasSpaceFor(sizeof(T)));
std::memcpy(m_cursor, &value, sizeof(T));
m_cursor += sizeof(T);
}
/// Emits a 16-bit value into the code buffer.
void Emit16(uint32_t value) noexcept {
Emit(static_cast<uint16_t>(value));
}
/// Emits a 32-bit value into the code buffer.
void Emit32(uint32_t value) noexcept {
Emit(value);
}
/**
* Sets the internal code buffer to be executable.
*
* @note This will make the contained region of memory non-writable
* to satisfy operating under W^X contexts. To make the
* region writable again, use SetWritable().
*/
void SetExecutable();
/**
* Sets the internal code buffer to be writable
*
* @note This will make the contained region of memory non-executable
* to satisfy operating under W^X contexts. To make the region
* executable again, use SetExecutable().
*/
void SetWritable();
private:
void EnsureBufferRange() const noexcept {
BISCUIT_ASSERT(m_cursor >= m_buffer && m_cursor <= m_buffer + m_capacity);
}
uint8_t* m_buffer = nullptr;
uint8_t* m_cursor = nullptr;
size_t m_capacity = 0;
bool m_is_managed = false;
};
} // namespace biscuit

View File

@ -0,0 +1,101 @@
// Copyright (c), 2022, KNS Group LLC (YADRO)
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
#pragma once
#include <biscuit/assembler.hpp>
#include <biscuit/registers.hpp>
#include <cstddef>
#include <cstdint>
#if defined(__linux__) && defined(__riscv)
#include <sys/auxv.h>
#include <sys/prctl.h>
#include <asm/hwcap.h>
#endif
namespace biscuit {
#ifndef COMPAT_HWCAP_ISA_I
#define COMPAT_HWCAP_ISA_I (1U << ('I' - 'A'))
#endif
#ifndef COMPAT_HWCAP_ISA_M
#define COMPAT_HWCAP_ISA_M (1U << ('M' - 'A'))
#endif
#ifndef COMPAT_HWCAP_ISA_A
#define COMPAT_HWCAP_ISA_A (1U << ('A' - 'A'))
#endif
#ifndef COMPAT_HWCAP_ISA_F
#define COMPAT_HWCAP_ISA_F (1U << ('F' - 'A'))
#endif
#ifndef COMPAT_HWCAP_ISA_D
#define COMPAT_HWCAP_ISA_D (1U << ('D' - 'A'))
#endif
#ifndef COMPAT_HWCAP_ISA_C
#define COMPAT_HWCAP_ISA_C (1U << ('C' - 'A'))
#endif
#ifndef COMPAT_HWCAP_ISA_V
#define COMPAT_HWCAP_ISA_V (1U << ('V' - 'A'))
#endif
enum class RISCVExtension : uint64_t {
I = COMPAT_HWCAP_ISA_I,
M = COMPAT_HWCAP_ISA_M,
A = COMPAT_HWCAP_ISA_A,
F = COMPAT_HWCAP_ISA_F,
D = COMPAT_HWCAP_ISA_D,
C = COMPAT_HWCAP_ISA_C,
V = COMPAT_HWCAP_ISA_V
};
template <CSR csr>
struct CSRReader : public biscuit::Assembler {
// Buffer capacity exactly for 2 instructions.
static constexpr size_t capacity = 8;
CSRReader() : biscuit::Assembler{CSRReader::capacity} {
CSRR(a0, csr);
RET();
}
// Copy constructor and assignment.
CSRReader(const CSRReader&) = delete;
CSRReader& operator=(const CSRReader&) = delete;
// Move constructor and assignment.
CSRReader(CSRReader&&) = default;
CSRReader& operator=(CSRReader&&) = default;
template <typename CSRReaderFunc>
CSRReaderFunc GetCode() {
this->GetCodeBuffer().SetExecutable();
return reinterpret_cast<CSRReaderFunc>(this->GetBufferPointer(0));
}
};
/**
* Class that detects information about a RISC-V CPU.
*/
class CPUInfo {
public:
/**
* Checks if a particular RISC-V extension is available.
*
* @param extension The extension to check.
*/
bool Has(RISCVExtension extension) const;
/// Returns the vector register length in bytes.
uint32_t GetVlenb() const;
};
} // namespace biscuit

View File

@ -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

View File

@ -0,0 +1,49 @@
#pragma once
#include <cstdint>
// Source file for general values and data structures
// that don't fit a particular criteria related to the ISA.
namespace biscuit {
enum class FenceOrder : uint32_t {
W = 1, // Write
R = 2, // Read
O = 4, // Device Output
I = 8, // Device Input
RW = R | W,
IO = I | O,
IR = I | R,
IW = I | W,
IRW = I | R | W,
OI = O | I,
OR = O | R,
OW = O | W,
ORW = O | R | W,
IORW = I | O | R | W,
};
// Atomic ordering
enum class Ordering : uint32_t {
None = 0, // None
RL = 1, // Release
AQ = 2, // Acquire
AQRL = AQ | RL, // Acquire-Release
};
// Floating-point Rounding Mode
enum class RMode : uint32_t {
RNE = 0b000, // Round to Nearest, ties to Even
RTZ = 0b001, // Round towards Zero
RDN = 0b010, // Round Down (towards negative infinity)
RUP = 0b011, // Round Up (towards positive infinity)
RMM = 0b100, // Round to Nearest, ties to Max Magnitude
DYN = 0b111, // Dynamic Rounding Mode
};
} // namespace biscuit

View File

@ -0,0 +1,173 @@
#pragma once
#include <cstddef>
#include <optional>
#include <set>
#include <biscuit/assert.hpp>
namespace biscuit {
/**
* A label is a representation of an address that can be used with branch and jump instructions.
*
* Labels do not need to be bound to a location immediately. A label can be created
* to provide branches with a tentative, undecided location that is then bound
* at a later point in time.
*
* @note Any label that is created, is used with a branch instruction,
* but is *not* bound to a location (via Bind() in the assembler)
* will result in an assertion being invoked when the label instance's
* destructor is executed.
*
* @note A label may only be bound to one location. Any attempt to rebind
* a label that is already bound will result in an assertion being
* invoked.
*
* @par
* An example of binding a label:
*
* @code{.cpp}
* Assembler as{...};
* Label label;
*
* as.BNE(x2, x3, &label); // Use the label
* as.ADD(x7, x8, x9);
* as.XOR(x7, x10, x12);
* as.Bind(&label); // Bind the label to a location
* @endcode
*/
class Label {
public:
using Location = std::optional<ptrdiff_t>;
using LocationOffset = Location::value_type;
/**
* Default constructor.
*
* This constructor results in a label being constructed that is not
* bound to a particular location yet.
*/
explicit Label() = default;
/// Destructor
~Label() noexcept {
// It's a logic bug if something references a label and hasn't been handled.
//
// This is usually indicative of a scenario where a label is referenced but
// hasn't been bound to a location.
//
BISCUIT_ASSERT(IsResolved());
}
// We disable copying of labels, as this doesn't really make sense to do.
// It also presents a problem. When labels are being resolved, if we have
// two labels pointing to the same place, resolving the links to this address
// are going to clobber each other N times for however many copies of the label
// exist.
//
// This isn't a particularly major problem, since the resolving will still result
// in the same end result, but it does make it annoying to think about label interactions
// moving forward. Thus, I choose to simply not think about it at all!
//
Label(const Label&) = delete;
Label& operator=(const Label&) = delete;
// Moving labels on the other hand is totally fine, this is just pushing data around
// to another label while invalidating the label having it's data "stolen".
Label(Label&&) noexcept = default;
Label& operator=(Label&&) noexcept = default;
/**
* Determines whether or not this label instance has a location assigned to it.
*
* A label is considered bound if it has an assigned location.
*/
[[nodiscard]] bool IsBound() const noexcept {
return m_location.has_value();
}
/**
* Determines whether or not this label is resolved.
*
* A label is considered resolved when all referencing offsets have been handled.
*/
[[nodiscard]] bool IsResolved() const noexcept {
return m_offsets.empty();
}
/**
* Determines whether or not this label is unresolved.
*
* A label is considered unresolved if it still has any unhandled referencing offsets.
*/
[[nodiscard]] bool IsUnresolved() const noexcept {
return !IsResolved();
}
/**
* Retrieves the location for this label.
*
* @note If the returned location is empty, then this label has not been assigned
* a location yet.
*/
[[nodiscard]] Location GetLocation() const noexcept {
return m_location;
}
private:
// A label instance is inherently bound to the assembler it's
// used with, as the offsets within the label set depend on
// said assemblers code buffer.
friend class Assembler;
/**
* Binds a label to the given location.
*
* @param offset The instruction offset to bind this label to.
*
* @pre The label must not have already been bound to a previous location.
* Attempting to rebind a label is typically, in almost all scenarios,
* the source of bugs.
* Attempting to rebind an already bound label will result in an assertion
* being triggered.
*/
void Bind(LocationOffset offset) noexcept {
BISCUIT_ASSERT(!IsBound());
m_location = offset;
}
/**
* Marks the given address as dependent on this label.
*
* This is used in scenarios where a label exists, but has not yet been
* bound to a location yet. It's important to track these addresses,
* as we'll need to patch the dependent branch instructions with the
* proper offset once the label is finally bound by the assembler.
*
* During label binding, the offset will be calculated and inserted
* into dependent instructions.
*/
void AddOffset(LocationOffset offset) {
// If a label is already bound to a location, then offset tracking
// isn't necessary. Tripping this assert means we have a bug somewhere.
BISCUIT_ASSERT(!IsBound());
BISCUIT_ASSERT(IsNewOffset(offset));
m_offsets.insert(offset);
}
// Clears all the underlying offsets for this label.
void ClearOffsets() noexcept {
m_offsets.clear();
}
// Determines whether or not this address has already been added before.
[[nodiscard]] bool IsNewOffset(LocationOffset offset) const noexcept {
return m_offsets.find(offset) == m_offsets.cend();
}
std::set<LocationOffset> m_offsets;
Location m_location;
};
} // namespace biscuit

View File

@ -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

View File

@ -0,0 +1,88 @@
#pragma once
#include <cstdint>
// Source file for anything specific to the RISC-V vector extension.
namespace biscuit {
/// Describes whether or not an instruction should make use of the mask vector.
enum class VecMask : uint32_t {
Yes = 0,
No = 1,
};
/// Describes the selected element width.
enum class SEW : uint32_t {
E8 = 0b000, // 8-bit vector elements
E16 = 0b001, // 16-bit vector elements
E32 = 0b010, // 32-bit vector elements
E64 = 0b011, // 64-bit vector elements
E128 = 0b100, // 128-bit vector elements
E256 = 0b101, // 256-bit vector elements
E512 = 0b110, // 512-bit vector elements
E1024 = 0b111, // 1024-bit vector elements
};
/// Describes the selected register group multiplier.
enum class LMUL : uint32_t {
M1 = 0b000, // Group of one vector
M2 = 0b001, // Groups of two vectors
M4 = 0b010, // Groups of four vectors
M8 = 0b011, // Groups of eight vectors
MF8 = 0b101, // Fractional vector group (1/8)
MF4 = 0b110, // Fractional vector group (1/4)
MF2 = 0b111, // Fractional vector group (1/2)
};
/**
* Describes whether or not vector masks are agnostic.
*
* From the RVV spec:
*
* When a set is marked undisturbed, the corresponding set of
* destination elements in a vector register group retain the
* value they previously held.
*
* When a set is marked agnostic, the corresponding set of destination
* elements in any vector destination operand can either retain the value
* they previously held, or are overwritten with 1s.
*
* Within a single vector instruction, each destination element can be either
* left undisturbed or overwritten with 1s, in any combination, and the pattern
* of undisturbed or overwritten with 1s is not required to be deterministic when
* the instruction is executed with the same inputs. In addition, except for
* mask load instructions, any element in the tail of a mask result can also be
* written with the value the mask-producing operation would have calculated with vl=VLMAX
*/
enum class VMA : uint32_t {
No, // Undisturbed
Yes, // Agnostic
};
/**
* Describes whether or not vector tail elements are agnostic.
*
* From the RVV spec:
*
* When a set is marked undisturbed, the corresponding set of
* destination elements in a vector register group retain the
* value they previously held.
*
* When a set is marked agnostic, the corresponding set of destination
* elements in any vector destination operand can either retain the value
* they previously held, or are overwritten with 1s.
*
* Within a single vector instruction, each destination element can be either
* left undisturbed or overwritten with 1s, in any combination, and the pattern
* of undisturbed or overwritten with 1s is not required to be deterministic when
* the instruction is executed with the same inputs. In addition, except for
* mask load instructions, any element in the tail of a mask result can also be
* written with the value the mask-producing operation would have calculated with vl=VLMAX
*/
enum class VTA : uint32_t {
No, // Undisturbed
Yes, // Agnostic
};
} // namespace biscuit