common: instruction encoding via macro and trait ugly hack works
This commit is contained in:
+65
-66
@@ -1,3 +1,5 @@
|
||||
use crate::common::instructions::encode::Encode;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Interrupt {
|
||||
Software(u8),
|
||||
@@ -124,35 +126,35 @@ impl TryFrom<u8> for Register {
|
||||
impl std::fmt::Display for Register {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Rg0 => write!(f, "Rg0"),
|
||||
Self::Rg1 => write!(f, "Rg1"),
|
||||
Self::Rg2 => write!(f, "Rg2"),
|
||||
Self::Rg3 => write!(f, "Rg3"),
|
||||
Self::Rg4 => write!(f, "Rg4"),
|
||||
Self::Rg5 => write!(f, "Rg5"),
|
||||
Self::Rg6 => write!(f, "Rg6"),
|
||||
Self::Rg7 => write!(f, "Rg7"),
|
||||
Self::Rg8 => write!(f, "Rg8"),
|
||||
Self::Rg9 => write!(f, "Rg9"),
|
||||
Self::Rga => write!(f, "Rga"),
|
||||
Self::Rgb => write!(f, "Rgb"),
|
||||
Self::Rgc => write!(f, "Rgc"),
|
||||
Self::Rgd => write!(f, "Rgd"),
|
||||
Self::Rge => write!(f, "Rge"),
|
||||
Self::Rgf => write!(f, "Rgf"),
|
||||
Self::Acc => write!(f, "Acc"),
|
||||
Self::Spr => write!(f, "Spr"),
|
||||
Self::Bpr => write!(f, "Bpr"),
|
||||
Self::Ret => write!(f, "Ret"),
|
||||
Self::Idr => write!(f, "Idr"),
|
||||
Self::Mmr => write!(f, "Mmr"),
|
||||
Self::Zero => write!(f, "Zero"),
|
||||
Self::NoReg => write!(f, "None"),
|
||||
Self::Mar => write!(f, "Mar"),
|
||||
Self::Mdr => write!(f, "Mdr"),
|
||||
Self::Sts => write!(f, "Sts"),
|
||||
Self::Cir => write!(f, "Cir"),
|
||||
Self::Pcx => write!(f, "Pcx"),
|
||||
Self::Rg0 => write!(f, "rg0"),
|
||||
Self::Rg1 => write!(f, "rg1"),
|
||||
Self::Rg2 => write!(f, "rg2"),
|
||||
Self::Rg3 => write!(f, "rg3"),
|
||||
Self::Rg4 => write!(f, "rg4"),
|
||||
Self::Rg5 => write!(f, "rg5"),
|
||||
Self::Rg6 => write!(f, "rg6"),
|
||||
Self::Rg7 => write!(f, "rg7"),
|
||||
Self::Rg8 => write!(f, "rg8"),
|
||||
Self::Rg9 => write!(f, "rg9"),
|
||||
Self::Rga => write!(f, "rga"),
|
||||
Self::Rgb => write!(f, "rgb"),
|
||||
Self::Rgc => write!(f, "rgc"),
|
||||
Self::Rgd => write!(f, "rgd"),
|
||||
Self::Rge => write!(f, "rge"),
|
||||
Self::Rgf => write!(f, "rgf"),
|
||||
Self::Acc => write!(f, "acc"),
|
||||
Self::Spr => write!(f, "spr"),
|
||||
Self::Bpr => write!(f, "bpr"),
|
||||
Self::Ret => write!(f, "ret"),
|
||||
Self::Idr => write!(f, "idr"),
|
||||
Self::Mmr => write!(f, "mmr"),
|
||||
Self::Zero => write!(f, "zero"),
|
||||
Self::NoReg => write!(f, "noreg"),
|
||||
Self::Mar => write!(f, "mar"),
|
||||
Self::Mdr => write!(f, "mdr"),
|
||||
Self::Sts => write!(f, "sts"),
|
||||
Self::Cir => write!(f, "cir"),
|
||||
Self::Pcx => write!(f, "pcx"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -180,6 +182,19 @@ impl ITypeArgs {
|
||||
}
|
||||
}
|
||||
|
||||
impl Encode for ITypeArgs {
|
||||
/// Encodes an I-type instruction from its fields. These must have some unused high-order
|
||||
/// bits set to 0 else the bit shifting logic gets fucked.
|
||||
fn encode(self, opcode: u8) -> u32 {
|
||||
let opcode = u32::from(opcode);
|
||||
let r1 = self.r1 as u32;
|
||||
let dr = self.r2 as u32;
|
||||
let immediate = u32::from(self.immediate);
|
||||
|
||||
(opcode << 26) | (r1 << 21) | (dr << 16) | immediate
|
||||
}
|
||||
}
|
||||
|
||||
/// Used by instructions not using immediates (besides 5 bit shift values).
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct RTypeArgs {
|
||||
@@ -213,6 +228,24 @@ impl RTypeArgs {
|
||||
}
|
||||
}
|
||||
|
||||
impl Encode for RTypeArgs {
|
||||
/// Encodes an R-type instruction from its fields. These must have unused high-order
|
||||
/// bits set to 0 else the bit shifting logic is fucked.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `shamt`: The amount to shift value (used only in shift instructions, otherwise 0).
|
||||
fn encode(self, opcode: u8) -> u32 {
|
||||
let opcode = u32::from(opcode);
|
||||
let sr1 = self.sr1 as u32;
|
||||
let sr2 = self.sr2 as u32;
|
||||
let dr = self.dr as u32;
|
||||
let shamt = u32::from(self.shamt);
|
||||
|
||||
(opcode << 26) | (sr1 << 21) | (sr2 << 16) | (dr << 11) | (shamt << 6)
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO: Turn argument tuples into simple structs like `TwoReg`, `TwoRegAndOff`
|
||||
/// etc just to make code a little cleaner.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
@@ -273,7 +306,6 @@ pub enum Instruction {
|
||||
Halt = 0x24,
|
||||
}
|
||||
|
||||
#[expect(clippy::missing_const_for_fn)]
|
||||
impl Instruction {
|
||||
/// Returns the opcode of an instruction.
|
||||
///
|
||||
@@ -288,42 +320,7 @@ impl Instruction {
|
||||
#[must_use]
|
||||
#[allow(unused)]
|
||||
pub fn encode(&self) -> u32 {
|
||||
// match self {
|
||||
// _ => todo!(),
|
||||
// }
|
||||
|
||||
// Note to Harry, I will finish this encode/decode shit in a few hours.
|
||||
|
||||
21
|
||||
}
|
||||
|
||||
/// Encodes an R-type instruction from its fields. These must have unused high-order
|
||||
/// bits set to 0 else the bit shifting logic is fucked.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `shamt`: The amount to shift value (used only in shift instructions, otherwise 0).
|
||||
#[must_use]
|
||||
pub const fn encode_r_type(opcode: u8, sr1: u8, sr2: u8, dr: u8, shamt: u8) -> u32 {
|
||||
let opcode = opcode as u32;
|
||||
let sr1 = sr1 as u32;
|
||||
let sr2 = sr2 as u32;
|
||||
let dr = dr as u32;
|
||||
let shamt = shamt as u32;
|
||||
|
||||
(opcode << 26) | (sr1 << 21) | (sr2 << 16) | (dr << 11) | (shamt << 6)
|
||||
}
|
||||
|
||||
/// Encodes an I-type instruction from its fields. These must have some unused high-order
|
||||
/// bits set to 0 else the bit shifting logic gets fucked.
|
||||
#[must_use]
|
||||
pub const fn encode_i_type(opcode: u8, sr1: u8, dr: u8, immediate: u16) -> u32 {
|
||||
let opcode = opcode as u32;
|
||||
let sr1 = sr1 as u32;
|
||||
let dr = dr as u32;
|
||||
let immediate = immediate as u32;
|
||||
|
||||
(opcode << 26) | (sr1 << 21) | (dr << 16) | immediate
|
||||
Encode::encode(*self, self.opcode())
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
@@ -407,3 +404,5 @@ impl std::fmt::Display for Instruction {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod encode;
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
use crate::common::instructions::Register;
|
||||
|
||||
use super::Instruction;
|
||||
|
||||
/// Not to be used directly, just call [`Instruction::encode`].
|
||||
pub trait Encode {
|
||||
fn encode(self, opcode: u8) -> u32;
|
||||
}
|
||||
|
||||
/// Encodes a zero argument instruction.
|
||||
fn encode_no_args(opcode: u8) -> u32 {
|
||||
let opcode = u32::from(opcode);
|
||||
let sr1 = Register::NoReg as u32;
|
||||
let sr2 = Register::NoReg as u32;
|
||||
let dr = Register::NoReg as u32;
|
||||
let shamt = 0;
|
||||
|
||||
(opcode << 26) | (sr1 << 21) | (sr2 << 16) | (dr << 11) | (shamt << 6)
|
||||
}
|
||||
|
||||
/// Expands to a match statement that calls encode on instructions that implement [`Encode`]:
|
||||
///
|
||||
/// # Usage
|
||||
///
|
||||
/// ```rs
|
||||
/// encode_instruction!(self, with_args: [...], no_args: [...], special: [...] )
|
||||
/// ```
|
||||
macro_rules! encode_instruction {
|
||||
($self:expr, with_args: [$($variant:ident),+ $(,)?], no_args: [$($no_arg_variant:ident),* $(,)?] $(, special: [$($special:pat => $body:expr),* $(,)?])?) => {
|
||||
match $self {
|
||||
$(
|
||||
Instruction::$variant(args) => args.encode($self.opcode()),
|
||||
)+
|
||||
$(
|
||||
Instruction::$no_arg_variant => encode_no_args($self.opcode()),
|
||||
)*
|
||||
$($(
|
||||
$special => $body,
|
||||
)*)?
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl Encode for Instruction {
|
||||
fn encode(self, _: u8) -> u32 {
|
||||
encode_instruction!(
|
||||
self,
|
||||
with_args: [
|
||||
Mov, MovSigned, LoadByte, LoadByteSigned, LoadHalfword,
|
||||
LoadHalfwordSigned, LoadWord, StoreByte, StoreHalfword,
|
||||
StoreWord, LoadLowerImmediate, LoadUpperImmediate, Jump,
|
||||
JumpEq, JumpNeq, JumpGt, JumpGe, JumpLt, JumpLe, Compare,
|
||||
Add, Sub, Increment, Decrement, ShiftLeft, ShiftRight,
|
||||
And, Or, Not, Xor, Nand, Nor, Xnor
|
||||
],
|
||||
no_args: [Nop, IntReturn, Halt],
|
||||
special: [
|
||||
Self::Interrupt(_) => todo!()
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user