14ac1bedfSNick Fitzgerald //! Pulley opcodes (without operands). 24ac1bedfSNick Fitzgerald 34ac1bedfSNick Fitzgerald macro_rules! define_opcode { 44ac1bedfSNick Fitzgerald ( 54ac1bedfSNick Fitzgerald $( 64ac1bedfSNick Fitzgerald $( #[$attr:meta] )* 74ac1bedfSNick Fitzgerald $snake_name:ident = $name:ident $( { 84ac1bedfSNick Fitzgerald $( 94ac1bedfSNick Fitzgerald $( #[$field_attr:meta] )* 104ac1bedfSNick Fitzgerald $field:ident : $field_ty:ty 114ac1bedfSNick Fitzgerald ),* 124ac1bedfSNick Fitzgerald } )? ; 134ac1bedfSNick Fitzgerald )* 144ac1bedfSNick Fitzgerald ) => { 154ac1bedfSNick Fitzgerald /// An opcode without its immediates and operands. 164ac1bedfSNick Fitzgerald #[repr(u8)] 174ac1bedfSNick Fitzgerald #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 184ac1bedfSNick Fitzgerald pub enum Opcode { 194ac1bedfSNick Fitzgerald $( 204ac1bedfSNick Fitzgerald $( #[$attr] )* 214ac1bedfSNick Fitzgerald $name, 224ac1bedfSNick Fitzgerald )* 234ac1bedfSNick Fitzgerald /// The extended-op opcode. An `ExtendedOpcode` follows this opcode. 244ac1bedfSNick Fitzgerald ExtendedOp, 254ac1bedfSNick Fitzgerald } 264ac1bedfSNick Fitzgerald 274ac1bedfSNick Fitzgerald impl Opcode { 284ac1bedfSNick Fitzgerald /// The value of the maximum defined opcode. 290058cb78SAlex Crichton pub const MAX: u8 = Opcode::ExtendedOp as u8; 304ac1bedfSNick Fitzgerald } 31c1d405c1SAlex Crichton } 324ac1bedfSNick Fitzgerald } 334ac1bedfSNick Fitzgerald for_each_op!(define_opcode); 344ac1bedfSNick Fitzgerald 354ac1bedfSNick Fitzgerald impl Opcode { 364ac1bedfSNick Fitzgerald /// Create a new `Opcode` from the given byte. 374ac1bedfSNick Fitzgerald /// 384ac1bedfSNick Fitzgerald /// Returns `None` if `byte` is not a valid opcode. new(byte: u8) -> Option<Self>394ac1bedfSNick Fitzgerald pub fn new(byte: u8) -> Option<Self> { 404ac1bedfSNick Fitzgerald if byte <= Self::MAX { 414ac1bedfSNick Fitzgerald Some(unsafe { Self::unchecked_new(byte) }) 424ac1bedfSNick Fitzgerald } else { 434ac1bedfSNick Fitzgerald None 444ac1bedfSNick Fitzgerald } 454ac1bedfSNick Fitzgerald } 464ac1bedfSNick Fitzgerald 474ac1bedfSNick Fitzgerald /// Like `new` but does not check whether `byte` is a valid opcode. 484ac1bedfSNick Fitzgerald /// 494ac1bedfSNick Fitzgerald /// # Safety 504ac1bedfSNick Fitzgerald /// 514ac1bedfSNick Fitzgerald /// It is unsafe to pass a `byte` that is not a valid opcode. unchecked_new(byte: u8) -> Self524ac1bedfSNick Fitzgerald pub unsafe fn unchecked_new(byte: u8) -> Self { 534ac1bedfSNick Fitzgerald debug_assert!(byte <= Self::MAX); 54073aedabSAlex Crichton unsafe { core::mem::transmute(byte) } 554ac1bedfSNick Fitzgerald } 564ac1bedfSNick Fitzgerald } 574ac1bedfSNick Fitzgerald 584ac1bedfSNick Fitzgerald macro_rules! define_extended_opcode { 594ac1bedfSNick Fitzgerald ( 604ac1bedfSNick Fitzgerald $( 614ac1bedfSNick Fitzgerald $( #[$attr:meta] )* 624ac1bedfSNick Fitzgerald $snake_name:ident = $name:ident $( { $( $field:ident : $field_ty:ty ),* } )? ; 634ac1bedfSNick Fitzgerald )* 644ac1bedfSNick Fitzgerald ) => { 654ac1bedfSNick Fitzgerald /// An extended opcode. 664ac1bedfSNick Fitzgerald #[repr(u16)] 674ac1bedfSNick Fitzgerald #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 684ac1bedfSNick Fitzgerald pub enum ExtendedOpcode { 694ac1bedfSNick Fitzgerald $( 704ac1bedfSNick Fitzgerald $( #[$attr] )* 714ac1bedfSNick Fitzgerald $name, 724ac1bedfSNick Fitzgerald )* 734ac1bedfSNick Fitzgerald } 744ac1bedfSNick Fitzgerald 754ac1bedfSNick Fitzgerald impl ExtendedOpcode { 764ac1bedfSNick Fitzgerald /// The value of the maximum defined extended opcode. 77c1d405c1SAlex Crichton pub const MAX: u16 = $( 78c1d405c1SAlex Crichton if true { 1 } else { ExtendedOpcode::$name as u16 } + 79*56cae563SAlex Crichton )* 0 - 1; 804ac1bedfSNick Fitzgerald } 814ac1bedfSNick Fitzgerald }; 824ac1bedfSNick Fitzgerald } 834ac1bedfSNick Fitzgerald for_each_extended_op!(define_extended_opcode); 844ac1bedfSNick Fitzgerald 854ac1bedfSNick Fitzgerald impl ExtendedOpcode { 864ac1bedfSNick Fitzgerald /// Create a new `ExtendedOpcode` from the given bytes. 874ac1bedfSNick Fitzgerald /// 884ac1bedfSNick Fitzgerald /// Returns `None` if `bytes` is not a valid extended opcode. new(bytes: u16) -> Option<Self>894ac1bedfSNick Fitzgerald pub fn new(bytes: u16) -> Option<Self> { 904ac1bedfSNick Fitzgerald if bytes <= Self::MAX { 914ac1bedfSNick Fitzgerald Some(unsafe { Self::unchecked_new(bytes) }) 924ac1bedfSNick Fitzgerald } else { 934ac1bedfSNick Fitzgerald None 944ac1bedfSNick Fitzgerald } 954ac1bedfSNick Fitzgerald } 964ac1bedfSNick Fitzgerald 974ac1bedfSNick Fitzgerald /// Like `new` but does not check whether `bytes` is a valid opcode. 984ac1bedfSNick Fitzgerald /// 994ac1bedfSNick Fitzgerald /// # Safety 1004ac1bedfSNick Fitzgerald /// 1014ac1bedfSNick Fitzgerald /// It is unsafe to pass `bytes` that is not a valid opcode. unchecked_new(byte: u16) -> Self1024ac1bedfSNick Fitzgerald pub unsafe fn unchecked_new(byte: u16) -> Self { 1034ac1bedfSNick Fitzgerald debug_assert!(byte <= Self::MAX); 104073aedabSAlex Crichton unsafe { core::mem::transmute(byte) } 1054ac1bedfSNick Fitzgerald } 1064ac1bedfSNick Fitzgerald } 107*56cae563SAlex Crichton 108*56cae563SAlex Crichton #[cfg(test)] 109*56cae563SAlex Crichton mod tests { 110*56cae563SAlex Crichton use super::*; 111*56cae563SAlex Crichton 112*56cae563SAlex Crichton #[test] max_values()113*56cae563SAlex Crichton fn max_values() { 114*56cae563SAlex Crichton assert!(Opcode::new(Opcode::MAX).is_some()); 115*56cae563SAlex Crichton assert!(Opcode::new(Opcode::MAX + 1).is_none()); 116*56cae563SAlex Crichton assert!(ExtendedOpcode::new(ExtendedOpcode::MAX).is_some()); 117*56cae563SAlex Crichton assert!(ExtendedOpcode::new(ExtendedOpcode::MAX + 1).is_none()); 118*56cae563SAlex Crichton } 119*56cae563SAlex Crichton } 120