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!() ] ) } }