Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
132 commits
Select commit Hold shift + click to select a range
19112f2
Initial CSR implementation. Currently Capstone does not decode CSR ad…
dANW34V3R Jan 19, 2023
5facccf
Update mock architecture updateSystemTimerRegisters method
dANW34V3R Jan 19, 2023
070f71c
Take changes from riscv-F-extension branch and delete it
dANW34V3R Jan 19, 2023
7800310
Majority of F extension support
dANW34V3R Feb 16, 2023
0b4a0e3
Finish main imlementation for all instructions and tests
dANW34V3R Feb 20, 2023
6a54377
Add comment to each execution case and improve ordering
dANW34V3R Feb 20, 2023
035108a
Improve NaNbox logic
dANW34V3R Feb 20, 2023
e2259d7
Correctly tag multiply, divide and floating point instructions
dANW34V3R Feb 22, 2023
33bd0bb
Add floating point instruction groups and correctly tag integer multi…
dANW34V3R Feb 22, 2023
8fccee8
Correctly tag RISC-V divide and multiply instructions
dANW34V3R Feb 27, 2023
8fe9969
Create test reproducing error most of the time
dANW34V3R Feb 27, 2023
ab352c3
Update inorder halting condition
dANW34V3R Feb 28, 2023
67fab7c
Rename knownTarget_ to knownOffset_ to better reflect meaning. Update…
dANW34V3R Feb 28, 2023
9230d43
Update comments
dANW34V3R Feb 28, 2023
5100faa
Update config file to test programs [WIP]
dANW34V3R Feb 23, 2023
a567dd7
Merge branch 'earlyHalting' into RISCV_F
dANW34V3R Feb 28, 2023
f04232c
Update RISCV_CONFIG to use new instruction groups
dANW34V3R Feb 28, 2023
78ffa82
Minor updates
dANW34V3R Mar 22, 2023
685957c
Populate auxved with PHDR values
dANW34V3R Mar 22, 2023
b59bc1e
Merge branch 'auxvecFix' into RISCV_F
dANW34V3R Mar 22, 2023
6f8a3b8
Add entry point to auxvec
dANW34V3R Mar 22, 2023
49557c6
Merge branch 'auxvecFix' into RISCV_F
dANW34V3R Mar 22, 2023
3a4e38a
Add comments
dANW34V3R Mar 22, 2023
fa60f72
Refactor Linux Process variable names
dANW34V3R Mar 22, 2023
8fc3675
Comment and variable name updates
dANW34V3R Mar 24, 2023
4b9aa60
Update spacing
dANW34V3R Mar 24, 2023
0ce1639
Create function to return pending slots in pipeline buffer
dANW34V3R Mar 24, 2023
b952393
Merge branch 'auxvecFix' into RISCV_F
dANW34V3R Mar 24, 2023
858c634
Merge branch 'earlyHalting' into RISCV_F
dANW34V3R Mar 24, 2023
785ec46
Fix typos
dANW34V3R Mar 24, 2023
07081d5
Change dataTransferred variable name
dANW34V3R Mar 24, 2023
382d1d7
Minor comment updates
dANW34V3R Mar 27, 2023
f4299b6
Update CSR dummy test and add pseudoinstruction
dANW34V3R Mar 27, 2023
8dc8957
Remove temporary mremap implementation
dANW34V3R Mar 27, 2023
218416e
Change cout to cerr
dANW34V3R Mar 27, 2023
e750b11
Merge branch 'auxvecFix' into RISCV_F
dANW34V3R Mar 29, 2023
d908843
Update branch prediction supplying logic
dANW34V3R Mar 31, 2023
904e6a4
Merge branch 'loopBufferFix' into RISCV_F
dANW34V3R Mar 31, 2023
1cc2bcd
Change ticks to uint to reduce chance of overflow
dANW34V3R Jul 17, 2023
f72bd3e
Merge branch 'dev' into RISCV_F
dANW34V3R Jul 18, 2023
1ba1d53
Remove empty_ from execute unit after merge
dANW34V3R Jul 18, 2023
f168f4f
Merge branch 'dev' into RISCV_F
dANW34V3R Oct 17, 2023
b4ac39b
Implement first C instructions, enough to run gcc 12.2 STREAM
dANW34V3R Oct 25, 2023
b28f68d
TEST Merge branch 'dev' into RISCV_C
dANW34V3R Dec 14, 2023
17f21a7
Fixup
dANW34V3R Dec 14, 2023
9fa7a7b
Create test file and add two more instructions
dANW34V3R Dec 15, 2023
29f931e
Add c.ebreak and test framework
dANW34V3R Dec 19, 2023
f38ee7c
Add some more tests
dANW34V3R Dec 20, 2023
7b4e3ff
Refactor getStackPointer function name for clarity
dANW34V3R Dec 20, 2023
221227e
Add runCompressed for finer control of extensions used in tests
dANW34V3R Dec 21, 2023
2f91d10
Complete C extension tests
dANW34V3R Dec 21, 2023
c08c33e
Merge branch 'dev' into RISCV_C
dANW34V3R Dec 21, 2023
e40a236
Minor fixup
dANW34V3R Dec 21, 2023
38aed44
Update JALR test for better coverage
dANW34V3R Dec 22, 2023
ae95e31
Change name of operands array for less ambiguity e.g. which operands,…
dANW34V3R Dec 22, 2023
f037024
Create Instruction immediate field to prevent usage of metadata outsi…
dANW34V3R Dec 22, 2023
6242e85
Cleanup
dANW34V3R Dec 22, 2023
60afac6
Initial OoO debug, prevent predecoding too many bytes
dANW34V3R Dec 22, 2023
f990a46
Fix OoO core
dANW34V3R Jan 9, 2024
472461c
Remove prints and ensure not too many bytes read
dANW34V3R Jan 9, 2024
f0489d8
Cleanup ready for PR
dANW34V3R Jan 10, 2024
7d52983
Update sourceRegValues name and apply to AArch64
dANW34V3R Jan 19, 2024
5844ffc
Docs update
dANW34V3R Jan 19, 2024
08dbf0a
Change name operandsPending for clarity
dANW34V3R Jan 19, 2024
95f86f7
Add comment
dANW34V3R Jan 19, 2024
4d5df21
Update type
dANW34V3R Jan 19, 2024
000fe93
Undo operands renaming
dANW34V3R Jan 26, 2024
60bcfb9
Undo operands renaming in docs
dANW34V3R Jan 29, 2024
cac1715
Undo operandsPending rename
dANW34V3R Jan 29, 2024
23b8f25
Undo RISC-V operandsPending rename
dANW34V3R Jan 29, 2024
267b1d3
Undo getInitialStackPointer rename
dANW34V3R Jan 29, 2024
31039f2
Merge branch 'dev' into RISCV_C
dANW34V3R Jan 29, 2024
1e43fd3
Rever Linux.getInitialStackPointer
dANW34V3R Jan 29, 2024
369d9ab
Fix incorrect formatting
dANW34V3R Jan 29, 2024
8304f1e
Add comments
dANW34V3R Jan 29, 2024
7d38328
Rename imm to imm_
dANW34V3R Jan 29, 2024
08cb07e
Remove comment
dANW34V3R Jan 30, 2024
2c00c9f
Cleanup instruction length field
dANW34V3R Jan 30, 2024
ba0b419
Update stack terminology
dANW34V3R Jan 31, 2024
3738db8
Remove TODOs
dANW34V3R Feb 1, 2024
25f2f31
Merge branch 'dev' into RISCV_C
dANW34V3R Feb 2, 2024
f527e05
Prevent segfault in fcvtzu test, unsure why fix works
dANW34V3R Feb 2, 2024
4f6ee8f
Don't attempt to predecode if max instruction length bytes not available
dANW34V3R Feb 2, 2024
f38e9cb
Nan fix in line with PR 381
dANW34V3R Feb 5, 2024
8c67ac5
Update predecode to predecode for compressed instructions meaning no …
dANW34V3R Feb 5, 2024
c223cc5
Merge branch 'dev' into RISCV_C
dANW34V3R Feb 6, 2024
21b06de
Update invalid instruction bits as now decodes as C.NOP
dANW34V3R Feb 6, 2024
76757cc
Remove debug prints and add assertion
dANW34V3R Feb 6, 2024
cf80e20
Update comments
dANW34V3R Feb 7, 2024
80faf6a
Update predecode to handle the last bytes of fetch buffer and invalid…
dANW34V3R Feb 8, 2024
9585677
Return 0 from predecode
dANW34V3R Feb 8, 2024
d9f5f50
Revert predecode to int8_t
dANW34V3R Feb 8, 2024
f8527d7
Add comments to compressed tests
dANW34V3R Feb 8, 2024
7ce768c
Cleanup
dANW34V3R Feb 8, 2024
00bb37d
Add min bytes getter and update fetch unit. Unit tests break
dANW34V3R Feb 9, 2024
de12b36
Address PR comments
dANW34V3R Feb 9, 2024
e9d9ad8
Fix fetch unit tests
dANW34V3R Feb 9, 2024
b9dadd6
Change imm_ name to sourceImm
dANW34V3R Feb 9, 2024
a2a674e
Update decode logic layout and add assertions
dANW34V3R Feb 9, 2024
4b667ef
Remove extra newlines in fetch unit and update comment
dANW34V3R Feb 9, 2024
2aa6801
Add comments to all tests and include JR and MV tests
dANW34V3R Feb 12, 2024
db339bf
Use calloc in release mode and add free
dANW34V3R Feb 12, 2024
e0cfbda
Only print relevant bytes on exception
dANW34V3R Feb 12, 2024
84eb25f
Add assertions for reserved encodings
dANW34V3R Feb 12, 2024
e7f72e2
Update TODO's
dANW34V3R Feb 12, 2024
36d20c6
Remove arch constants struct
dANW34V3R Feb 12, 2024
e795794
Docs update
dANW34V3R Feb 12, 2024
b5ed8f5
Add fetch unit tests and allow continuation with 2 bytes in buffer
dANW34V3R Feb 13, 2024
4b6ec28
Merge branch 'dev' into RISCV_C
dANW34V3R Feb 13, 2024
7e85590
Remove prints from fetch unit
dANW34V3R Feb 13, 2024
5e2a8b2
Remove query comments
dANW34V3R Feb 13, 2024
78aaa94
Comment cleanup
dANW34V3R Feb 17, 2024
a09cf77
Update test and architecture
dANW34V3R Feb 17, 2024
0bf5212
Update fetch unit
dANW34V3R Feb 17, 2024
9958073
Remove compressed wording from unit tests
dANW34V3R Feb 17, 2024
8f47ba7
Updates regarding PR comments
dANW34V3R Feb 17, 2024
2876560
Update docs and unit tests
dANW34V3R Feb 17, 2024
a9e3bec
Add build type conditions to fetch units tests
dANW34V3R Feb 18, 2024
d0c7527
Merge branch 'dev' into RISCV_C
dANW34V3R Feb 18, 2024
45f8afc
Parameterise tests
dANW34V3R Feb 19, 2024
12ce7c6
Use cs register enum in all cases
dANW34V3R Feb 19, 2024
6c6642b
Capitalise
dANW34V3R Feb 19, 2024
848c1ae
PR comments
dANW34V3R Feb 19, 2024
b06672e
Update fetch unit comment
dANW34V3R Feb 19, 2024
f22b0da
Update fetch unit comments inline with new parameterisation
dANW34V3R Feb 20, 2024
b72ddda
Move comment in instruction decode
dANW34V3R Feb 20, 2024
ffbfc03
Add TODO
dANW34V3R Feb 20, 2024
f69eb0b
Comment update
dANW34V3R Feb 20, 2024
7cbf65a
Merge branch 'dev' into RISCV_C
dANW34V3R Feb 20, 2024
eca2361
Clang format
dANW34V3R Feb 20, 2024
5827c89
Make compressed default false and update tests
dANW34V3R Feb 20, 2024
bcb2490
Change assertion to expect
dANW34V3R Feb 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions configs/DEMO_RISCV.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

