vax_disassembler/
operand.rs

1//! # MACRO32 Operands
2
3use std::{
4    convert::TryFrom,
5    fmt::{self, Display, Formatter},
6    io::Read,
7};
8use crate::{
9    error::{Error, Result},
10    opcode::{AccessType, DataType, DataValue, ReadDataValue},
11};
12
13macro_rules! define_registers {
14    ($(($reg: ident, $value: expr),)+) => {
15        /// # VAX General Registers
16        ///
17        /// The VAX has 16 registers that are directly accessible by all instructions. There are 12
18        /// general purpose registers (`R0`-`R11`), two named regisers that can be used as general
19        /// purpose registers (`AP` (argument) and `FP` (frame pointer)), and two special purpose
20        /// registers (`SP` (stack pointer) and `PC` (program counter)).
21        ///
22        /// # Examples
23        ///
24        /// ```rust
25        /// use vax_disassembler::operand::Register;
26        ///
27        /// // All registers directly map to a u8 value.
28        $(
29            #[doc = concat!("assert_eq!(Register::", stringify!($reg), " as u8, ", stringify!($value), ");")]
30        )+
31        ///
32        /// // All u8 values map to the register based on the low 4 bits.
33        /// for byte in (0_u8..=0xF0).step_by(0x10) {
34        $(
35            #[doc = concat!("   assert_eq!(Register::", stringify!($reg), ", Register::from(byte + ", stringify!($value), "));")]
36        )+
37        /// }
38        /// ```
39        #[repr(u8)]
40        #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
41        pub enum Register {
42            $(
43            #[doc = concat!(" # The ", stringify!($reg), " Register")]
44            ///
45            /// ## Examples
46            ///
47            /// ```rust
48            /// use vax_disassembler::Register;
49            ///
50            /// for high_nibble in 0_u8..16 {
51            #[doc = concat!("    let operand_byte = (high_nibble << 4) + ", stringify!($value), ";")]
52            #[doc = concat!("    assert_eq!(Register::", stringify!($reg), ", Register::from(operand_byte));")]
53            /// }
54            /// ```
55            $reg = $value,
56            )+
57        }
58
59        impl From<u8> for Register {
60            /// Converts to this type from the input type.
61            ///
62            /// The general mode addressing formats (other than literal mode) consists of the
63            /// register number in bits 0-3 (the low nibble) and the addressing mode specifier bits
64            /// in bits 4-7 (the high nibble). `Register::from(u8)` will take bits 0-3 of the u8
65            /// value and return the `Register`.
66            ///
67            /// The register numbers are as follows:
68            ///
69            /// ```text
70            $(
71                #[doc = concat!(stringify!($reg), "\t=\t", stringify!($value))]
72            )+
73            /// ```
74            ///
75            /// ```rust
76            /// use vax_disassembler::operand::Register;
77            ///
78            $(
79                #[doc = concat!("assert_eq!(Register::", stringify!($reg), ", Register::from(", stringify!($value), "));")]
80            )+
81            /// // Verify that all values of u8 are covered.
82            /// for i in 16..=u8::MAX {
83            ///     let _ = Register::from(i);
84            /// }
85            /// ```
86            fn from(value: u8) -> Register {
87                match value & 0xF {
88                    $(
89                    $value => Register::$reg,
90                    )+
91                    _ => unreachable!()
92                }
93            }
94        }
95
96        impl Display for Register {
97            /// Formats the value using the given formatter.
98            ///
99            /// # Examples
100            ///
101            /// ```rust
102            /// use vax_disassembler::operand::Register;
103            ///
104            $(
105            #[doc = concat!("assert_eq!(&format!(\"{}\", Register::", stringify!($reg), "), \"",
106                stringify!($reg), "\");")]
107            )+
108            /// ```
109            fn fmt(&self, f: &mut Formatter) -> fmt::Result {
110                let text = match self {
111                    $(
112                    Register::$reg => stringify!($reg),
113                    )+
114                };
115                f.write_str(text)
116            }
117        }
118    };
119}
120
121define_registers! {
122    (R0, 0),
123    (R1, 1),
124    (R2, 2),
125    (R3, 3),
126    (R4, 4),
127    (R5, 5),
128    (R6, 6),
129    (R7, 7),
130    (R8, 8),
131    (R9, 9),
132    (R10, 10),
133    (R11, 11),
134    (AP, 12),
135    (FP, 13),
136    (SP, 14),
137    (PC, 15),
138}
139
140/// # VAX Operand Type
141///
142/// The operand type is the translation from the first byte to determine the addressing mode of the
143/// operand.
144#[derive(Copy, Clone, Debug, PartialEq, Eq)]
145pub enum OperandType {
146    #[doc = include_str!("doc/literal.txt")]
147    ///
148    /// ## Examples
149    ///
150    /// ```rust
151    /// # use vax_disassembler::operand::OperandType;
152    /// for literal in 0_u8..=63 {
153    ///     assert_eq!(OperandType::Literal(literal), OperandType::from(literal));
154    /// }
155    /// ```
156    Literal(u8),
157    #[doc = include_str!("doc/indexed.txt")]
158    ///
159    /// ## Examples
160    ///
161    /// ```rust
162    /// # use vax_disassembler::operand::{OperandType, Register};
163    /// for indexed in 0x40_u8..=0x4E {
164    ///     let reg = Register::from(indexed);
165    ///     assert_eq!(OperandType::Indexed(reg), OperandType::from(indexed));
166    /// }
167    /// ```
168    Indexed(Register),
169    #[doc = include_str!("doc/register.txt")]
170    ///
171    /// ## Examples
172    ///
173    /// ```rust
174    /// # use vax_disassembler::operand::{OperandType, Register};
175    /// for register in 0x50_u8..=0x5E {
176    ///     let reg = Register::from(register);
177    ///     assert_eq!(OperandType::Register(reg), OperandType::from(register));
178    /// }
179    /// ```
180    Register(Register),
181    #[doc = include_str!("doc/register_deferred.txt")]
182    ///
183    /// ## Examples
184    ///
185    /// ```rust
186    /// # use vax_disassembler::operand::{OperandType, Register};
187    /// for register_deferred in 0x60_u8..=0x6E {
188    ///     let reg = Register::from(register_deferred);
189    ///     assert_eq!(OperandType::RegisterDeferred(reg), OperandType::from(register_deferred));
190    /// }
191    /// ```
192    RegisterDeferred(Register),
193    #[doc = include_str!("doc/autodecrement.txt")]
194    ///
195    /// ## Examples
196    ///
197    /// ```rust
198    /// # use vax_disassembler::operand::{OperandType, Register};
199    /// for autodecrement in 0x70_u8..=0x7E {
200    ///     let reg = Register::from(autodecrement);
201    ///     assert_eq!(OperandType::AutoDecrement(reg), OperandType::from(autodecrement));
202    /// }
203    /// ```
204    AutoDecrement(Register),
205    #[doc = include_str!("doc/autoincrement.txt")]
206    ///
207    /// ## Examples
208    ///
209    /// ```rust
210    /// # use vax_disassembler::operand::{OperandType, Register};
211    /// for autoincrement in 0x80_u8..=0x8E {
212    ///     let reg = Register::from(autoincrement);
213    ///     assert_eq!(OperandType::AutoIncrement(reg), OperandType::from(autoincrement));
214    /// }
215    /// ```
216    AutoIncrement(Register),
217    #[doc = include_str!("doc/autoincrement_deferred.txt")]
218    ///
219    /// ## Examples
220    ///
221    /// ```rust
222    /// # use vax_disassembler::operand::{OperandType, Register};
223    /// for autoincrement_deferred in 0x90_u8..=0x9E {
224    ///     let reg = Register::from(autoincrement_deferred);
225    ///     assert_eq!(OperandType::AutoIncrementDeferred(reg),
226    ///         OperandType::from(autoincrement_deferred));
227    /// }
228    /// ```
229    AutoIncrementDeferred(Register),
230    #[doc = include_str!("doc/byte_displacement.txt")]
231    ///
232    /// ## Examples
233    ///
234    /// ```rust
235    /// # use vax_disassembler::operand::{OperandType, Register};
236    /// for byte_displacement in 0xA0_u8..=0xAF {
237    ///     let reg = Register::from(byte_displacement);
238    ///     assert_eq!(OperandType::ByteDisplacement(reg), OperandType::from(byte_displacement));
239    /// }
240    /// ```
241    ByteDisplacement(Register),
242    #[doc = include_str!("doc/byte_displacement_deferred.txt")]
243    ///
244    /// ## Examples
245    ///
246    /// ```rust
247    /// # use vax_disassembler::operand::{OperandType, Register};
248    /// for byte_displacement_deferred in 0xB0_u8..=0xBF {
249    ///     let reg = Register::from(byte_displacement_deferred);
250    ///     assert_eq!(OperandType::ByteDisplacementDeferred(reg),
251    ///         OperandType::from(byte_displacement_deferred));
252    /// }
253    /// ```
254    ByteDisplacementDeferred(Register),
255    #[doc = include_str!("doc/word_displacement.txt")]
256    ///
257    /// ## Examples
258    ///
259    /// ```rust
260    /// # use vax_disassembler::operand::{OperandType, Register};
261    /// for word_displacement in 0xC0_u8..=0xCF {
262    ///     let reg = Register::from(word_displacement);
263    ///     assert_eq!(OperandType::WordDisplacement(reg), OperandType::from(word_displacement));
264    /// }
265    /// ```
266    WordDisplacement(Register),
267    #[doc = include_str!("doc/word_displacement_deferred.txt")]
268    ///
269    /// ## Examples
270    ///
271    /// ```rust
272    /// # use vax_disassembler::operand::{OperandType, Register};
273    /// for word_displacement_deferred in 0xD0_u8..=0xDF {
274    ///     let reg = Register::from(word_displacement_deferred);
275    ///     assert_eq!(OperandType::WordDisplacementDeferred(reg),
276    ///         OperandType::from(word_displacement_deferred));
277    /// }
278    /// ```
279    WordDisplacementDeferred(Register),
280    #[doc = include_str!("doc/longword_displacement.txt")]
281    ///
282    /// ## Examples
283    ///
284    /// ```rust
285    /// # use vax_disassembler::operand::{OperandType, Register};
286    /// for longword_displacement in 0xE0_u8..=0xEF {
287    ///     let reg = Register::from(longword_displacement);
288    ///     assert_eq!(OperandType::LongwordDisplacement(reg),
289    ///         OperandType::from(longword_displacement));
290    /// }
291    /// ```
292    LongwordDisplacement(Register),
293    #[doc = include_str!("doc/longword_displacement_deferred.txt")]
294    ///
295    /// ## Examples
296    ///
297    /// ```rust
298    /// # use vax_disassembler::operand::{OperandType, Register};
299    /// for longword_displacement_deferred in 0xF0_u8..=0xFF {
300    ///     let reg = Register::from(longword_displacement_deferred);
301    ///     assert_eq!(OperandType::LongwordDisplacementDeferred(reg),
302    ///         OperandType::from(longword_displacement_deferred));
303    /// }
304    /// ```
305    LongwordDisplacementDeferred(Register),
306    #[doc = include_str!("doc/immediate.txt")]
307    ///
308    /// ## Examples
309    ///
310    /// ```rust
311    /// # use vax_disassembler::operand::{OperandType, Register};
312    /// assert_eq!(OperandType::Immediate, OperandType::from(0x8F));
313    /// ```
314    Immediate,
315    #[doc = include_str!("doc/absolute.txt")]
316    ///
317    /// ## Examples
318    ///
319    /// ```rust
320    /// # use vax_disassembler::operand::{OperandType, Register};
321    /// assert_eq!(OperandType::Absolute, OperandType::from(0x9F));
322    /// ```
323    Absolute,
324}
325
326impl From<u8> for OperandType {
327    fn from(value: u8) -> OperandType {
328        match value {
329            0x00..=0x3F => OperandType::Literal(value),
330            0x40..=0x4F => OperandType::Indexed(Register::from(value)),
331            0x50..=0x5F => OperandType::Register(Register::from(value)),
332            0x60..=0x6F => OperandType::RegisterDeferred(Register::from(value)),
333            0x70..=0x7F => OperandType::AutoDecrement(Register::from(value)),
334            0x80..=0x8E => OperandType::AutoIncrement(Register::from(value)),
335            0x8F => OperandType::Immediate,
336            0x90..=0x9E => OperandType::AutoIncrementDeferred(Register::from(value)),
337            0x9F => OperandType::Absolute,
338            0xA0..=0xAF => OperandType::ByteDisplacement(Register::from(value)),
339            0xB0..=0xBF => OperandType::ByteDisplacementDeferred(Register::from(value)),
340            0xC0..=0xCF => OperandType::WordDisplacement(Register::from(value)),
341            0xD0..=0xDF => OperandType::WordDisplacementDeferred(Register::from(value)),
342            0xE0..=0xEF => OperandType::LongwordDisplacement(Register::from(value)),
343            0xF0..=0xFF => OperandType::LongwordDisplacementDeferred(Register::from(value)),
344        }
345    }
346}
347
348/// # VAX Instruction Operand
349///
350/// This enum specifies all of the valid VAX instruction operands plus an undefined state.
351#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
352pub enum Operand {
353    /// # Undefined operand
354    ///
355    /// This is used as a placeholder for an operand that hasn't been defined yet. It is equivalent
356    /// to the None state without having to use `Option<Operand>` explicitly.
357    #[default]
358    Undefined,
359    #[doc = include_str!("doc/literal.txt")]
360    ///
361    /// ## Examples
362    ///
363    /// ```rust
364    /// use vax_disassembler::opcode::{AccessType, DataType};
365    /// use vax_disassembler::operand::{Operand, ReadOperand};
366    /// use std::io::Cursor;
367    ///
368    /// for literal in 0_u8..=63 {
369    ///     assert_eq!(Operand::Literal(literal),
370    ///         Cursor::new([literal])
371    ///             .read_operand(AccessType::Read, DataType::Byte).unwrap());
372    /// }
373    /// ```
374    Literal(u8),
375    #[doc = include_str!("doc/indexed.txt")]
376    ///
377    /// ## Examples
378    ///
379    /// ```rust
380    /// use vax_disassembler::opcode::{AccessType, DataType};
381    /// use vax_disassembler::operand::{IndexedOperand, Operand, ReadOperand, Register};
382    /// use std::io::Cursor;
383    ///
384    /// for indexed in 0x40_u8..=0x4E {
385    ///     let indexed_reg = Register::from(indexed);
386    ///     for register_deferred in 0x60_u8..=0x6E {
387    ///         let reg = Register::from(register_deferred);
388    ///         assert_eq!(Operand::Indexed(IndexedOperand::RegisterDeferred(reg), indexed_reg),
389    ///             Cursor::new([indexed, register_deferred])
390    ///                 .read_operand(AccessType::Read, DataType::Byte).unwrap());
391    ///     }
392    /// }
393    /// ```
394    Indexed(IndexedOperand, Register),
395    #[doc = include_str!("doc/register.txt")]
396    ///
397    /// ## Examples
398    ///
399    /// ```rust
400    /// use vax_disassembler::opcode::{AccessType, DataType};
401    /// use vax_disassembler::operand::{Operand, ReadOperand, Register};
402    /// use std::io::Cursor;
403    ///
404    /// for register in 0x50_u8..=0x5E {
405    ///     let reg = Register::from(register);
406    ///     assert_eq!(Operand::Register(reg),
407    ///         Cursor::new([register])
408    ///             .read_operand(AccessType::Read, DataType::Byte).unwrap());
409    /// }
410    /// ```
411    Register(Register),
412    #[doc = include_str!("doc/register_deferred.txt")]
413    ///
414    /// ## Examples
415    ///
416    /// ```rust
417    /// use vax_disassembler::opcode::{AccessType, DataType};
418    /// use vax_disassembler::operand::{Operand, ReadOperand, Register};
419    /// use std::io::Cursor;
420    ///
421    /// for register_deferred in 0x60_u8..=0x6E {
422    ///     let reg = Register::from(register_deferred);
423    ///     assert_eq!(Operand::RegisterDeferred(reg),
424    ///         Cursor::new([register_deferred])
425    ///             .read_operand(AccessType::Read, DataType::Byte).unwrap());
426    /// }
427    /// ```
428    RegisterDeferred(Register),
429    #[doc = include_str!("doc/autodecrement.txt")]
430    ///
431    /// ## Examples
432    ///
433    /// ```rust
434    /// use vax_disassembler::opcode::{AccessType, DataType};
435    /// use vax_disassembler::operand::{Operand, ReadOperand, Register};
436    /// use std::io::Cursor;
437    ///
438    /// for autodecrement in 0x70_u8..=0x7E {
439    ///     let reg = Register::from(autodecrement);
440    ///     assert_eq!(Operand::AutoDecrement(reg),
441    ///         Cursor::new([autodecrement])
442    ///             .read_operand(AccessType::Read, DataType::Byte).unwrap());
443    /// }
444    /// ```
445    AutoDecrement(Register),
446    #[doc = include_str!("doc/autoincrement.txt")]
447    ///
448    /// ## Examples
449    ///
450    /// ```rust
451    /// use vax_disassembler::opcode::{AccessType, DataType};
452    /// use vax_disassembler::operand::{Operand, ReadOperand, Register};
453    /// use std::io::Cursor;
454    ///
455    /// for autoincrement in 0x80_u8..=0x8E {
456    ///     let reg = Register::from(autoincrement);
457    ///     assert_eq!(Operand::AutoIncrement(reg),
458    ///         Cursor::new([autoincrement])
459    ///             .read_operand(AccessType::Read, DataType::Byte).unwrap());
460    /// }
461    /// ```
462    AutoIncrement(Register),
463    #[doc = include_str!("doc/autoincrement_deferred.txt")]
464    ///
465    /// ## Examples
466    ///
467    /// ```rust
468    /// use vax_disassembler::opcode::{AccessType, DataType};
469    /// use vax_disassembler::operand::{Operand, ReadOperand, Register};
470    /// use std::io::Cursor;
471    ///
472    /// for autoincrement_deferred in 0x90_u8..=0x9E {
473    ///     let reg = Register::from(autoincrement_deferred);
474    ///     assert_eq!(Operand::AutoIncrementDeferred(reg),
475    ///         Cursor::new([autoincrement_deferred])
476    ///             .read_operand(AccessType::Read, DataType::Byte).unwrap());
477    /// }
478    /// ```
479    AutoIncrementDeferred(Register),
480    #[doc = include_str!("doc/byte_displacement.txt")]
481    ///
482    /// ## Examples
483    ///
484    /// ```rust
485    /// use vax_disassembler::opcode::{AccessType, DataType};
486    /// use vax_disassembler::operand::{Operand, ReadOperand, Register};
487    /// use std::io::Cursor;
488    ///
489    /// const BYTE_OFFSETS: &[i8] = &[-128, -56, -1, 0, 20, 42, 127];
490    /// for byte_displacement in 0xA0_u8..=0xAF {
491    ///     let reg = Register::from(byte_displacement);
492    ///     for byte_offset in BYTE_OFFSETS.iter() {
493    ///         assert_eq!(Operand::ByteDisplacement(*byte_offset, reg),
494    ///             Cursor::new([byte_displacement, *byte_offset as u8])
495    ///                 .read_operand(AccessType::Read, DataType::Byte).unwrap());
496    ///     }
497    /// }
498    /// ```
499    ByteDisplacement(i8, Register),
500    #[doc = include_str!("doc/byte_displacement_deferred.txt")]
501    ///
502    /// ## Examples
503    ///
504    /// ```rust
505    /// use vax_disassembler::opcode::{AccessType, DataType};
506    /// use vax_disassembler::operand::{Operand, ReadOperand, Register};
507    /// use std::io::Cursor;
508    ///
509    /// const BYTE_OFFSETS: &[i8] = &[-128, -56, -1, 0, 20, 42, 127];
510    /// for byte_displacement_deferred in 0xB0_u8..=0xBF {
511    ///     let reg = Register::from(byte_displacement_deferred);
512    ///     for byte_offset in BYTE_OFFSETS.iter() {
513    ///         assert_eq!(Operand::ByteDisplacementDeferred(*byte_offset, reg),
514    ///             Cursor::new([byte_displacement_deferred, *byte_offset as u8])
515    ///                 .read_operand(AccessType::Read, DataType::Byte).unwrap());
516    ///     }
517    /// }
518    /// ```
519    ByteDisplacementDeferred(i8, Register),
520    #[doc = include_str!("doc/word_displacement.txt")]
521    ///
522    /// ## Examples
523    ///
524    /// ```rust
525    /// use vax_disassembler::opcode::{AccessType, DataType};
526    /// use vax_disassembler::operand::{Operand, ReadOperand, Register};
527    /// use std::io::Cursor;
528    ///
529    /// const WORD_OFFSETS: &[i16] = &[-32768, -23456, -9876, -129, 128, 5678, 12345, 32767];
530    /// for word_displacement in 0xC0_u8..=0xCF {
531    ///     let reg = Register::from(word_displacement);
532    ///     for word_offset in WORD_OFFSETS.iter() {
533    ///         let word_bytes = word_offset.to_le_bytes();
534    ///         assert_eq!(Operand::WordDisplacement(*word_offset, reg),
535    ///             Cursor::new([word_displacement, word_bytes[0], word_bytes[1]])
536    ///                 .read_operand(AccessType::Read, DataType::Byte).unwrap());
537    ///     }
538    /// }
539    /// ```
540    WordDisplacement(i16, Register),
541    #[doc = include_str!("doc/word_displacement_deferred.txt")]
542    ///
543    /// ## Examples
544    ///
545    /// ```rust
546    /// use vax_disassembler::opcode::{AccessType, DataType};
547    /// use vax_disassembler::operand::{Operand, ReadOperand, Register};
548    /// use std::io::Cursor;
549    ///
550    /// const WORD_OFFSETS: &[i16] = &[-32768, -23456, -9876, -129, 128, 5678, 12345, 32767];
551    /// for word_displacement_deferred in 0xD0_u8..=0xDF {
552    ///     let reg = Register::from(word_displacement_deferred);
553    ///     for word_offset in WORD_OFFSETS.iter() {
554    ///         let word_bytes = word_offset.to_le_bytes();
555    ///         assert_eq!(Operand::WordDisplacementDeferred(*word_offset, reg),
556    ///             Cursor::new([word_displacement_deferred, word_bytes[0], word_bytes[1]])
557    ///                 .read_operand(AccessType::Read, DataType::Byte).unwrap());
558    ///     }
559    /// }
560    /// ```
561    WordDisplacementDeferred(i16, Register),
562    #[doc = include_str!("doc/longword_displacement.txt")]
563    ///
564    /// ## Examples
565    ///
566    /// ```rust
567    /// use vax_disassembler::opcode::{AccessType, DataType};
568    /// use vax_disassembler::operand::{Operand, ReadOperand, Register};
569    /// use std::io::Cursor;
570    ///
571    /// const LONGWORD_OFFSETS: &[i32] = &[-2147483648, -12345678, -32769, 32768, 87654321, 2147483647];
572    /// for longword_displacement in 0xE0_u8..=0xEF {
573    ///     let reg = Register::from(longword_displacement);
574    ///     for longword_offset in LONGWORD_OFFSETS.iter() {
575    ///         let longword_bytes = longword_offset.to_le_bytes();
576    ///         assert_eq!(Operand::LongwordDisplacement(*longword_offset, reg),
577    ///             Cursor::new([
578    ///                 longword_displacement,
579    ///                 longword_bytes[0],
580    ///                 longword_bytes[1],
581    ///                 longword_bytes[2],
582    ///                 longword_bytes[3],
583    ///             ]).read_operand(AccessType::Read, DataType::Byte).unwrap());
584    ///     }
585    /// }
586    /// ```
587    LongwordDisplacement(i32, Register),
588    #[doc = include_str!("doc/longword_displacement_deferred.txt")]
589    ///
590    /// ## Examples
591    ///
592    /// ```rust
593    /// use vax_disassembler::opcode::{AccessType, DataType};
594    /// use vax_disassembler::operand::{Operand, ReadOperand, Register};
595    /// use std::io::Cursor;
596    ///
597    /// const LONGWORD_OFFSETS: &[i32] = &[-2147483648, -12345678, -32769, 32768, 87654321, 2147483647];
598    /// for longword_displacement_deferred in 0xF0_u8..=0xFF {
599    ///     let reg = Register::from(longword_displacement_deferred);
600    ///     for longword_offset in LONGWORD_OFFSETS.iter() {
601    ///         let longword_bytes = longword_offset.to_le_bytes();
602    ///         assert_eq!(Operand::LongwordDisplacementDeferred(*longword_offset, reg),
603    ///             Cursor::new([
604    ///                 longword_displacement_deferred,
605    ///                 longword_bytes[0],
606    ///                 longword_bytes[1],
607    ///                 longword_bytes[2],
608    ///                 longword_bytes[3],
609    ///             ]).read_operand(AccessType::Read, DataType::Byte).unwrap());
610    ///     }
611    /// }
612    /// ```
613    LongwordDisplacementDeferred(i32, Register),
614    #[doc = include_str!("doc/immediate.txt")]
615    ///
616    /// ## Examples
617    ///
618    /// ```rust
619    /// use vax_disassembler::opcode::{AccessType, DataType, DataValue};
620    /// use vax_disassembler::operand::{Operand, ReadOperand, Register};
621    /// use std::io::Cursor;
622    ///
623    /// const BYTES: [i8; 5] = [i8::MIN, -1, 64, 100, i8::MAX];
624    /// const WORDS: [i16; 5] = [i16::MIN, -129, 128, 23456, i16::MAX];
625    /// const LONGWORDS: [i32; 5] = [i32::MIN, -32769, 32768, 987654321, i32::MAX];
626    /// const QUADWORDS: [i64; 5] = [i64::MIN, -2147483649, 2147483648, 0xABCDEF123, i64::MAX];
627    /// for i in 0..5 {
628    ///     let byte_immediate = [0x8F, BYTES[i] as u8];
629    ///     assert_eq!(Operand::Immediate(DataValue::Byte(BYTES[i])),
630    ///         Cursor::new(byte_immediate)
631    ///             .read_operand(AccessType::Read, DataType::Byte).unwrap());
632    ///     let mut word_immediate = [0x8F, 0, 0];
633    ///     word_immediate[1..].copy_from_slice(&WORDS[i].to_le_bytes());
634    ///     assert_eq!(Operand::Immediate(DataValue::Word(WORDS[i])),
635    ///         Cursor::new(word_immediate)
636    ///             .read_operand(AccessType::Read, DataType::Word).unwrap());
637    ///     let mut longword_immediate = [0x8F, 0, 0, 0, 0];
638    ///     longword_immediate[1..].copy_from_slice(&LONGWORDS[i].to_le_bytes());
639    ///     assert_eq!(Operand::Immediate(DataValue::Longword(LONGWORDS[i])),
640    ///         Cursor::new(longword_immediate)
641    ///             .read_operand(AccessType::Read, DataType::Longword).unwrap());
642    ///     let mut quadword_immediate = [0x8F, 0, 0, 0, 0, 0, 0, 0, 0];
643    ///     quadword_immediate[1..].copy_from_slice(&QUADWORDS[i].to_le_bytes());
644    ///     assert_eq!(Operand::Immediate(DataValue::Quadword(QUADWORDS[i])),
645    ///         Cursor::new(quadword_immediate)
646    ///             .read_operand(AccessType::Read, DataType::Quadword).unwrap());
647    /// }
648    /// ```
649    Immediate(DataValue),
650    #[doc = include_str!("doc/absolute.txt")]
651    ///
652    /// ## Examples
653    ///
654    /// ```rust
655    /// use vax_disassembler::opcode::{AccessType, DataType};
656    /// use vax_disassembler::operand::{Operand, ReadOperand, Register};
657    /// use std::io::Cursor;
658    ///
659    /// const ADDRESSES: &[u32] = &[0x0, 0x200, 0x80000000, 0x81234567, 0xBFFFFFFF, 0xFFFFFFFF];
660    /// for address in ADDRESSES.iter() {
661    ///     let address_bytes = address.to_le_bytes();
662    ///     assert_eq!(Operand::Absolute(*address),
663    ///         Cursor::new([
664    ///             0x9F,
665    ///             address_bytes[0],
666    ///             address_bytes[1],
667    ///             address_bytes[2],
668    ///             address_bytes[3],
669    ///         ]).read_operand(AccessType::Read, DataType::Byte).unwrap());
670    /// }
671    /// ```
672    Absolute(u32),
673    /// # Branch
674    ///
675    /// This is a special mode determined by the operand's access type of branch. There is no
676    /// operand code, just a branch offset from the address after reading the offset value.
677    ///
678    /// ## Examples
679    ///
680    /// ```rust
681    /// use vax_disassembler::opcode::{AccessType, DataType, DataValue};
682    /// use vax_disassembler::operand::{Operand, ReadOperand, Register};
683    /// use std::io::Cursor;
684    ///
685    /// const BYTE_OFFSETS: [i8; 9] = [-128, -100, -39, -20, 0, 30, 42, 100, 127];
686    /// const WORD_OFFSETS: [i16; 9] = [-32768, -23456, -1234, -129, 128, 512, 1234, 23456, 32767];
687    /// for i in 0..9 {
688    ///     let word_bytes = WORD_OFFSETS[i].to_le_bytes();
689    ///     assert_eq!(Operand::Branch(DataValue::Byte(BYTE_OFFSETS[i])),
690    ///         Cursor::new([BYTE_OFFSETS[i] as u8])
691    ///             .read_operand(AccessType::Branch, DataType::Byte).unwrap());
692    ///     assert_eq!(Operand::Branch(DataValue::Word(WORD_OFFSETS[i])),
693    ///         Cursor::new(word_bytes)
694    ///             .read_operand(AccessType::Branch, DataType::Word).unwrap());
695    /// }
696    /// ```
697    Branch(DataValue),
698}
699
700/// # VAX Instruction Indexed Operand
701///
702/// This enum specifies all of the valid VAX instruction operands that can be part of an indexed
703/// addressing mode.
704#[derive(Copy, Clone, Debug, PartialEq, Eq)]
705pub enum IndexedOperand {
706    #[doc = include_str!("doc/register_deferred.txt")]
707    ///
708    /// ## Examples
709    ///
710    /// ```rust
711    /// use vax_disassembler::opcode::{AccessType, DataType};
712    /// use vax_disassembler::operand::{IndexedOperand, Operand, ReadOperand, Register};
713    /// use std::io::Cursor;
714    ///
715    /// for indexed in 0x40_u8..=0x4E {
716    ///     let indexed_reg = Register::from(indexed);
717    ///     for register_deferred in 0x60_u8..=0x6E {
718    ///         let reg = Register::from(register_deferred);
719    ///         assert_eq!(Operand::Indexed(IndexedOperand::RegisterDeferred(reg), indexed_reg),
720    ///             Cursor::new([indexed, register_deferred])
721    ///                 .read_operand(AccessType::Read, DataType::Byte).unwrap());
722    ///     }
723    /// }
724    /// ```
725    RegisterDeferred(Register),
726    #[doc = include_str!("doc/autodecrement.txt")]
727    ///
728    /// ## Examples
729    ///
730    /// ```rust
731    /// use vax_disassembler::opcode::{AccessType, DataType};
732    /// use vax_disassembler::operand::{IndexedOperand, Operand, ReadOperand, Register};
733    /// use std::io::Cursor;
734    ///
735    /// for indexed in 0x40_u8..=0x4E {
736    ///     let indexed_reg = Register::from(indexed);
737    ///     for autodecrement in 0x70_u8..=0x7E {
738    ///         let reg = Register::from(autodecrement);
739    ///         if indexed_reg != reg {
740    ///             assert_eq!(Operand::Indexed(IndexedOperand::AutoDecrement(reg), indexed_reg),
741    ///                 Cursor::new([indexed, autodecrement])
742    ///                     .read_operand(AccessType::Read, DataType::Byte).unwrap());
743    ///         }
744    ///     }
745    /// }
746    /// ```
747    AutoDecrement(Register),
748    #[doc = include_str!("doc/autoincrement.txt")]
749    ///
750    /// ## Examples
751    ///
752    /// ```rust
753    /// use vax_disassembler::opcode::{AccessType, DataType};
754    /// use vax_disassembler::operand::{IndexedOperand, Operand, ReadOperand, Register};
755    /// use std::io::Cursor;
756    ///
757    /// for indexed in 0x40_u8..=0x4E {
758    ///     let indexed_reg = Register::from(indexed);
759    ///     for autoincrement in 0x80_u8..=0x8E {
760    ///         let reg = Register::from(autoincrement);
761    ///         if indexed_reg != reg {
762    ///             assert_eq!(Operand::Indexed(IndexedOperand::AutoIncrement(reg), indexed_reg),
763    ///                 Cursor::new([indexed, autoincrement])
764    ///                     .read_operand(AccessType::Read, DataType::Byte).unwrap());
765    ///         }
766    ///     }
767    /// }
768    /// ```
769    AutoIncrement(Register),
770    #[doc = include_str!("doc/autoincrement_deferred.txt")]
771    ///
772    /// ## Examples
773    ///
774    /// ```rust
775    /// use vax_disassembler::opcode::{AccessType, DataType};
776    /// use vax_disassembler::operand::{IndexedOperand, Operand, ReadOperand, Register};
777    /// use std::io::Cursor;
778    ///
779    /// for indexed in 0x40_u8..=0x4E {
780    ///     let indexed_reg = Register::from(indexed);
781    ///     for autoincrement_deferred in 0x90_u8..=0x9E {
782    ///         let reg = Register::from(autoincrement_deferred);
783    ///         if indexed_reg != reg {
784    ///             assert_eq!(Operand::Indexed(IndexedOperand::AutoIncrementDeferred(reg),
785    ///                 indexed_reg), Cursor::new([indexed, autoincrement_deferred])
786    ///                     .read_operand(AccessType::Read, DataType::Byte).unwrap());
787    ///         }
788    ///     }
789    /// }
790    /// ```
791    AutoIncrementDeferred(Register),
792    #[doc = include_str!("doc/byte_displacement.txt")]
793    ///
794    /// ## Examples
795    ///
796    /// ```rust
797    /// use vax_disassembler::opcode::{AccessType, DataType};
798    /// use vax_disassembler::operand::{IndexedOperand, Operand, ReadOperand, Register};
799    /// use std::io::Cursor;
800    ///
801    /// const BYTE_OFFSETS: &[i8] = &[-128, -56, -1, 0, 20, 42, 127];
802    /// for indexed in 0x40_u8..=0x4E {
803    ///     let indexed_reg = Register::from(indexed);
804    ///     for byte_displacement in 0xA0_u8..=0xAF {
805    ///         let reg = Register::from(byte_displacement);
806    ///         for byte_offset in BYTE_OFFSETS.iter() {
807    ///             assert_eq!(Operand::Indexed(
808    ///                 IndexedOperand::ByteDisplacement(*byte_offset, reg), indexed_reg),
809    ///                 Cursor::new([indexed, byte_displacement, *byte_offset as u8])
810    ///                     .read_operand(AccessType::Read, DataType::Byte).unwrap());
811    ///         }
812    ///     }
813    /// }
814    /// ```
815    ByteDisplacement(i8, Register),
816    #[doc = include_str!("doc/byte_displacement_deferred.txt")]
817    ///
818    /// ## Examples
819    ///
820    /// ```rust
821    /// use vax_disassembler::opcode::{AccessType, DataType};
822    /// use vax_disassembler::operand::{IndexedOperand, Operand, ReadOperand, Register};
823    /// use std::io::Cursor;
824    ///
825    /// const BYTE_OFFSETS: &[i8] = &[-128, -56, -1, 0, 20, 42, 127];
826    /// for indexed in 0x40_u8..=0x4E {
827    ///     let indexed_reg = Register::from(indexed);
828    ///     for byte_displacement_deferred in 0xB0_u8..=0xBF {
829    ///         let reg = Register::from(byte_displacement_deferred);
830    ///         for byte_offset in BYTE_OFFSETS.iter() {
831    ///             assert_eq!(Operand::Indexed(
832    ///                 IndexedOperand::ByteDisplacementDeferred(*byte_offset, reg), indexed_reg),
833    ///                 Cursor::new([indexed, byte_displacement_deferred, *byte_offset as u8])
834    ///                     .read_operand(AccessType::Read, DataType::Byte).unwrap());
835    ///         }
836    ///     }
837    /// }
838    /// ```
839    ByteDisplacementDeferred(i8, Register),
840    #[doc = include_str!("doc/word_displacement.txt")]
841    ///
842    /// ## Examples
843    ///
844    /// ```rust
845    /// use vax_disassembler::opcode::{AccessType, DataType};
846    /// use vax_disassembler::operand::{IndexedOperand, Operand, ReadOperand, Register};
847    /// use std::io::Cursor;
848    ///
849    /// const WORD_OFFSETS: &[i16] = &[-32768, -23456, -9876, -129, 128, 5678, 12345, 32767];
850    /// for indexed in 0x40_u8..=0x4E {
851    ///     let indexed_reg = Register::from(indexed);
852    ///     for word_displacement in 0xC0_u8..=0xCF {
853    ///         let reg = Register::from(word_displacement);
854    ///         for word_offset in WORD_OFFSETS.iter() {
855    ///             let word_bytes = word_offset.to_le_bytes();
856    ///             assert_eq!(Operand::Indexed(
857    ///                 IndexedOperand::WordDisplacement(*word_offset, reg), indexed_reg),
858    ///                 Cursor::new([indexed, word_displacement, word_bytes[0], word_bytes[1]])
859    ///                     .read_operand(AccessType::Read, DataType::Byte).unwrap());
860    ///         }
861    ///     }
862    /// }
863    /// ```
864    WordDisplacement(i16, Register),
865    #[doc = include_str!("doc/word_displacement_deferred.txt")]
866    ///
867    /// ## Examples
868    ///
869    /// ```rust
870    /// use vax_disassembler::opcode::{AccessType, DataType};
871    /// use vax_disassembler::operand::{IndexedOperand, Operand, ReadOperand, Register};
872    /// use std::io::Cursor;
873    ///
874    /// const WORD_OFFSETS: &[i16] = &[-32768, -23456, -9876, -129, 128, 5678, 12345, 32767];
875    /// for indexed in 0x40_u8..=0x4E {
876    ///     let indexed_reg = Register::from(indexed);
877    ///     for word_displacement_deferred in 0xD0_u8..=0xDF {
878    ///         let reg = Register::from(word_displacement_deferred);
879    ///         for word_offset in WORD_OFFSETS.iter() {
880    ///             let word_bytes = word_offset.to_le_bytes();
881    ///             assert_eq!(Operand::Indexed(
882    ///                 IndexedOperand::WordDisplacementDeferred(*word_offset, reg), indexed_reg),
883    ///                 Cursor::new([
884    ///                     indexed,
885    ///                     word_displacement_deferred,
886    ///                     word_bytes[0],
887    ///                     word_bytes[1],
888    ///                 ]).read_operand(AccessType::Read, DataType::Byte).unwrap());
889    ///         }
890    ///     }
891    /// }
892    /// ```
893    WordDisplacementDeferred(i16, Register),
894    #[doc = include_str!("doc/longword_displacement.txt")]
895    ///
896    /// ## Examples
897    ///
898    /// ```rust
899    /// use vax_disassembler::opcode::{AccessType, DataType};
900    /// use vax_disassembler::operand::{IndexedOperand, Operand, ReadOperand, Register};
901    /// use std::io::Cursor;
902    ///
903    /// const LONGWORD_OFFSETS: &[i32] = &[-2147483648, -12345678, -32769, 32768, 87654321, 2147483647];
904    /// for indexed in 0x40_u8..=0x4E {
905    ///     let indexed_reg = Register::from(indexed);
906    ///     for longword_displacement in 0xE0_u8..=0xEF {
907    ///         let reg = Register::from(longword_displacement);
908    ///         for longword_offset in LONGWORD_OFFSETS.iter() {
909    ///             let longword_bytes = longword_offset.to_le_bytes();
910    ///             assert_eq!(Operand::Indexed(
911    ///                 IndexedOperand::LongwordDisplacement(*longword_offset, reg), indexed_reg),
912    ///                 Cursor::new([
913    ///                     indexed,
914    ///                     longword_displacement,
915    ///                     longword_bytes[0],
916    ///                     longword_bytes[1],
917    ///                     longword_bytes[2],
918    ///                     longword_bytes[3],
919    ///                 ]).read_operand(AccessType::Read, DataType::Byte).unwrap());
920    ///         }
921    ///     }
922    /// }
923    /// ```
924    LongwordDisplacement(i32, Register),
925    #[doc = include_str!("doc/longword_displacement_deferred.txt")]
926    ///
927    /// ## Examples
928    ///
929    /// ```rust
930    /// use vax_disassembler::opcode::{AccessType, DataType};
931    /// use vax_disassembler::operand::{IndexedOperand, Operand, ReadOperand, Register};
932    /// use std::io::Cursor;
933    ///
934    /// const LONGWORD_OFFSETS: &[i32] = &[-2147483648, -12345678, -32769, 32768, 87654321, 2147483647];
935    /// for indexed in 0x40_u8..=0x4E {
936    ///     let indexed_reg = Register::from(indexed);
937    ///     for longword_displacement_deferred in 0xF0_u8..=0xFF {
938    ///         let reg = Register::from(longword_displacement_deferred);
939    ///         for longword_offset in LONGWORD_OFFSETS.iter() {
940    ///             let longword_bytes = longword_offset.to_le_bytes();
941    ///             assert_eq!(Operand::Indexed(
942    ///                 IndexedOperand::LongwordDisplacementDeferred(*longword_offset, reg), indexed_reg),
943    ///                 Cursor::new([
944    ///                     indexed,
945    ///                     longword_displacement_deferred,
946    ///                     longword_bytes[0],
947    ///                     longword_bytes[1],
948    ///                     longword_bytes[2],
949    ///                     longword_bytes[3],
950    ///                 ]).read_operand(AccessType::Read, DataType::Byte).unwrap());
951    ///         }
952    ///     }
953    /// }
954    /// ```
955    LongwordDisplacementDeferred(i32, Register),
956    #[doc = include_str!("doc/absolute.txt")]
957    ///
958    /// ## Examples
959    ///
960    /// ```rust
961    /// use vax_disassembler::opcode::{AccessType, DataType};
962    /// use vax_disassembler::operand::{IndexedOperand, Operand, ReadOperand, Register};
963    /// use std::io::Cursor;
964    ///
965    /// const ADDRESSES: &[u32] = &[0x0, 0x200, 0x80000000, 0x81234567, 0xBFFFFFFF, 0xFFFFFFFF];
966    /// for indexed in 0x40_u8..=0x4E {
967    ///     let indexed_reg = Register::from(indexed);
968    ///     for address in ADDRESSES.iter() {
969    ///         let address_bytes = address.to_le_bytes();
970    ///         assert_eq!(Operand::Indexed(IndexedOperand::Absolute(*address), indexed_reg),
971    ///             Cursor::new([
972    ///                 indexed,
973    ///                 0x9F,
974    ///                 address_bytes[0],
975    ///                 address_bytes[1],
976    ///                 address_bytes[2],
977    ///                 address_bytes[3],
978    ///             ]).read_operand(AccessType::Read, DataType::Byte).unwrap());
979    ///     }
980    /// }
981    /// ```
982    Absolute(u32),
983}
984
985impl TryFrom<Operand> for IndexedOperand {
986    type Error = Error;
987
988    fn try_from(operand: Operand) -> Result<IndexedOperand> {
989        match operand {
990            Operand::RegisterDeferred(reg) => Ok(IndexedOperand::RegisterDeferred(reg)),
991            Operand::AutoDecrement(reg) => Ok(IndexedOperand::AutoDecrement(reg)),
992            Operand::AutoIncrement(reg) => Ok(IndexedOperand::AutoIncrement(reg)),
993            Operand::AutoIncrementDeferred(reg) => Ok(IndexedOperand::AutoIncrementDeferred(reg)),
994            Operand::ByteDisplacement(value, reg) => Ok(IndexedOperand::ByteDisplacement(value, reg)),
995            Operand::ByteDisplacementDeferred(value, reg) => Ok(IndexedOperand::ByteDisplacementDeferred(value, reg)),
996            Operand::WordDisplacement(value, reg) => Ok(IndexedOperand::WordDisplacement(value, reg)),
997            Operand::WordDisplacementDeferred(value, reg) => Ok(IndexedOperand::WordDisplacementDeferred(value, reg)),
998            Operand::LongwordDisplacement(value, reg) => Ok(IndexedOperand::LongwordDisplacement(value, reg)),
999            Operand::LongwordDisplacementDeferred(value, reg) => Ok(IndexedOperand::LongwordDisplacementDeferred(value, reg)),
1000            // Immediate behavior is always unpredictable. I may support this in the future.
1001            //Operand::Immediate(value) => Ok(IndexedOperand::Immediate(value)),
1002            Operand::Absolute(value) => Ok(IndexedOperand::Absolute(value)),
1003            other => Err(Error::InvalidIndexedOperand(other)),
1004        }
1005    }
1006}
1007
1008impl From<IndexedOperand> for Operand {
1009    fn from(operand: IndexedOperand) -> Operand {
1010        match operand {
1011            IndexedOperand::RegisterDeferred(reg) => Operand::RegisterDeferred(reg),
1012            IndexedOperand::AutoDecrement(reg) => Operand::AutoDecrement(reg),
1013            IndexedOperand::AutoIncrement(reg) => Operand::AutoIncrement(reg),
1014            IndexedOperand::AutoIncrementDeferred(reg) => Operand::AutoIncrementDeferred(reg),
1015            IndexedOperand::ByteDisplacement(value, reg) => Operand::ByteDisplacement(value, reg),
1016            IndexedOperand::ByteDisplacementDeferred(value, reg) => Operand::ByteDisplacementDeferred(value, reg),
1017            IndexedOperand::WordDisplacement(value, reg) => Operand::WordDisplacement(value, reg),
1018            IndexedOperand::WordDisplacementDeferred(value, reg) => Operand::WordDisplacementDeferred(value, reg),
1019            IndexedOperand::LongwordDisplacement(value, reg) => Operand::LongwordDisplacement(value, reg),
1020            IndexedOperand::LongwordDisplacementDeferred(value, reg) => Operand::LongwordDisplacementDeferred(value, reg),
1021            // Immediate behavior is always unpredictable. I may support this in the future.
1022            //IndexedOperand::Immediate(value) => Operand::Immediate(value),
1023            IndexedOperand::Absolute(value) => Operand::Absolute(value),
1024        }
1025    }
1026}
1027
1028fn display_no_pc<T: Display>(f: &mut Formatter, lead: &str, value: T, reg: &Register) -> fmt::Result {
1029    if &Register::PC == reg {
1030        write!(f, "{}{}", lead, value)
1031    }
1032    else {
1033        write!(f, "{}{}({})", lead, value, reg)
1034    }
1035}
1036
1037impl Display for Operand {
1038    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1039        use Operand::*;
1040        match self {
1041            Undefined => f.write_str("Error: Undefined Operand"),
1042            Literal(value) => write!(f, "S^#{}", value),
1043            Indexed(operand, reg) => write!(f, "{}[{}]", operand, reg),
1044            Register(reg) => write!(f, "{}", reg),
1045            RegisterDeferred(reg) => write!(f, "({})", reg),
1046            AutoDecrement(reg) => write!(f, "-({0})", reg),
1047            AutoIncrement(reg) => write!(f, "({0})+", reg),
1048            AutoIncrementDeferred(reg) => write!(f, "@({0})+", reg),
1049            ByteDisplacement(value, reg) => display_no_pc(f, "B^", value, reg),
1050            ByteDisplacementDeferred(value, reg) => display_no_pc(f, "@B^", value, reg),
1051            WordDisplacement(value, reg) => display_no_pc(f, "W^", value, reg),
1052            WordDisplacementDeferred(value, reg) => display_no_pc(f, "@W^", value, reg),
1053            LongwordDisplacement(value, reg) => display_no_pc(f, "L^", value, reg),
1054            LongwordDisplacementDeferred(value, reg) => display_no_pc(f, "@L^", value, reg),
1055            Immediate(value) => write!(f, "#{0}", value),
1056            Absolute(value) => write!(f, "@#{0}", value),
1057            Branch(value) => write!(f, "{0}", value),
1058        }
1059    }
1060}
1061
1062impl Display for IndexedOperand {
1063    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1064        Operand::from(*self).fmt(f)
1065    }
1066}
1067
1068/// Extends [`Read`] with a method to read a VAX operand ([`Operand`]).
1069///
1070/// # Examples
1071///
1072/// ```rust
1073/// use vax_disassembler::opcode::{AccessType, DataType, DataValue};
1074/// use vax_disassembler::operand::{Operand, ReadOperand};
1075/// use std::io::Cursor;
1076///
1077/// assert_eq!(Cursor::new([30]).read_operand(AccessType::Branch, DataType::Byte).unwrap(),
1078///     Operand::Branch(DataValue::Byte(30)));
1079///
1080/// for quadword in (i64::MIN..=i64::MAX).step_by(u64::MAX as usize / 241) {
1081///     let mut buffer = [0u8; 9];
1082///     buffer[0] = 0x8F;   // Immediate
1083///     buffer[1..].copy_from_slice(&quadword.to_le_bytes());
1084///     let mut reader = Cursor::new(buffer);
1085///     let data_value = reader.read_operand(AccessType::Read, DataType::Quadword).unwrap();
1086///     assert_eq!(data_value, Operand::Immediate(DataValue::Quadword(quadword)));
1087/// }
1088/// ```
1089pub trait ReadOperand: Read + ReadDataValue {
1090    /// Read in a `MACRO32` operand from a reader.
1091    ///
1092    /// # Examples
1093    ///
1094    /// ```rust
1095    /// use vax_disassembler::operand::{Operand, ReadOperand, Register};
1096    /// use vax_disassembler::opcode::{AccessType, DataType};
1097    /// use std::io::Read;
1098    ///
1099    /// for byte_branch in i8::MIN..=i8::MAX {
1100    ///     let mut reader = std::io::Cursor::new([byte_branch as u8]);
1101    ///     let output = reader.read_operand(AccessType::Branch, DataType::Byte).unwrap();
1102    /// }
1103    /// for literal in 0_u8..=63 {
1104    ///     let mut reader = std::io::Cursor::new([literal]);
1105    ///     let output = reader.read_operand(AccessType::Read, DataType::Byte).unwrap();
1106    ///     assert_eq!(Operand::Literal(literal), output);
1107    /// }
1108    /// for reg in 0x50..=0x5E {
1109    ///     let mut reader = std::io::Cursor::new([reg]);
1110    ///     let output = reader.read_operand(AccessType::Read, DataType::Word).unwrap();
1111    ///     assert_eq!(Operand::Register(Register::from(reg)), output);
1112    /// }
1113    /// ```
1114    fn read_operand(&mut self, access: AccessType, size: DataType) -> Result<Operand> {
1115        match access {
1116            AccessType::Branch => Ok(Operand::Branch(self.read_data_value(size)?)),
1117            _ => {
1118                let mut buf = [0; 1];
1119                self.read_exact(&mut buf)?;
1120                match OperandType::from(buf[0]) {
1121                    OperandType::Literal(lit) => Ok(Operand::Literal(lit)),
1122                    OperandType::Indexed(reg) =>
1123                        Ok(Operand::Indexed(IndexedOperand::try_from(self.read_operand(access, size)?)?, reg)),
1124                    OperandType::Register(reg) => Ok(Operand::Register(reg)),
1125                    OperandType::RegisterDeferred(reg) => Ok(Operand::RegisterDeferred(reg)),
1126                    OperandType::AutoDecrement(reg) => Ok(Operand::AutoDecrement(reg)),
1127                    OperandType::AutoIncrement(reg) => Ok(Operand::AutoIncrement(reg)),
1128                    OperandType::AutoIncrementDeferred(reg) =>
1129                        Ok(Operand::AutoIncrementDeferred(reg)),
1130                    OperandType::ByteDisplacement(reg) => {
1131                        let mut buf = [0; 1];
1132                        self.read_exact(&mut buf)?;
1133                        Ok(Operand::ByteDisplacement(buf[0] as i8, reg))
1134                    }
1135                    OperandType::ByteDisplacementDeferred(reg) => {
1136                        let mut buf = [0; 1];
1137                        self.read_exact(&mut buf)?;
1138                        Ok(Operand::ByteDisplacementDeferred(buf[0] as i8, reg))
1139                    }
1140                    OperandType::WordDisplacement(reg) => {
1141                        let mut buf = [0; 2];
1142                        self.read_exact(&mut buf)?;
1143                        Ok(Operand::WordDisplacement(i16::from_le_bytes(buf), reg))
1144                    }
1145                    OperandType::WordDisplacementDeferred(reg) => {
1146                        let mut buf = [0; 2];
1147                        self.read_exact(&mut buf)?;
1148                        Ok(Operand::WordDisplacementDeferred(i16::from_le_bytes(buf), reg))
1149                    }
1150                    OperandType::LongwordDisplacement(reg) => {
1151                        let mut buf = [0; 4];
1152                        self.read_exact(&mut buf)?;
1153                        Ok(Operand::LongwordDisplacement(i32::from_le_bytes(buf), reg))
1154                    }
1155                    OperandType::LongwordDisplacementDeferred(reg) => {
1156                        let mut buf = [0; 4];
1157                        self.read_exact(&mut buf)?;
1158                        Ok(Operand::LongwordDisplacementDeferred(i32::from_le_bytes(buf), reg))
1159                    }
1160                    OperandType::Immediate => Ok(Operand::Immediate(self.read_data_value(size)?)),
1161                    OperandType::Absolute => {
1162                        let mut buf = [0; 4];
1163                        self.read_exact(&mut buf)?;
1164                        Ok(Operand::Absolute(u32::from_le_bytes(buf)))
1165                    }
1166                }
1167            }
1168        }
1169    }
1170}
1171
1172/// All types that implement `Read` get methods defined in `ReadMacro32` for free.
1173impl<R: Read + ?Sized> ReadOperand for R {}
1174
1175#[cfg(test)]
1176mod tests {
1177    use super::*;
1178    use proptest::prelude::*;
1179
1180    // Get data_value() strategy.
1181    use crate::opcode::{
1182        WriteDataValue,
1183        data_value_tests::data_value,
1184    };
1185
1186    const OPTYP_STD: usize = 36;
1187    const OPTYP_LITERAL: usize = 8;
1188    const OPTYP_REGISTER: usize = 27;
1189    prop_compose! {
1190        fn operand_type(limit: usize)(select in 0..=limit) -> (AccessType, DataType) {
1191            match select {
1192    			 0 => (AccessType::Read, DataType::Byte),
1193    			 1 => (AccessType::Read, DataType::Word),
1194    			 2 => (AccessType::Read, DataType::Longword),
1195    			 3 => (AccessType::Read, DataType::Quadword),
1196    			 4 => (AccessType::Read, DataType::Octoword),
1197    			 5 => (AccessType::Read, DataType::Floating),
1198    			 6 => (AccessType::Read, DataType::Double),
1199    			 7 => (AccessType::Read, DataType::GFloating),
1200    			 8 => (AccessType::Read, DataType::HFloating),
1201    			 9 => (AccessType::Write, DataType::Byte),
1202    			10 => (AccessType::Write, DataType::Word),
1203    			11 => (AccessType::Write, DataType::Longword),
1204    			12 => (AccessType::Write, DataType::Quadword),
1205    			13 => (AccessType::Write, DataType::Octoword),
1206    			14 => (AccessType::Write, DataType::Floating),
1207    			15 => (AccessType::Write, DataType::Double),
1208    			16 => (AccessType::Write, DataType::GFloating),
1209    			17 => (AccessType::Write, DataType::HFloating),
1210    			18 => (AccessType::Modify, DataType::Byte),
1211    			19 => (AccessType::Modify, DataType::Word),
1212    			20 => (AccessType::Modify, DataType::Longword),
1213    			21 => (AccessType::Modify, DataType::Quadword),
1214    			22 => (AccessType::Modify, DataType::Octoword),
1215    			23 => (AccessType::Modify, DataType::Floating),
1216    			24 => (AccessType::Modify, DataType::Double),
1217    			25 => (AccessType::Modify, DataType::GFloating),
1218    			26 => (AccessType::Modify, DataType::HFloating),
1219    			27 => (AccessType::VariableBitField, DataType::Byte),
1220    			28 => (AccessType::Address, DataType::Byte),
1221    			29 => (AccessType::Address, DataType::Word),
1222    			30 => (AccessType::Address, DataType::Longword),
1223    			31 => (AccessType::Address, DataType::Quadword),
1224    			32 => (AccessType::Address, DataType::Octoword),
1225    			33 => (AccessType::Address, DataType::Floating),
1226    			34 => (AccessType::Address, DataType::Double),
1227    			35 => (AccessType::Address, DataType::GFloating),
1228    			36 => (AccessType::Address, DataType::HFloating),
1229    			 _ => (AccessType::Read, DataType::Byte),
1230            }
1231        }
1232    }
1233
1234    prop_compose! {
1235        fn literal()(
1236            literal in 0_u8..=63,
1237            (access, size) in operand_type(OPTYP_LITERAL),
1238        ) -> (Operand, Vec<u8>, AccessType, DataType) {
1239            (Operand::Literal(literal), vec![literal], access, size)
1240        }
1241    }
1242
1243    prop_compose! {
1244        fn register()(
1245            register in 0x50_u8..=0x5E,
1246            (access, size) in operand_type(OPTYP_REGISTER),
1247        ) -> (Operand, Vec<u8>, AccessType, DataType) {
1248            (Operand::Register(Register::from(register)), vec![register], access, size)
1249        }
1250    }
1251
1252    prop_compose! {
1253        fn register_deferred()(
1254            register in 0x60_u8..=0x6E,
1255            (access, size) in operand_type(OPTYP_STD),
1256        ) -> (Operand, Vec<u8>, AccessType, DataType) {
1257            (Operand::RegisterDeferred(Register::from(register)), vec![register], access, size)
1258        }
1259    }
1260
1261    prop_compose! {
1262        fn auto_decrement()(
1263            register in 0x70_u8..=0x7E,
1264            (access, size) in operand_type(OPTYP_STD),
1265        ) -> (Operand, Vec<u8>, AccessType, DataType) {
1266            (Operand::AutoDecrement(Register::from(register)), vec![register], access, size)
1267        }
1268    }
1269
1270    prop_compose! {
1271        fn auto_increment()(
1272            register in 0x80_u8..=0x8E,
1273            (access, size) in operand_type(OPTYP_STD),
1274        ) -> (Operand, Vec<u8>, AccessType, DataType) {
1275            (Operand::AutoIncrement(Register::from(register)), vec![register], access, size)
1276        }
1277    }
1278
1279    prop_compose! {
1280        fn auto_increment_deferred()(
1281            register in 0x90_u8..=0x9E,
1282            (access, size) in operand_type(OPTYP_STD),
1283        ) -> (Operand, Vec<u8>, AccessType, DataType) {
1284            (Operand::AutoIncrementDeferred(Register::from(register)), vec![register], access, size)
1285        }
1286    }
1287
1288    prop_compose! {
1289        fn byte_displacement()(
1290            register in 0xA0_u8..=0xAF,
1291            disp in i8::MIN..=i8::MAX,
1292            (access, size) in operand_type(OPTYP_STD),
1293        ) -> (Operand, Vec<u8>, AccessType, DataType) {
1294            (Operand::ByteDisplacement(disp, Register::from(register)), vec![register, disp as u8], access, size)
1295        }
1296    }
1297
1298    prop_compose! {
1299        fn byte_displacement_deferred()(
1300            register in 0xB0_u8..=0xBF,
1301            disp in i8::MIN..=i8::MAX,
1302            (access, size) in operand_type(OPTYP_STD),
1303        ) -> (Operand, Vec<u8>, AccessType, DataType) {
1304            (Operand::ByteDisplacementDeferred(disp, Register::from(register)), vec![register, disp as u8], access, size)
1305        }
1306    }
1307
1308    prop_compose! {
1309        fn word_displacement()(
1310            register in 0xC0_u8..=0xCF,
1311            disp in i16::MIN..=i16::MAX,
1312            (access, size) in operand_type(OPTYP_STD),
1313        ) -> (Operand, Vec<u8>, AccessType, DataType) {
1314            let mut buf = Vec::with_capacity(3);
1315            buf.push(register);
1316            buf.extend_from_slice(&disp.to_le_bytes());
1317            (Operand::WordDisplacement(disp, Register::from(register)), buf, access, size)
1318        }
1319    }
1320
1321    prop_compose! {
1322        fn word_displacement_deferred()(
1323            register in 0xD0_u8..=0xDF,
1324            disp in i16::MIN..=i16::MAX,
1325            (access, size) in operand_type(OPTYP_STD),
1326        ) -> (Operand, Vec<u8>, AccessType, DataType) {
1327            let mut buf = Vec::with_capacity(3);
1328            buf.push(register);
1329            buf.extend_from_slice(&disp.to_le_bytes());
1330            (Operand::WordDisplacementDeferred(disp, Register::from(register)), buf, access, size)
1331        }
1332    }
1333
1334    prop_compose! {
1335        fn longword_displacement()(
1336            register in 0xE0_u8..=0xEF,
1337            disp in i32::MIN..=i32::MAX,
1338            (access, size) in operand_type(OPTYP_STD),
1339        ) -> (Operand, Vec<u8>, AccessType, DataType) {
1340            let mut buf = Vec::with_capacity(5);
1341            buf.push(register);
1342            buf.extend_from_slice(&disp.to_le_bytes());
1343            (Operand::LongwordDisplacement(disp, Register::from(register)), buf, access, size)
1344        }
1345    }
1346
1347    prop_compose! {
1348        fn longword_displacement_deferred()(
1349            register in 0xF0_u8..=0xFF,
1350            disp in i32::MIN..=i32::MAX,
1351            (access, size) in operand_type(OPTYP_STD),
1352        ) -> (Operand, Vec<u8>, AccessType, DataType) {
1353            let mut buf = Vec::with_capacity(5);
1354            buf.push(register);
1355            buf.extend_from_slice(&disp.to_le_bytes());
1356            (Operand::LongwordDisplacementDeferred(disp, Register::from(register)), buf, access, size)
1357        }
1358    }
1359
1360    prop_compose! {
1361        fn absolute()(
1362            disp in u32::MIN..=u32::MAX,
1363            (access, size) in operand_type(OPTYP_STD),
1364        ) -> (Operand, Vec<u8>, AccessType, DataType) {
1365            let mut buf = Vec::with_capacity(5);
1366            buf.push(0x9F);
1367            buf.extend_from_slice(&disp.to_le_bytes());
1368            (Operand::Absolute(disp), buf, access, size)
1369        }
1370    }
1371
1372    fn indexable_operand() -> BoxedStrategy<(Operand, Vec<u8>, AccessType, DataType)> {
1373        prop_oneof![
1374            register_deferred(),
1375            auto_decrement(),
1376            auto_increment(),
1377            auto_increment_deferred(),
1378            byte_displacement(),
1379            byte_displacement_deferred(),
1380            word_displacement(),
1381            word_displacement_deferred(),
1382            longword_displacement(),
1383            longword_displacement_deferred(),
1384            absolute(),
1385        ].boxed()
1386    }
1387
1388    prop_compose! {
1389        fn indexed()(
1390            (i_operand, i_buf, access, size) in indexable_operand(),
1391            mut register in 0x40_u8..=0x4E,
1392        ) -> (Operand, Vec<u8>, AccessType, DataType) {
1393            let i_operand = match IndexedOperand::try_from(i_operand) {
1394                Ok(op) => op,
1395                // This should never happen. Default to basic operand.
1396                Err(_) => IndexedOperand::RegisterDeferred(Register::R0),
1397            };
1398            match i_operand {
1399                IndexedOperand::AutoDecrement(i_reg) |
1400                IndexedOperand::AutoIncrement(i_reg) |
1401                IndexedOperand::AutoIncrementDeferred(i_reg) => {
1402                    if i_reg == Register::from(register) {
1403                        // If index register is the same as the indexed register, wrap around to a
1404                        // different register.
1405                        if 0x4E == register {
1406                            register = 0x40;
1407                        }
1408                        else {
1409                            register += 1;
1410                        }
1411                    }
1412                }
1413                _ => {}
1414            }
1415            let mut buf = Vec::with_capacity(1 + i_buf.len());
1416            buf.push(register);
1417            buf.extend_from_slice(&i_buf);
1418            (Operand::Indexed(i_operand, Register::from(register)), buf, access, size)
1419        }
1420    }
1421
1422    prop_compose! {
1423        fn immediate()(
1424            value in data_value(),
1425        ) -> (Operand, Vec<u8>, AccessType, DataType) {
1426            let mut buf = Vec::new();
1427            buf.push(0x8F);
1428            let _ = buf.write_data_value(value); // Ignore any error.
1429            (Operand::Immediate(value), buf, AccessType::Read, value.data_type())
1430        }
1431    }
1432
1433    fn branch() -> impl Strategy<Value = (Operand, Vec<u8>, AccessType, DataType)> {
1434        prop_oneof![
1435            any::<i8>().prop_map(|x| (
1436                Operand::Branch(DataValue::Byte(x)),
1437                vec![x as u8],
1438                AccessType::Branch,
1439                DataType::Byte)),
1440        ]
1441    }
1442
1443    fn valid_operand() -> BoxedStrategy<(Operand, Vec<u8>, AccessType, DataType)> {
1444        prop_oneof![
1445            literal(),
1446            indexed(),
1447            register(),
1448            register_deferred(),
1449            auto_decrement(),
1450            auto_increment(),
1451            auto_increment_deferred(),
1452            byte_displacement(),
1453            byte_displacement_deferred(),
1454            word_displacement(),
1455            word_displacement_deferred(),
1456            longword_displacement(),
1457            longword_displacement_deferred(),
1458            immediate(),
1459            absolute(),
1460            branch(),
1461        ].boxed()
1462    }
1463
1464    proptest! {
1465        #[test]
1466        fn valid_read_operands((operand, input, access, size) in valid_operand()) {
1467            let mut reader = std::io::Cursor::new(input);
1468            prop_assert_eq!(reader.read_operand(access, size)?, operand);
1469        }
1470    }
1471}