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}