Core:
ISA: rv64
Compressed: True
Comment thread
jj16791 marked this conversation as resolved.
Simulation-Mode: outoforder
Clock-Frequency-GHz: 2.5
Timer-Frequency-MHz: 200
Expand Down
4 changes: 3 additions & 1 deletion docs/sphinx/developer/arch/supported/riscv.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
RISCV
=======

SimEng provides an almost complete implementation of the rv64imafd architecture, as well as being capable of handling some supervisor call (syscall) exceptions via basic system call emulation. This is sufficient to run many simple single threaded programs that have been statically compiled with the standard library.
SimEng provides an almost complete implementation of the rv64imafdc architecture, as well as being capable of handling some supervisor call (syscall) exceptions via basic system call emulation. This is sufficient to run many simple single threaded programs that have been statically compiled with the standard library.

.. contents:: Contents

Expand Down Expand Up @@ -57,6 +57,8 @@ Adding execution behaviour

The process for adding a new instruction is very similar to that of :ref:`AArch64 <aarch64-adding-instructions>`, by adding a new, uniquely identified entry to ``src/lib/arch/riscv/Instruction_execute.cc``.

Compressed instructions are treated in the same way as pseudoinstructions. By design they can be expanded to full instructions from the base and floating point extensions. A new case should be added to the switch statement in ``InstructionMetadata`` to perform the relevant adjustment to the metadata. The instruction can then be allowed to flow through the pipeline - no new execute case is necessary.

