common: instruction encoding via macro and trait ugly hack works
This commit is contained in:
@@ -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