1 //! Pulley opcodes (without operands). 2 3 macro_rules! define_opcode { 4 ( 5 $( 6 $( #[$attr:meta] )* 7 $snake_name:ident = $name:ident $( { 8 $( 9 $( #[$field_attr:meta] )* 10 $field:ident : $field_ty:ty 11 ),* 12 } )? ; 13 )* 14 ) => { 15 /// An opcode without its immediates and operands. 16 #[repr(u8)] 17 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 18 pub enum Opcode { 19 $( 20 $( #[$attr] )* 21 $name, 22 )* 23 /// The extended-op opcode. An `ExtendedOpcode` follows this opcode. 24 ExtendedOp, 25 } 26 27 impl Opcode { 28 /// The value of the maximum defined opcode. 29 pub const MAX: u8 = Opcode::ExtendedOp as u8; 30 } 31 }; 32 33 ( @max $x:ident ) => { 0 }; 34 ( @max $x:ident $( $xs:ident )* ) => { 1 + define_opcode!(@max $( $xs )* ) }; 35 } 36 for_each_op!(define_opcode); 37 38 impl Opcode { 39 /// Create a new `Opcode` from the given byte. 40 /// 41 /// Returns `None` if `byte` is not a valid opcode. 42 pub fn new(byte: u8) -> Option<Self> { 43 if byte <= Self::MAX { 44 Some(unsafe { Self::unchecked_new(byte) }) 45 } else { 46 None 47 } 48 } 49 50 /// Like `new` but does not check whether `byte` is a valid opcode. 51 /// 52 /// # Safety 53 /// 54 /// It is unsafe to pass a `byte` that is not a valid opcode. 55 pub unsafe fn unchecked_new(byte: u8) -> Self { 56 debug_assert!(byte <= Self::MAX); 57 core::mem::transmute(byte) 58 } 59 } 60 61 macro_rules! define_extended_opcode { 62 ( 63 $( 64 $( #[$attr:meta] )* 65 $snake_name:ident = $name:ident $( { $( $field:ident : $field_ty:ty ),* } )? ; 66 )* 67 ) => { 68 /// An extended opcode. 69 #[repr(u16)] 70 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 71 pub enum ExtendedOpcode { 72 $( 73 $( #[$attr] )* 74 $name, 75 )* 76 } 77 78 impl ExtendedOpcode { 79 /// The value of the maximum defined extended opcode. 80 pub const MAX: u16 = define_opcode!( @max $( $name )* ) + 1; 81 } 82 }; 83 } 84 for_each_extended_op!(define_extended_opcode); 85 86 impl ExtendedOpcode { 87 /// Create a new `ExtendedOpcode` from the given bytes. 88 /// 89 /// Returns `None` if `bytes` is not a valid extended opcode. 90 pub fn new(bytes: u16) -> Option<Self> { 91 if bytes <= Self::MAX { 92 Some(unsafe { Self::unchecked_new(bytes) }) 93 } else { 94 None 95 } 96 } 97 98 /// Like `new` but does not check whether `bytes` is a valid opcode. 99 /// 100 /// # Safety 101 /// 102 /// It is unsafe to pass `bytes` that is not a valid opcode. 103 pub unsafe fn unchecked_new(byte: u16) -> Self { 104 debug_assert!(byte <= Self::MAX); 105 core::mem::transmute(byte) 106 } 107 } 108