Zero registers
**************

Expand Down
3 changes: 3 additions & 0 deletions docs/sphinx/user/configuring_simeng.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ Vector-Length (Only in use when ISA is ``AArch64``)
Streaming-Vector-Length (Only in use when ISA is ``AArch64``)
The vector length used by instructions belonging to Arm's Scalable Matrix Extension. Although the architecturally valid vector lengths are powers of 2 between 128 and 2048 inclusive, the supported vector lengths are those between 128 and 2048 in increments of 128.

Compressed (Only in use when ISA is ``rv64``)
Enables the RISC-V compressed extension. If set to false and compressed instructions are supplied, a misaligned program counter exception is usually thrown.

Fetch
-----

Expand Down
3 changes: 3 additions & 0 deletions src/include/simeng/arch/Architecture.hh
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ class Architecture {
/** Returns the maximum size of a valid instruction in bytes. */
virtual uint8_t getMaxInstructionSize() const = 0;

/** Returns the minimum size of a valid instruction in bytes. */
virtual uint8_t getMinInstructionSize() const = 0;

/** Updates System registers of any system-based timers. */
virtual void updateSystemTimerRegisters(RegisterFileSet* regFile,
const uint64_t iterations) const = 0;
Expand Down
3 changes: 3 additions & 0 deletions src/include/simeng/arch/aarch64/Architecture.hh
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ class Architecture : public arch::Architecture {
/** Returns the maximum size of a valid instruction in bytes. */
uint8_t getMaxInstructionSize() const override;

/** Returns the minimum size of a valid instruction in bytes. */
uint8_t getMinInstructionSize() const override;

/** Updates System registers of any system-based timers. */
void updateSystemTimerRegisters(RegisterFileSet* regFile,
const uint64_t iterations) const override;
Expand Down
4 changes: 2 additions & 2 deletions src/include/simeng/arch/aarch64/Instruction.hh
Original file line number Diff line number Diff line change
Expand Up @@ -437,8 +437,8 @@ class Instruction : public simeng::Instruction {
/** The current exception state of this instruction. */
InstructionException exception_ = InstructionException::None;

/** The number of operands that have not yet had values supplied. Used to
* determine execution readiness. */
/** The number of source operands that have not yet had values supplied. Used
* to determine execution readiness. */
uint16_t sourceOperandsPending_ = 0;

/** Is the micro-operation opcode of the instruction, where appropriate. */
Expand Down
8 changes: 8 additions & 0 deletions src/include/simeng/arch/riscv/ArchInfo.hh
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ typedef enum riscv_sysreg {

} riscv_sysreg;

// A struct of RISC-V specific constants
namespace constantsPool {
const uint8_t addressAlignMask = 0x3;
const uint8_t addressAlignMaskCompressed = 0x1;
const uint8_t minInstWidthBytes = 4;
const uint8_t minInstWidthBytesCompressed = 2;
}; // namespace constantsPool

/** A class to hold and generate riscv specific architecture configuration
* options. */
class ArchInfo : public simeng::arch::ArchInfo {
Expand Down
13 changes: 11 additions & 2 deletions src/include/simeng/arch/riscv/Architecture.hh
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ class Architecture : public arch::Architecture {
~Architecture();

/** Pre-decode instruction memory into a macro-op of `Instruction`
* instances. Returns the number of bytes consumed to produce it (always 4),
* and writes into the supplied macro-op vector. */
* instances. Returns the number of bytes consumed to produce it (0 if
* failure), and writes into the supplied macro-op vector. */
uint8_t predecode(const void* ptr, uint16_t bytesAvailable,
uint64_t instructionAddress,
MacroOp& output) const override;
Expand All @@ -45,6 +45,9 @@ class Architecture : public arch::Architecture {
/** Returns the maximum size of a valid instruction in bytes. */
uint8_t getMaxInstructionSize() const override;

/** Returns the minimum size of a valid instruction in bytes. */
uint8_t getMinInstructionSize() const override;

/** Updates System registers of any system-based timers. */
void updateSystemTimerRegisters(RegisterFileSet* regFile,
const uint64_t iterations) const override;
Expand All @@ -68,6 +71,12 @@ class Architecture : public arch::Architecture {

/** System Register of Processor Cycle Counter. */
simeng::Register cycleSystemReg_;

/** A mask used to determine if an address has the correct byte alignment */
uint8_t addressAlignmentMask_;

/** Minimum number of bytes that can represent an instruction */
uint8_t minInsnLength_;
};

} // namespace riscv
Expand Down
8 changes: 6 additions & 2 deletions src/include/simeng/arch/riscv/Instruction.hh
Original file line number Diff line number Diff line change
Expand Up @@ -233,15 +233,19 @@ class Instruction : public simeng::Instruction {
* `sourceRegisters` entry. */
std::array<RegisterValue, MAX_SOURCE_REGISTERS> sourceValues_;

/** The immediate source operand for which there is only ever one. Remains 0
* if unused. */
int64_t sourceImm_ = 0;

/** An array of generated output results. Each entry corresponds to a
* `destinationRegisters` entry. */
std::array<RegisterValue, MAX_DESTINATION_REGISTERS> results_;

/** The current exception state of this instruction. */
InstructionException exception_ = InstructionException::None;

/** The number of operands that have not yet had values supplied. Used to
* determine execution readiness. */
/** The number of source operands that have not yet had values supplied. Used
* to determine execution readiness. */
uint16_t sourceOperandsPending_ = 0;

/** Used to denote what type of instruction this is. Utilises the constants in
Expand Down
8 changes: 4 additions & 4 deletions src/include/simeng/kernel/LinuxProcess.hh
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ uint64_t alignToBoundary(uint64_t value, uint64_t boundary);
*
* The constructed process follows a typical layout:
*
* |---------------| <- start of stack
* |---------------| <- start/bottom of stack
* | Stack | stack grows downwards
* |-v-----------v-|
* | |
Expand Down Expand Up @@ -76,7 +76,7 @@ class LinuxProcess {
/** Get the address of the start of the heap region. */
uint64_t getHeapStart() const;

/** Get the address of the top of the stack. */
/** Get the address of the bottom of the stack. */
uint64_t getStackStart() const;

/** Get the address of the start of the mmap region. */
Expand All @@ -94,7 +94,7 @@ class LinuxProcess {
/** Get the entry point. */
uint64_t getEntryPoint() const;

/** Get the initial stack pointer address. */
/** Get the initial stack pointer. */
uint64_t getInitialStackPointer() const;

/** Get the path of the executable. */
Expand Down Expand Up @@ -134,7 +134,7 @@ class LinuxProcess {
/** The page size of the process memory. */
const uint64_t pageSize_ = 4096;

/** The address of the stack pointer. */
/** The address of the head/top of the stack */
uint64_t stackPointer_;

/** The process image size. */
Expand Down
7 changes: 7 additions & 0 deletions src/include/simeng/pipeline/FetchUnit.hh
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,13 @@ class FetchUnit {

/** The amount of data currently in the fetch buffer. */
uint16_t bufferedBytes_ = 0;

/** Let the following PipelineFetchUnitTest derived classes be a friend of
* this class to allow proper testing of 'tick' function. */
friend class PipelineFetchUnitTest_invalidMinBytesAtEndOfBuffer_Test;
friend class PipelineFetchUnitTest_minSizeInstructionAtEndOfBuffer_Test;
friend class PipelineFetchUnitTest_validMinSizeReadsDontComplete_Test;
friend class PipelineFetchUnitTest_invalidMinBytesreadsDontComplete_Test;
};

} // namespace pipeline
Expand Down
2 changes: 2 additions & 0 deletions src/lib/arch/aarch64/Architecture.cc
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,8 @@ ProcessStateChange Architecture::getInitialState() const {

uint8_t Architecture::getMaxInstructionSize() const { return 4; }

uint8_t Architecture::getMinInstructionSize() const { return 4; }

void Architecture::updateSystemTimerRegisters(RegisterFileSet* regFile,
const uint64_t iterations) const {
// Update the Processor Cycle Counter to total cycles completed.
Expand Down
95 changes: 78 additions & 17 deletions src/lib/arch/riscv/Architecture.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,25 @@ Architecture::Architecture(kernel::Linux& kernel, ryml::ConstNodeRef config)
// TODO set fcsr accordingly when Zicsr extension supported
fesetround(FE_TONEAREST);

cs_err n = cs_open(CS_ARCH_RISCV, CS_MODE_RISCV64, &capstoneHandle_);
cs_err n;

// Check whether compressed instructions in use. Initialise variables and
// Capstone accordingly
if (config["Core"]["Compressed"].as<bool>()) {
Comment thread
jj16791 marked this conversation as resolved.
addressAlignmentMask_ = constantsPool::addressAlignMaskCompressed;
minInsnLength_ = constantsPool::minInstWidthBytesCompressed;

n = cs_open(CS_ARCH_RISCV,
static_cast<cs_mode>(CS_MODE_RISCV64 | CS_MODE_RISCVC),
&capstoneHandle_);
} else {
addressAlignmentMask_ = constantsPool::addressAlignMask;
minInsnLength_ = constantsPool::minInstWidthBytes;

n = cs_open(CS_ARCH_RISCV, static_cast<cs_mode>(CS_MODE_RISCV64),
&capstoneHandle_);
}

if (n != CS_ERR_OK) {
std::cerr << "[SimEng:Architecture] Could not create capstone handle due "
"to error "
Expand Down Expand Up @@ -141,7 +159,8 @@ uint8_t Architecture::predecode(const void* ptr, uint16_t bytesAvailable,
uint64_t instructionAddress,
MacroOp& output) const {
// Check that instruction address is 4-byte aligned as required by RISC-V
if (instructionAddress & 0x3) {
// 2-byte when Compressed extension is supported
if (instructionAddress & addressAlignmentMask_) {
// Consume 1-byte and raise a misaligned PC exception
auto metadata = InstructionMetadata((uint8_t*)ptr, 1);
metadataCache_.emplace_front(metadata);
Expand All @@ -154,31 +173,65 @@ uint8_t Architecture::predecode(const void* ptr, uint16_t bytesAvailable,
return 1;
}

assert(bytesAvailable >= 4 &&
"Fewer than 4 bytes supplied to RISC-V decoder");

// Dereference the instruction pointer to obtain the instruction word
uint32_t insn;
memcpy(&insn, ptr, 4);
assert(bytesAvailable >= minInsnLength_ &&
"Fewer than bytes limit supplied to RISC-V decoder");

// Get the first byte
uint8_t firstByte = ((uint8_t*)ptr)[0];

uint32_t insnEncoding = 0;
size_t insnSize = 4;

// Predecode bytes to determine whether we have a compressed instruction.
// This will allow continuation if a compressed instruction is in the last 2
// bytes of a fetch block, but will request more data if only half of a
// non-compressed instruction is present

// Check the 2 least significant bits as these determine instruction length
if ((firstByte & 0b11) != 0b11) {
// 2 byte - compressed
// Only use relevant bytes
// Dereference the instruction pointer to obtain the instruction word
memcpy(&insnEncoding, ptr, 2);
insnSize = 2;
} else {
// 4 byte
if (bytesAvailable < 4) {
// Not enough bytes available, bail
return 0;
}
// Dereference the instruction pointer to obtain the instruction word
memcpy(&insnEncoding, ptr, 4);
}

// Try to find the decoding in the decode cache
auto iter = decodeCache_.find(insn);
auto iter = decodeCache_.find(insnEncoding);
if (iter == decodeCache_.end()) {
// No decoding present. Generate a fresh decoding, and add to cache
cs_insn rawInsn;
// Calloc memory to ensure rawInsn is initialised with zeros. Errors can
// occur otherwise as Capstone doesn't update variables for invalid
// instructions
cs_insn* rawInsnPointer = (cs_insn*)calloc(1, sizeof(cs_insn));
cs_insn rawInsn = *rawInsnPointer;
assert(rawInsn.size == 0 && "rawInsn not initialised correctly");

cs_detail rawDetail;
rawInsn.detail = &rawDetail;
// Size requires initialisation in case of capstone failure which won't
// update this value
rawInsn.size = insnSize;

size_t size = 4;
uint64_t address = 0;

const uint8_t* encoding = reinterpret_cast<const uint8_t*>(ptr);

bool success =
cs_disasm_iter(capstoneHandle_, &encoding, &size, &address, &rawInsn);
bool success = cs_disasm_iter(capstoneHandle_, &encoding, &insnSize,
&address, &rawInsn);

auto metadata = success ? InstructionMetadata(rawInsn)
: InstructionMetadata(encoding, rawInsn.size);

auto metadata =
success ? InstructionMetadata(rawInsn) : InstructionMetadata(encoding);
free(rawInsnPointer);

// Cache the metadata
metadataCache_.push_front(metadata);
Expand All @@ -187,10 +240,16 @@ uint8_t Architecture::predecode(const void* ptr, uint16_t bytesAvailable,
Instruction newInsn(*this, metadataCache_.front());
// Set execution information for this instruction
newInsn.setExecutionInfo(getExecutionInfo(newInsn));

// Cache the instruction
iter = decodeCache_.insert({insn, newInsn}).first;
iter = decodeCache_.insert({insnEncoding, newInsn}).first;
}

assert(((insnEncoding & 0b11) != 0b11
? iter->second.getMetadata().getInsnLength() == 2
: iter->second.getMetadata().getInsnLength() == 4) &&
"Predicted number of bytes don't match disassembled number of bytes");

output.resize(1);
auto& uop = output[0];

Expand All @@ -199,7 +258,7 @@ uint8_t Architecture::predecode(const void* ptr, uint16_t bytesAvailable,

uop->setInstructionAddress(instructionAddress);

return 4;
return iter->second.getMetadata().getInsnLength();
}

int32_t Architecture::getSystemRegisterTag(uint16_t reg) const {
Expand Down Expand Up @@ -231,6 +290,8 @@ ProcessStateChange Architecture::getInitialState() const {

uint8_t Architecture::getMaxInstructionSize() const { return 4; }

uint8_t Architecture::getMinInstructionSize() const { return minInsnLength_; }

void Architecture::updateSystemTimerRegisters(RegisterFileSet* regFile,
const uint64_t iterations) const {
regFile->set(cycleSystemReg_, iterations);
Expand Down
5 changes: 3 additions & 2 deletions src/lib/arch/riscv/ExceptionHandler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -909,9 +909,10 @@ void ExceptionHandler::printException(const Instruction& insn) const {
<< insn.getInstructionAddress() << ": ";

auto& metadata = insn.getMetadata();
for (uint8_t byte : metadata.encoding) {
for (uint8_t byteIndex = 0; byteIndex < metadata.getInsnLength();
byteIndex++) {
std::cout << std::setfill('0') << std::setw(2)
<< static_cast<unsigned int>(byte) << " ";
<< static_cast<unsigned int>(metadata.encoding[byteIndex]) << " ";
}
std::cout << std::dec << " ";
if (exception == InstructionException::EncodingUnallocated) {
Expand Down
Loading