IT WORKS HELL YEAH.

This commit is contained in:
2025-06-18 22:53:01 +01:00
parent 1210b19333
commit e281bc2d1d
26 changed files with 715 additions and 188 deletions
+31 -4
View File
@@ -81,7 +81,7 @@ impl TryFrom<u8> for Register {
type Error = RegisterParseError;
fn try_from(idx: u8) -> Result<Self, Self::Error> {
if idx > 0x18 {
if idx > 0x1C {
return Err(RegisterParseError::InvalidIndex(idx));
}
@@ -111,6 +111,11 @@ impl TryFrom<u8> for Register {
0x15 => Self::Mmr,
0x16 => Self::Zero,
0x17 => Self::NoReg,
0x18 => Self::Mar,
0x19 => Self::Mdr,
0x1A => Self::Sts,
0x1B => Self::Cir,
0x1C => Self::Pcx,
_ => unreachable!("This is already checked for in top `if` branch."),
})
}
@@ -145,6 +150,7 @@ impl TryFrom<&str> for Register {
"mmr" => Ok(Self::Mmr),
"zero" => Ok(Self::Zero),
"null" => Ok(Self::NoReg),
"pcx" => Ok(Self::Pcx),
_ => Err(RegisterParseError::InvalidName(value.to_string())),
}
}
@@ -248,6 +254,14 @@ pub enum Instruction {
Interrupt(Interrupt) = 0x22,
IntReturn = 0x23,
Halt = 0x24,
// Immediate Arithmetic
AddImmediate(args::ITypeArgs) = 0x25,
SubImmediate(args::ITypeArgs) = 0x26,
// Fake Instructions
Data(u32) = 0x3E,
Segment(u32) = 0x3F,
}
impl PartialEq for Instruction {
@@ -319,6 +333,10 @@ impl Instruction {
Self::Nand(_) => "nand",
Self::Nor(_) => "nor",
Self::Xnor(_) => "xnor",
Self::Data(_) => "data",
Self::AddImmediate(_) => "addi",
Self::SubImmediate(_) => "subi",
Self::Segment(_) => "[SEGMENT]",
}
}
@@ -355,7 +373,11 @@ impl std::fmt::Display for Instruction {
| Self::StoreByte(args)
| Self::StoreHalfword(args)
| Self::StoreWord(args) => {
write!(f, " {:x}({}), {}", args.immediate, args.r1, args.r2)
write!(
f,
" {}({:x}/{}), {}",
args.r1, args.immediate, args.immediate, args.r2
)
}
Self::Jump(args)
| Self::JumpEq(args)
@@ -364,10 +386,10 @@ impl std::fmt::Display for Instruction {
| Self::JumpGe(args)
| Self::JumpLt(args)
| Self::JumpLe(args) => {
write!(f, " ({:x}){}", args.immediate, args.r1)
write!(f, " 0x{:x}/{}({})", args.immediate, args.immediate, args.r1)
}
Self::LoadLowerImmediate(args) | Self::LoadUpperImmediate(args) => {
write!(f, " {}, {}, {}", args.immediate, args.r1, args.r2)
write!(f, " 0x{:x}, {}, {}", args.immediate, args.r1, args.r2)
}
Self::Compare(args) | Self::Not(args) => {
write!(f, " {}, {}", args.sr1, args.sr2)
@@ -388,6 +410,8 @@ impl std::fmt::Display for Instruction {
Self::Increment(a) | Self::Decrement(a) => write!(f, " {}", a.dr),
Self::Interrupt(a) => write!(f, " {}", a.as_u8()),
Self::Data(a) => write!(f, " {}", a),
Self::Segment(x) => write!(f, " [SEGMENT {}]", x),
_ => Ok(()),
}
}
@@ -439,6 +463,9 @@ impl TryFrom<u32> for Instruction {
0x22 => Ok(Self::Interrupt(Interrupt::from((data & 0xFF) as u8))),
0x23 => Ok(Self::IntReturn),
0x24 => Ok(Self::Halt),
0x25 => Ok(Self::AddImmediate(ITypeArgs::try_from(data)?)),
0x26 => Ok(Self::SubImmediate(ITypeArgs::try_from(data)?)),
0x3F => Ok(Self::Segment(data as u8 as u32)),
_ => Err(InstructionDecodeError::InvalidOpcode(opcode)),
}
}
+51
View File
@@ -155,3 +155,54 @@ impl TryFrom<u32> for RTypeArgs {
})
}
}
#[macro_export]
macro_rules! args {
// R-type arguments - allows omitting any field
(R $(, $field:ident: $value:expr)* $(,)?) => {{
let mut sr1: Option<Register> = None;
let mut sr2: Option<Register> = None;
let mut dr: Option<Register> = None;
let mut shamt: Option<u8> = None;
$(
args!(@assign_r_option sr1, sr2, dr, shamt, $field, $value);
)*
RTypeArgs::new(sr1, sr2, dr, shamt)
}};
// I-type arguments - requires immediate, allows omitting registers
(I, immediate: $immediate:expr $(, $field:ident: $value:expr)* $(,)?) => {{
let mut r1: Option<Register> = None;
let mut r2: Option<Register> = None;
$(
args!(@assign_i_option r1, r2, $field, $value);
)*
ITypeArgs::new($immediate, r1, r2)
}};
// Internal helpers (same as above for R-type)
(@assign_r_option $sr1:ident, $sr2:ident, $dr:ident, $shamt:ident, sr1, $value:expr) => {
$sr1 = Some($value);
};
(@assign_r_option $sr1:ident, $sr2:ident, $dr:ident, $shamt:ident, sr2, $value:expr) => {
$sr2 = Some($value);
};
(@assign_r_option $sr1:ident, $sr2:ident, $dr:ident, $shamt:ident, dr, $value:expr) => {
$dr = Some($value);
};
(@assign_r_option $sr1:ident, $sr2:ident, $dr:ident, $shamt:ident, shamt, $value:expr) => {
$shamt = Some($value);
};
// Internal helpers for I-type (without immediate handling)
(@assign_i_option $r1:ident, $r2:ident, r1, $value:expr) => {
$r1 = Some($value);
};
(@assign_i_option $r1:ident, $r2:ident, r2, $value:expr) => {
$r2 = Some($value);
};
}
+8 -2
View File
@@ -49,11 +49,17 @@ impl Encode for Instruction {
StoreWord, LoadLowerImmediate, LoadUpperImmediate, Jump,
JumpEq, JumpNeq, JumpGt, JumpGe, JumpLt, JumpLe, Compare,
Add, Sub, Increment, Decrement, ShiftLeft, ShiftRight,
And, Or, Not, Xor, Nand, Nor, Xnor
And, Or, Not, Xor, Nand, Nor, Xnor, AddImmediate, SubImmediate
],
no_args: [Nop, IntReturn, Halt],
special: [
Self::Interrupt(_) => todo!()
Self::Interrupt(_) => todo!(),
Self::Data(data) => data,
Self::Segment(segment) => {
let opcode = u32::from(self.opcode());
let segment = segment as u8;
(opcode << 26) | (segment as u32)
}
]
)
}