-
Notifications
You must be signed in to change notification settings - Fork 407
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move Instruction-Related Types into New Common Module (#61)
* Move Instruction-Related Types into New Common Module * Non-Automatic Merge Fixes * Add Traits for CPU/Registers * Sam Comments II * Revert "Sam Comments II" to Remove Generic Errors This reverts commit f515ade66841d6e47403468420b318674e784eb3. * Sam Comments II - Separate Errors Version * Add Missing Files * Sam Comments III + Misc. Fixes * Sam Comments IV * Fix Test
- Loading branch information
Showing
61 changed files
with
1,022 additions
and
836 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
[package] | ||
name = "nexus-common" | ||
edition.workspace = true | ||
version.workspace = true | ||
authors.workspace = true | ||
homepage.workspace = true | ||
repository.workspace = true | ||
keywords.workspace = true | ||
categories.workspace = true | ||
publish.workspace = true | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
rrs-lib = { git = "https://github.com/GregAC/rrs/" } | ||
thiserror = "1.0" | ||
variant_count = "1.1" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
mod pc; | ||
mod registers; | ||
mod traits; | ||
|
||
pub use pc::PC; | ||
pub use registers::Registers; | ||
pub use traits::{InstructionExecutor, InstructionState, Processor}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] | ||
pub struct PC { | ||
pub value: u32, | ||
} | ||
|
||
impl PC { | ||
// Increment PC by 4 bytes (standard instruction length) | ||
pub fn step(&mut self) { | ||
self.value = self.value.wrapping_add(4); | ||
} | ||
|
||
// Branch: Add immediate value to PC | ||
pub fn branch(&mut self, imm: u32) { | ||
self.value = self.value.wrapping_add(sign_extension_branch(imm)); | ||
} | ||
|
||
// Jump and Link: Add immediate value to PC | ||
pub fn jal(&mut self, imm: u32) { | ||
self.value = self.value.wrapping_add(sign_extension_jal(imm)); | ||
} | ||
|
||
// Jump and Link Register: Set PC to rs1 + imm | ||
pub fn jalr(&mut self, rs1: u32, imm: u32) { | ||
self.value = rs1.wrapping_add(sign_extension_jalr(imm)); | ||
} | ||
} | ||
|
||
impl PartialEq<u32> for PC { | ||
fn eq(&self, other: &u32) -> bool { | ||
self.value == *other | ||
} | ||
} | ||
|
||
#[inline] | ||
const fn sign_extension(imm: u32, bits: u32) -> u32 { | ||
let mask = 1u32 << (bits - 1); | ||
let value = imm & ((1u32 << bits) - 1); // Ensure we only use the specified number of bits | ||
if value & mask != 0 { | ||
// If the sign bit is set, extend with 1s | ||
value | !((1u32 << bits) - 1) | ||
} else { | ||
// If the sign bit is not set, extend with 0s | ||
value | ||
} | ||
} | ||
|
||
// Sign extension for Branch (13-bit immediate) | ||
#[inline] | ||
const fn sign_extension_branch(imm: u32) -> u32 { | ||
sign_extension(imm, 13) | ||
} | ||
|
||
// Sign extension for JAL (21-bit immediate) | ||
#[inline] | ||
const fn sign_extension_jal(imm: u32) -> u32 { | ||
sign_extension(imm, 21) | ||
} | ||
|
||
// Sign extension for JALR (12-bit immediate) | ||
#[inline] | ||
const fn sign_extension_jalr(imm: u32) -> u32 { | ||
sign_extension(imm, 12) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
use std::{fmt::Display, ops::Index}; | ||
|
||
use crate::riscv::register::Register; | ||
|
||
pub trait Registers: Index<Register, Output = u32> + Display { | ||
fn read(&self, reg: Register) -> u32; | ||
fn write(&mut self, reg: Register, value: u32); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
use crate::{error::MemoryError, memory::MemoryProcessor, riscv::instruction::Instruction}; | ||
|
||
use super::{pc::PC, registers::Registers}; | ||
|
||
/// Interface that a CPU implementation must provide. | ||
pub trait Processor { | ||
/// Returns an immutable reference to the CPU registers. | ||
fn registers(&self) -> &impl Registers; | ||
|
||
/// Returns a mutable reference to the CPU registers. | ||
fn registers_mut(&mut self) -> &mut impl Registers; | ||
|
||
fn pc(&self) -> &PC; | ||
|
||
fn pc_mut(&mut self) -> &mut PC; | ||
} | ||
|
||
pub trait InstructionState { | ||
type Result; | ||
|
||
/// Executes the instruction's operation. | ||
/// | ||
/// This method performs the actual operation specified by the instruction, | ||
/// such as arithmetic, logical operations, or control flow changes. | ||
/// * `self` - The current instruction state. | ||
fn execute(&mut self); | ||
|
||
/// Performs memory access for load operations. | ||
/// | ||
/// # Arguments | ||
/// * `self` - The mutable current instruction state. | ||
/// * `memory` - Immutable reference to the memory subsystem. | ||
/// | ||
/// # Returns | ||
/// A `Result` indicating the outcome of the memory access operation. | ||
fn memory_read(&mut self, memory: &impl MemoryProcessor) -> Result<Self::Result, MemoryError>; | ||
|
||
/// Performs memory access for store operations. | ||
/// | ||
/// # Arguments | ||
/// * `self` - The immutable current instruction state. | ||
/// * `memory` - Mutable reference to the memory subsystem. | ||
/// | ||
/// # Returns | ||
/// A `Result` indicating the outcome of the memory access operation. | ||
fn memory_write(&self, memory: &mut impl MemoryProcessor) -> Result<Self::Result, MemoryError>; | ||
|
||
/// Updates the CPU state with the result of the instruction execution. | ||
/// | ||
/// This method writes back the results to registers or updates other CPU state as necessary. | ||
/// | ||
/// # Arguments | ||
/// * `self` - The current instruction state. | ||
/// * `cpu` - Mutable reference to the CPU state. | ||
fn write_back(&self, cpu: &mut impl Processor); | ||
} | ||
|
||
/// Trait defining the execution stages of a RISC-V instruction. | ||
/// | ||
/// This trait represents a simplified instruction cycle, excluding the fetch stage. | ||
/// It includes decode, execute, memory access, and write-back stages. | ||
pub trait InstructionExecutor { | ||
type InstructionState: InstructionState; | ||
|
||
/// Decodes the instruction and prepares operands. | ||
/// | ||
/// # Arguments | ||
/// * `ins` - The instruction to be decoded. | ||
/// * `regs` - The current state of the CPU registers. | ||
/// | ||
/// # Returns | ||
/// An `InstructionState` containing the decoded instruction information. | ||
fn decode(ins: &Instruction, regs: &impl Registers) -> Self::InstructionState; | ||
|
||
/// Evaluates the constructed executor | ||
/// | ||
/// # Arguments | ||
/// * `cpu` - Mutable reference to the CPU state. | ||
/// * `memory` - Immutable reference to the memory subsystem. | ||
/// * `ins` - The instruction to be decoded. | ||
/// | ||
/// # Returns | ||
/// A `Result` indicating the whether the instruction was executed successfully. | ||
fn evaluator( | ||
cpu: &mut impl Processor, | ||
memory: &mut impl MemoryProcessor, | ||
ins: &Instruction, | ||
) -> Result<(), MemoryError> { | ||
let mut executor: Self::InstructionState = Self::decode(ins, cpu.registers()); | ||
executor.memory_read(memory)?; | ||
executor.execute(); | ||
executor.memory_write(memory)?; | ||
executor.write_back(cpu); | ||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
use thiserror::Error; | ||
|
||
#[derive(Error, Debug, PartialEq)] | ||
pub enum MemoryError { | ||
// Cannot write unaligned memory | ||
#[error("Unaligned memory write: 0x{0:08X}")] | ||
UnalignedMemoryWrite(u32), | ||
|
||
// Cannot read unaligned memory | ||
#[error("Unaligned memory read: 0x{0:08X}")] | ||
UnalignedMemoryRead(u32), | ||
|
||
// Invalid memory access | ||
#[error("Invalid memory access: 0x{0:08X}")] | ||
InvalidMemoryAccess(u32), | ||
|
||
// Address calculation overflow | ||
#[error("Address calculation overflow")] | ||
AddressCalculationOverflow, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
mod memory; | ||
mod opcode; | ||
|
||
pub use memory::MemoryError; | ||
pub use opcode::OpcodeError; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
use thiserror::Error; | ||
|
||
use crate::riscv::Opcode; | ||
|
||
#[derive(Debug, Error, PartialEq)] | ||
pub enum OpcodeError { | ||
#[error("Cannot convert non-builtin opcode to BuiltinOpcode: {0}")] | ||
OpcodeNotBuiltin(Opcode), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
pub mod cpu; | ||
pub mod error; | ||
pub mod memory; | ||
pub mod riscv; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
pub mod traits; | ||
pub use traits::*; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.