From 39f183cb5ea8f5514a0010b9b9a43f2d449567cd Mon Sep 17 00:00:00 2001
From: iximeow <me@iximeow.net>
Date: Sun, 2 Jan 2022 00:01:55 -0800
Subject: document the crate

---
 src/armv7.rs     | 141 +++++++++++++++++++++-
 src/armv8/a64.rs | 356 ++++++++++++++++++++++++++++++++++++++++++-------------
 src/armv8/mod.rs |   1 +
 src/lib.rs       |  50 ++++++++
 4 files changed, 464 insertions(+), 84 deletions(-)

(limited to 'src')

diff --git a/src/armv7.rs b/src/armv7.rs
index 5f826ac..c2254a5 100644
--- a/src/armv7.rs
+++ b/src/armv7.rs
@@ -12,6 +12,10 @@ use yaxpeax_arch::{Arch, AddressDiff, Colorize, Decoder, LengthedInstruction, Re
 mod thumb;
 
 // opcode, s, w, cond
+/// a struct for the combined display of an opcode and possible suffixes.
+///
+/// this includes the opcode, its optional `.s` suffix, optional `.w` suffix, and condition code,
+/// if any.
 pub struct ConditionedOpcode(pub Opcode, pub bool, pub bool, pub ConditionCode);
 
 impl Display for ConditionedOpcode {
@@ -20,6 +24,9 @@ impl Display for ConditionedOpcode {
     }
 }
 
+/// a context impl to display `arm` instructions with no additional context (no symbol name
+/// information, offset names, etc). this impl results in `some_instruction.contextualize(...)`
+/// displaying an instruction the same way its `Display` impl would.
 pub struct NoContext;
 
 fn reg_name_colorize<Y: YaxColors>(reg: Reg, colors: &Y) -> impl fmt::Display {
@@ -850,6 +857,7 @@ impl Display for Opcode {
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 #[allow(non_camel_case_types)]
+#[allow(missing_docs)]
 pub enum Opcode {
     Invalid,
     /*
@@ -1088,6 +1096,8 @@ static DATA_PROCESSING_OPCODES: [Opcode; 16] = [
     Opcode::MVN
 ];
 
+/// a struct describiing a shifted register operand. this is primarily interesting in that it can
+/// be translated to a `RegShiftStyle` for further interpretation.
 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
 #[repr(transparent)]
 pub struct RegShift {
@@ -1103,26 +1113,37 @@ impl RegShift {
         }
     }
 
+    /// don't use this. it's for armv7 testing only.
+    #[doc(hidden)]
     pub fn from_raw(data: u16) -> Self {
         RegShift { data }
     }
 }
 
+/// an enum describing one of two ways a shifted register operand may be shifted.
 pub enum RegShiftStyle {
+    /// a register shifted by an immediate.
     RegImm(RegImmShift),
+    /// a register shifted by a register.
     RegReg(RegRegShift),
 }
 
+/// a register shifted by a register.
 #[repr(transparent)]
 pub struct RegRegShift {
     data: u16
 }
 
+/// the way a shift operation is carried out.
 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
 pub enum ShiftStyle {
+    /// left-shift the value, filling in zeroes.
     LSL = 0,
+    /// right-shift the value, filling in zeroes.
     LSR = 1,
+    /// arithmetic shift right, filling with the top bit of the value (sign-extending).
     ASR = 2,
+    /// rotate-right, filling with bits shifted out of the value.
     ROR = 3,
 }
 
@@ -1150,34 +1171,42 @@ impl ShiftStyle {
 }
 
 impl RegRegShift {
+    /// the general-purpose register, an amount to shift the shiftee.
     pub fn shifter(&self) -> Reg {
         Reg::from_u8((self.data >> 8) as u8 & 0b1111)
     }
+    /// the way in which this register is shifted.
     pub fn stype(&self) -> ShiftStyle {
         ShiftStyle::from((self.data >> 5) as u8 & 0b11)
     }
+    /// the general-purpose register to be shifted.
     pub fn shiftee(&self) -> Reg {
         Reg::from_u8(self.data as u8 & 0b1111)
     }
 }
 
+/// a register shifted by an immediate.
 #[repr(transparent)]
 pub struct RegImmShift {
     data: u16
 }
 
 impl RegImmShift {
+    /// the immediate this register is shifted by.
     pub fn imm(&self) -> u8 {
         (self.data >> 7) as u8 & 0b11111
     }
+    /// the way in which this register is shifted.
     pub fn stype(&self) -> ShiftStyle {
         ShiftStyle::from((self.data >> 5) as u8 & 0b11)
     }
+    /// the general-purpose register to be shifted.
     pub fn shiftee(&self) -> Reg {
         Reg::from_u8(self.data as u8 & 0b1111)
     }
 }
 
+/// a struct describing an `arm` register.
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 #[repr(transparent)]
 pub struct Reg {
@@ -1252,6 +1281,9 @@ impl Reg {
         }
     }
 
+    /// create a new `Reg` with the specified number.
+    ///
+    /// panics if `bits` is out of range (16 or above).
     pub fn from_u8(bits: u8) -> Reg {
         if bits > 0b1111 {
             panic!("register number out of range");
@@ -1260,11 +1292,13 @@ impl Reg {
         Reg { bits }
     }
 
+    /// get the number of this register. the returned value will be between 0 and 15.
     pub fn number(&self) -> u8 {
         self.bits
     }
 }
 
+/// a control register.
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 #[repr(transparent)]
 pub struct CReg {
@@ -1278,6 +1312,9 @@ impl Display for CReg {
 }
 
 impl CReg {
+    /// create a new `CReg` with the specified number.
+    ///
+    /// panics if `bits` is out of range (16 or above).
     pub fn from_u8(bits: u8) -> CReg {
         if bits > 0b1111 {
             panic!("register number out of range");
@@ -1286,6 +1323,7 @@ impl CReg {
         CReg { bits }
     }
 
+    /// get the number of this register. the returned value will be between 0 and 15.
     pub fn number(&self) -> u8 {
         self.bits
     }
@@ -1331,6 +1369,7 @@ impl Display for StatusRegMask {
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 #[allow(non_camel_case_types)]
+#[allow(missing_docs)]
 pub enum StatusRegMask {
     // Note 0b0000 is unused (as is 0b10000)
     CPSR_C = 0b0001,
@@ -1409,36 +1448,82 @@ impl StatusRegMask {
     }
 }
 
+/// an operand in an `arm` instruction.
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum Operand {
+    /// a general-purpose register.
     Reg(Reg),
+    /// a general-purpose register, with writeback. these generally imply an increment by width of
+    /// a memort operand, depending on the instruction.
     RegWBack(Reg, bool),
+    /// a list of registers specified as a bitmask from bits 0 to 15.
     RegList(u16),
+    /// a memory access, dereferencing a general-purpose register.
     RegDeref(Reg),
+    /// a memory access, dereferencing a shifted general-purpose register with register or
+    /// immediate offset.
     RegShift(RegShift),
+    /// a memory access of a register, post-indexed a register shifted by register or immediate.
+    /// the first bool indicates if the shifted-register is added or subtracted ot the base
+    /// register, while the second bool indicates if the resulting address is written back to the
+    /// base register.
     RegDerefPostindexRegShift(Reg, RegShift, bool, bool), // add/sub, wback
+    /// a memory access of a register, pre-indexed with a register shifted by register or
+    /// immediate. the first bool indicates if the shifted-register is added or subtracted ot the
+    /// base register, while the second bool indicates if the resulting address is written back to
+    /// the base register.
     RegDerefPreindexRegShift(Reg, RegShift, bool, bool), // add/sub, wback
+    /// a memory access of a register, post-indexed with an immediate. the first bool indicates if
+    /// the shifted-register is added or subtracted ot the base register, while the second bool
+    /// indicates if the resulting address is written back to the base register.
     RegDerefPostindexOffset(Reg, u16, bool, bool), // add/sub, wback
+    /// a memory access of a register, pre-indexed with an immediate. the first bool indicates if
+    /// the shifted-register is added or subtracted ot the base register, while the second bool
+    /// indicates if the resulting address is written back to the base register.
     RegDerefPreindexOffset(Reg, u16, bool, bool), // add/sub, wback
+    /// a memory access of a register, post-indexed with a register. the first bool indicates if the
+    /// shifted-register is added or subtracted ot the base register, while the second bool
+    /// indicates if the resulting address is written back to the base register.
     RegDerefPostindexReg(Reg, Reg, bool, bool), // add/sub, wback
+    /// a memory access of a register, pre-indexed with a register. the first bool indicates if the
+    /// shifted-register is added or subtracted ot the base register, while the second bool
+    /// indicates if the resulting address is written back to the base register.
     RegDerefPreindexReg(Reg, Reg, bool, bool), // add/sub, wback
+    /// a 12-bit immediate, stored in a `u16`.
     Imm12(u16),
+    /// a 32-bit immediate, stored in a `u32`.
     Imm32(u32),
+    /// a pc-relative branch, with 32-bit signed offset, left-shifted by 2.
     BranchOffset(i32),
+    /// a pc-relative branch, with 32-bit signed offset, left-shifted by 1.
     BranchThumbOffset(i32),
+    /// a coprocessor index.
     Coprocessor(u8),
+    /// a coprocessor option number.
     CoprocOption(u8),
+    /// an `arm` control register.
     CReg(CReg),
+    /// an `arm` banked register, either `usr` (general-purpose) bank or one of the alternate sets
+    /// of `arm` registers.
     BankedReg(Bank, Reg),
+    /// `spsr` in some `arm` register bank.
     BankedSPSR(Bank),
+    /// a mask of bits for the `spsr` register.
     StatusRegMask(StatusRegMask),
+    /// the `apsr` register.
     APSR,
+    /// the `spsr` register.
     SPSR,
+    /// the `cpsr` register.
     CPSR,
+    /// "no operand". since an instruction's `operands` array is always four entries, this is used
+    /// to fill space, if any, after recording an instruction's extant operands.
     Nothing,
 }
 
+/// a register bank for a register in `armv7` or below.
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
+#[allow(missing_docs)]
 pub enum Bank {
     Usr,
     Fiq,
@@ -1551,10 +1636,16 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Operand {
     }
 }
 
+/// a `armv7` or below instruction.
 #[derive(Debug, PartialEq, Eq)]
 pub struct Instruction {
+    /// the condition code for this instruction, defaults to `AL` if the instruction is
+    /// unconditional.
     pub condition: ConditionCode,
+    /// the opcode of this instruction.
     pub opcode: Opcode,
+    /// operands for the decoded instruction. operands are populated from index 0, to 1, 2, and 3.
+    /// operands from the instruction are non-`Operand::Nothing`.
     pub operands: [Operand; 4],
     /// does this instruction update flags, while variants that do not update flags exist?
     pub s: bool,
@@ -1566,14 +1657,28 @@ pub struct Instruction {
     pub thumb: bool,
 }
 
+/// the kinds of errors possibly encountered in trying to decode an `armv7` or below instruction.
 #[derive(Debug, PartialEq, Copy, Clone)]
 pub enum DecodeError {
+    /// the input was insufficient to decode a full instruction. for non-thumb instructions, this means
+    /// the input was not at least four bytes long. for thumb instructions, the input was either
+    /// not two bytes, or not four bytes, depending on how much the instruction would need.
     ExhaustedInput,
+    /// the instruction encodes an opcode that is not valid.
     InvalidOpcode,
+    /// the instruction encodes an operand that is not valid.
     InvalidOperand,
+    /// `yaxpeax-arm` doesn't know how to decode this, but it may be a valid instruction. the
+    /// instruction decoder is not complete, sorry. :(
+    ///
+    /// in practice this typically indicates some kinds of coprocessor instruction, or `ARMv7` SIMD
+    /// instruction.
     Incomplete,
+    /// the instruction includes reserved bits that were not set as required.
     Nonconforming,
+    /// the input encodes an instruction that is explicitly undefined.
     Undefined,
+    /// the input encodes an instruction with unpredictable behavior.
     Unpredictable,
 }
 
@@ -1641,18 +1746,23 @@ impl Instruction {
     fn set_s(&mut self, value: bool) {
         self.s = value;
     }
+    /// does this instruction set status flags?
     pub fn s(&self) -> bool { self.s }
     pub(crate) fn set_w(&mut self, value: bool) {
         self.thumb_w = value;
     }
+    /// was this instruction encoded in `thumb` mode and still 4 bytes, *and* requires a `.w`
+    /// suffix on the opcode?
     pub fn w(&self) -> bool { self.thumb_w }
     pub(crate) fn set_wide(&mut self, value: bool) {
         self.wide = value;
     }
+    /// was this instruction encoded in `thumb` mode and still 4 bytes?
     pub fn wide(&self) -> bool { self.wide }
     pub(crate) fn set_thumb(&mut self, value: bool) {
         self.thumb = value;
     }
+    /// was this instruction encoded in `thumb` mode?
     pub fn thumb(&self) -> bool { self.thumb }
 }
 
@@ -1769,7 +1879,9 @@ impl LengthedInstruction for Instruction {
     }
 }
 
+/// a condition code for am `armv7` or below instruction.
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[allow(missing_docs)]
 pub enum ConditionCode {
     EQ,
     NE,
@@ -1811,7 +1923,7 @@ impl Display for ConditionCode {
 }
 
 impl ConditionCode {
-    pub fn build(value: u8) -> ConditionCode {
+    fn build(value: u8) -> ConditionCode {
         match value {
             0b0000 => ConditionCode::EQ,
             0b0001 => ConditionCode::NE,
@@ -1918,6 +2030,14 @@ impl Default for ARMVersion {
 }
 
 // nothing checks/rejects by arm version yet, but.. soon....
+/// a struct with decode configuration for `ARMv7` and below. the same decoder is used for `thumb`
+/// and non-`thumb` modes, and the same instruction struct is used for decoded instructions in
+/// either mode.
+///
+/// NOTE: helper functions here create `InstDecoder` for specific revisions, extensions, or lack
+/// thereof, in the supported instruction set. `yaxpeax-arm` does not actually honor these settings
+/// yet. this means any `InstDecoder` will decode all known instructions through the latest `ARMv7`
+/// extensions.
 #[allow(unused)]
 #[derive(Debug)]
 pub struct InstDecoder {
@@ -1939,19 +2059,28 @@ impl Default for InstDecoder {
 }
 
 impl InstDecoder {
+    /// set the decoder to decoding in thumb mode as the specified bool provides; `true` means
+    /// "yes, decode in `thumb` mode", where `false` means to decode as a normal `arm` instruction.
     pub fn set_thumb_mode(&mut self, thumb: bool) {
         self.thumb = thumb;
     }
 
+    /// set the decoder to decoding in thumb mode as the specified bool provides; `true` means
+    /// "yes, decode in `thumb` mode", where `false` means to decode as a normal `arm` instruction.
+    ///
+    /// (this consumes and returns the `InstDecoder` to support use in chained calls.)`
     pub fn with_thumb_mode(mut self, thumb: bool) -> Self {
         self.set_thumb_mode(thumb);
         self
     }
 
+    /// initialize a new `arm` `InstDecoder` with default ("everything") support, but in `thumb`
+    /// mode.
     pub fn default_thumb() -> Self {
         Self::default().with_thumb_mode(true)
     }
 
+    /// create an `InstDecoder` that supports only instructions through to `ARMv4`.
     pub fn armv4() -> Self {
         Self {
             mode: DecodeMode::Any,
@@ -1961,6 +2090,7 @@ impl InstDecoder {
         }
     }
 
+    /// create an `InstDecoder` that supports only instructions through to `ARMv5`.
     pub fn armv5() -> Self {
         Self {
             mode: DecodeMode::Any,
@@ -1970,6 +2100,7 @@ impl InstDecoder {
         }
     }
 
+    /// create an `InstDecoder` that supports only instructions through to `ARMv6`.
     pub fn armv6() -> Self {
         Self {
             mode: DecodeMode::Any,
@@ -1979,6 +2110,7 @@ impl InstDecoder {
         }
     }
 
+    /// create an `InstDecoder` that supports only instructions through to `ARMv6t2`.
     pub fn armv6t2() -> Self {
         Self {
             mode: DecodeMode::Any,
@@ -1988,6 +2120,7 @@ impl InstDecoder {
         }
     }
 
+    /// create an `InstDecoder` that supports only instructions through to `ARMv6t2` in thumb mode.
     pub fn armv6t2_thumb() -> Self {
         Self {
             mode: DecodeMode::Any,
@@ -1997,6 +2130,7 @@ impl InstDecoder {
         }
     }
 
+    /// create an `InstDecoder` that supports only instructions through to `ARMv7`.
     pub fn armv7() -> Self {
         Self {
             mode: DecodeMode::Any,
@@ -2006,6 +2140,7 @@ impl InstDecoder {
         }
     }
 
+    /// create an `InstDecoder` that supports only instructions through to `ARMv7` in thumb mode.
     pub fn armv7_thumb() -> Self {
         Self {
             mode: DecodeMode::Any,
@@ -2015,6 +2150,7 @@ impl InstDecoder {
         }
     }
 
+    /// create an `InstDecoder` that supports only instructions through to `ARMv7ve`.
     pub fn armv7ve() -> Self {
         Self {
             mode: DecodeMode::Any,
@@ -2024,6 +2160,7 @@ impl InstDecoder {
         }
     }
 
+    /// create an `InstDecoder` that supports only instructions through to `ARMv7ve` in thumb mode.
     pub fn armv7ve_thumb() -> Self {
         Self {
             mode: DecodeMode::Any,
@@ -2033,6 +2170,7 @@ impl InstDecoder {
         }
     }
 
+    /// create an `InstDecoder` that supports only instructions through to `ARMv7vese`.
     pub fn armv7vese() -> Self {
         Self {
             mode: DecodeMode::Any,
@@ -3709,6 +3847,7 @@ impl Decoder<ARMv7> for InstDecoder {
     }
 }
 
+/// a struct with a summary of the `ARMv7` instruction set in an associated `impl Arch for ARMv7`.
 #[cfg_attr(feature="use-serde", derive(Serialize, Deserialize))]
 #[derive(Debug)]
 pub struct ARMv7;
diff --git a/src/armv8/a64.rs b/src/armv8/a64.rs
index 0ca7bff..dc7d399 100644
--- a/src/armv8/a64.rs
+++ b/src/armv8/a64.rs
@@ -161,11 +161,21 @@ mod docs {
     }
 }
 
+/// the kinds of errors possibly encountered in trying to decode an `aarch64` instruction
 #[derive(Debug, PartialEq, Copy, Clone)]
 pub enum DecodeError {
+    /// the input was insufficient to decode a full instruction. for `a64` instructions, this means
+    /// the input was not at least four bytes long.
     ExhaustedInput,
+    /// the instruction encodes an opcode that is not valid.
     InvalidOpcode,
+    /// the instruction encodes an operand that is not valid.
     InvalidOperand,
+    /// `yaxpeax-arm` doesn't know how to decode this, but it may be a valid instruction. the
+    /// instruction decoder is not complete, sorry. :(
+    ///
+    /// in practice this means that the instruction is likely either in the `SVE` or `SVE2`
+    /// additions.
     IncompleteDecoder,
 }
 
@@ -210,6 +220,9 @@ impl yaxpeax_arch::Instruction for Instruction {
     fn well_defined(&self) -> bool { true }
 }
 
+/// a context impl to display `a64` instructions with no additional context (no symbol name
+/// information, offset names, etc). this impl results in `some_instruction.contextualize(...)`
+/// displaying an instruction the same way its `Display` impl would.
 pub struct NoContext;
 
 impl <T: fmt::Write, Y: YaxColors> ShowContextual<u64, NoContext, T, Y> for Instruction {
@@ -218,10 +231,14 @@ impl <T: fmt::Write, Y: YaxColors> ShowContextual<u64, NoContext, T, Y> for Inst
     }
 }
 
+/// a struct with a summary of the `ARMv8`/`aarch64` instruction set in an associated `impl Arch
+/// for ARMv8`.
 #[cfg(feature="use-serde")]
 #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
 pub struct ARMv8 { }
 
+/// a struct with a summary of the `ARMv8`/`aarch64` instruction set in an associated `impl Arch
+/// for ARMv8`.
 #[cfg(not(feature="use-serde"))]
 #[derive(Copy, Clone, Debug)]
 pub struct ARMv8 { }
@@ -235,13 +252,31 @@ impl Arch for ARMv8 {
     type Operand = Operand;
 }
 
+/// a size marker for a register.
 #[derive(Copy, Clone, Debug, PartialEq)]
 #[repr(u8)]
-pub enum SizeCode { X, W }
+pub enum SizeCode {
+    /// an x-size (64-bits) register.
+    X,
+    /// a w-size (32-bits) register.
+    W
+}
 
+/// a size marker for a SIMD register, a full scalar size, or vector element size.
 #[derive(Copy, Clone, Debug, PartialEq)]
 #[repr(u8)]
-pub enum SIMDSizeCode { B, H, S, D, Q }
+pub enum SIMDSizeCode {
+    /// a byte (8-bits) scalar or element.
+    B,
+    /// a halfword (16-bits) scalar or element.
+    H,
+    /// a single(?) word (32-bits) scalar or element.
+    S,
+    /// a dword (64-bits) scalar or element.
+    D,
+    /// a qword (128-bits) scalar or element.
+    Q
+}
 
 impl SIMDSizeCode {
     fn width(&self) -> u16 {
@@ -265,10 +300,14 @@ impl SIMDSizeCode {
     }
 }
 
+/// an `aarch64` instruction.
 #[derive(Copy, Clone, Debug, PartialEq)]
 #[repr(C)]
 pub struct Instruction {
+    /// the operation of the decoded instruction.
     pub opcode: Opcode,
+    /// operands for the decoded instruction. operands are populated from index 0, to 1, 2, and 3.
+    /// operands from the instruction are non-`Operand::Nothing`.
     pub operands: [Operand; 4],
 }
 
@@ -1078,6 +1117,10 @@ impl Default for Instruction {
     }
 }
 
+/// a descriptor for the operation in a `sys` or `sysl` instruction.
+///
+/// there are two fields of interest, `op1` and `op2`. for a description of how to interpret these
+/// fields of the `sys{,l}` opcodes, consult the `ARM Reference Manual`.
 #[derive(Copy, Clone, Debug, PartialEq)]
 #[repr(transparent)]
 pub struct SysOps {
@@ -1091,10 +1134,12 @@ impl SysOps {
         }
     }
 
+    /// retrieve the `op1` field encoded in this `SysOps`.
     #[inline]
     pub fn op1(&self) -> u8 {
         self.data & 0b1111
     }
+    /// retrieve the `op2` field encoded in this `SysOps`.
     #[inline]
     pub fn op2(&self) -> u8 {
         (self.data >> 4) & 0b1111
@@ -1103,6 +1148,7 @@ impl SysOps {
 
 #[derive(Copy, Clone, Debug, PartialEq)]
 #[repr(u16)]
+#[allow(missing_docs)]
 pub enum Opcode {
     Invalid,
     MOVN,
@@ -2609,19 +2655,32 @@ impl Display for Opcode {
     }
 }
 
+/// the way a shift operation is carried out.
 #[derive(Copy, Clone, Debug, PartialEq)]
 pub enum ShiftStyle {
+    /// left-shift the value, filling in zeroes.
     LSL,
+    /// right-shift the value, filling in zeroes.
     LSR,
+    /// arithmetic shift right, filling with the top bit of the value (sign-extending).
     ASR,
+    /// rotate-right, filling with bits shifted out of the value.
     ROR,
+    /// unsigned extend byte to 64-bit word.
     UXTB,
+    /// unsigned extend half-word (16-bit) to 64-bit word.
     UXTH,
+    /// unsigned extend word (32-bit) to 64-bit word.
     UXTW,
+    /// unsigned extend 64-bit word to 64-bit word (functionally equivalent to left-shift).
     UXTX,
+    /// signed extend byte to 64-bit word.
     SXTB,
+    /// signed extend half-word (16-bit) to 64-bit word.
     SXTH,
+    /// signed extend word (32-bit) to 64-bit word.
     SXTW,
+    /// signed extend 64-bit word to 64-bit word (functionally equivalent to left-shift).
     SXTX,
 }
 
@@ -2644,37 +2703,179 @@ impl Display for ShiftStyle {
     }
 }
 
+/// an operand for an `aarch64` instruction.
+///
+/// an instruction's `operands` array allows many more combination of `Operand` than are possible
+/// in practice; no `aarch64` instruction has multiple `Operand::PCOffset` entries, for example.
 #[derive(Copy, Clone, Debug, PartialEq)]
 #[repr(C)]
 pub enum Operand {
+    /// "no operand". since an instruction's `operands` array is always four entries, this is used
+    /// to fill space, if any, after recording an instruction's extant operands.
     Nothing,
+    /// a general-purpose register.
+    ///
+    /// for example, `x5` would be represented as `Operand::Register(SizeCode::X, 5)`. the register
+    /// number currently does not extend beyond 31. `Operand::Register(_, 31)` is the zero
+    /// register, either `wzr` or `xzr`.
     Register(SizeCode, u16),
+    /// a general-purpose register.
+    ///
+    /// for example, `x5` would be represented as `Operand::Register(SizeCode::X, 5)`. the register
+    /// number ranges between 0 and 31. unlike `Operand::Register`, `Operand::Register(_, 31)` is
+    /// the stack pointer, either `wsp` or `xsp`.
     RegisterPair(SizeCode, u16),
+    /// a SIMD register, used as a scalar element.
+    ///
+    /// for example, `d3` would be represented as `Operand::SIMDRegister(SIMDSizeCode::D, 3)`. the
+    /// register number ranges between 0 and 31.
     SIMDRegister(SIMDSizeCode, u16),
+    /// a SIMD register, used as a vector of elements.
+    ///
+    /// for example, `v10.4h` would be represented as
+    /// `Operand::SIMDRegisterElements(SIMDSizeCode::D, 10, SIMDSizeCode::H)`.
+    ///
+    /// SIMD registers are either `SIMDSizeCode::Q` or `SIMDSizeCode::D` wide, and can have
+    /// elements of width `SIMDSizeCode::{B, H, S, D}`. the register number ranges between 0 and 31.
     SIMDRegisterElements(SIMDSizeCode, u16, SIMDSizeCode),
+    /// one lane in a SIMD vector of elements.
+    ///
+    /// for example, `v10.h[3]` would be represented as
+    /// `Operand::SIMDRegisterElementsLane(SIMDSizeCode::D, 10, SIMDSizeCode::H, 3)`.
+    ///
+    /// SIMD registers are either `SIMDSizeCode::Q` or `SIMDSizeCode::D` wide, and can have
+    /// elements of width `SIMDSizeCode::{B, H, S, D}`. the register number ranges between 0 and 31.
+    /// the lane number can range between 0 and `element.width() / vector.width()`.
     SIMDRegisterElementsLane(SIMDSizeCode, u16, SIMDSizeCode, u8),
+    /// multiple lanes in a SIMD vector of elements.
+    ///
+    /// for example, `v10.4h[3]` would be represented as
+    /// `Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, 10, SIMDSizeCode::H, 3, 4)`.
+    ///
+    /// SIMD registers are either `SIMDSizeCode::Q` or `SIMDSizeCode::D` wide, and can have
+    /// elements of width `SIMDSizeCode::{B, H, S, D}`. the register number ranges between 0 and 31.
+    /// the lane number can range between 0 and `element.width() / vector.width()`. the number of
+    /// elements is, in practice, always 4.
     SIMDRegisterElementsMultipleLane(SIMDSizeCode, u16, SIMDSizeCode, u8, u8),
+    /// multiple full SIMD vectors.
+    ///
+    /// for example, `{v2.2d, v3.2d, v4.2d}` would be represented as
+    /// `Operand::SIMDRegisterGroup(SIMDSizeCode::Q, 2, SIMDSizeCode::D, 3)`.
+    ///
+    /// SIMD registers are either `SIMDSizeCode::Q` or `SIMDSizeCode::D` wide, and can have
+    /// elements of width `SIMDSizeCode::{B, H, S, D}`. the register number ranges between 0 and 31.
+    /// the number of SIMD registers ranges from 1 to 4.
     SIMDRegisterGroup(SIMDSizeCode, u16, SIMDSizeCode, u8),
+    /// a lane in multiple SIMD vectors.
+    ///
+    /// for example, `{v2.2d, v3.2d, v4.2d}[1]` would be represented as
+    /// `Operand::SIMDRegisterGroup(SIMDSizeCode::Q, 2, SIMDSizeCode::D, 3, 1)`.
+    ///
+    /// SIMD registers are either `SIMDSizeCode::Q` or `SIMDSizeCode::D` wide, and can have
+    /// elements of width `SIMDSizeCode::{B, H, S, D}`. the register number ranges between 0 and 31.
+    /// the number of SIMD registers ranges from 1 to 4. the lane number can range between 0 and
+    /// `element.width() / vector.width()`.
     SIMDRegisterGroupLane(u16, SIMDSizeCode, u8, u8),
+    /// a general-purpose register, where register 31 is `sp`, rather than `zr`.
+    ///
+    /// for example, `x5` would be represented as `Operand::Register(SizeCode::X, 5)`. the register
+    /// number currently does not extend beyond 31. `Operand::Register(_, 31)` is the stack pointer
+    /// register, either `wsp` or `xsp`.
     RegisterOrSP(SizeCode, u16),
+    /// a condition code describing some comparison.
+    ///
+    /// there are 16 condition codes with number 0 to 15: `eq, hs, mi, vs, hi, ge, gt, al, ne, lo,
+    /// pl, vc, ls, lt, le, nv`. the `nv` condition code is identical to `al`, and only has a
+    /// different condition code number in encoded instructions.
     ConditionCode(u8),
-    Offset(i64),
+    /// a pc-relative offset.
+    ///
+    /// this is the addressing mode for instructions like, `bl $+0x1234`, or `adrp $-0x123000`.
     PCOffset(i64),
+    /// a 32-bit immediate.
+    ///
+    /// this immediate may be signed or unsigned, depending on the instruction in question. if the
+    /// immediate is signed, it was sign-extended to 32-bits and that extended value is reported
+    /// here.
     Immediate(u32),
-    ImmediateDouble(f64),
+    /// a 64-bit immediate.
+    ///
+    /// this immediate may be signed or unsigned, depending on the instruction in question. if the
+    /// immediate is signed, it was sign-extended to 64-bits and that extended value is reported
+    /// here.
     Imm64(u64),
+    /// a 16-bit immediate.
+    ///
+    /// this immediate may be signed or unsigned, depending on the instruction in question. if the
+    /// immediate is signed, it was sign-extended to 16-bits and that extended value is reported
+    /// here.
     Imm16(u16),
+    /// a 64-bit floating-point immediate.
+    ///
+    /// the immediate as recorded in the instruction may be `f16`, `f32`, or `f64`, but is
+    /// converted to an `f64` for this operand.
+    ImmediateDouble(f64),
+    /// an immediate, a base number left-shifted by some amount.
+    ///
+    /// this is displayed as, for example, `#0x1234, lsl #12`. the base number may be any 16-bit
+    /// value, and can be shifted by up to 64 bits.
     ImmShift(u16, u8),
+    /// an immediate, a base number left-shifted by some amount, filling with 1's.
+    ///
+    /// this is displayed as, for example, `#0x1234, msl #12`. the base number may be any 16-bit
+    /// value, and can be shifted by up to 64 bits.
     ImmShiftMSL(u16, u8),
+    /// a register, shifted by some constant number of bits.
+    ///
+    /// this is displayed as, for example, `x15, lsl #3`. the operand would be represented by
+    /// `Operand::RegShift(ShiftStyle::LSL, 3, Sizecode::X, 15)`.
     RegShift(ShiftStyle, u8, SizeCode, u16),
-    RegOffset(u16, i16),
+    /// a memory access, with base register offset by another register shifted by some amount.
+    ///
+    /// this is displayed as, for example, `[x6, w9, lsl #5]`, and would be represented by
+    /// `Operand::RegRegOffset(6, 9, SizeCode::W, ShiftStyle::LSL, 5)`.
     RegRegOffset(u16, u16, SizeCode, ShiftStyle, u8),
+    /// a memory access, with a register base address and constant offset, and optional writeback.
+    ///
+    /// this is displayed as, for example:
+    /// * `[x13]` (no writeback, offset of 0)
+    ///   - Offset::RegPreIndex(13, 0, false)`
+    /// * `[x13, #0x80]` (no writeback, offset of 0x80)
+    ///   - Offset::RegPreIndex(13, 0x80, false)`
+    /// * `[x13, #0x80]!` (writeback, offset of 0x80)
+    ///   - Offset::RegPreIndex(13, 0x80, true)`
     RegPreIndex(u16, i32, bool),
+    /// a memory access, with register base address and constant offset, base+offset written back
+    /// to the base register after access.
+    ///
+    /// this is displayed as, for example, `[x5], #-0x40`. the operand would be represented by
+    /// `Operand::RegPostIndex(5, -0x40)`.
     RegPostIndex(u16, i32),
+    /// a memory access, with register base address and register offset, base+offset written back
+    /// to the base register after access.
+    ///
+    /// this is displayed as, for example, `[x5], x9`. the operand would be represented by
+    /// `Operand::RegPostIndex(5, 9)`.
     RegPostIndexReg(u16, u16),
+    /// some kind of operation for a `prfm` or `prfum` operation.
+    ///
+    /// if the operation has a specified name, it will be `{pld,pli,pst}{l1,l2,l3}{keep,strm}`.
+    /// otherwise, the prefetch operation will be shown as the underlying integer from the encoded
+    /// instruction.
     PrefetchOp(u16),
+    /// a system register for an `msr` or `mrs` operation.
+    ///
+    /// if the register is a standard system register, and `yaxpeax-arm` knows about it, its name
+    /// will be used instead. otherwise, this will display as, for example, `sysreg:a6f4`.
     SystemReg(u16),
+    /// a control register for an `sys` or `sysl` operation.
+    ///
+    /// this operand will display as, for example, `cr5`.
     ControlReg(u16),
+    /// a selector for a field of the `pstate` control register.
+    ///
+    /// `yaxpeax-arm` does not name specific fields of `pstate` yet, so this operand displays as
+    /// `pstate.0x50`.
     PstateField(u8),
 }
 
@@ -2738,7 +2939,7 @@ impl Display for Operand {
             Operand::PstateField(reg) => {
                 // `MSR (immediate)` writes to the `PSTATE` register, setting a few bit patterns as
                 // selected by `reg`.
-                write!(fmt, "pstate.{:x}", reg)
+                write!(fmt, "pstate.{:#x}", reg)
             }
             Operand::SIMDRegister(size, reg) => {
                 match size {
@@ -2834,13 +3035,6 @@ impl Display for Operand {
                     _ => { unreachable!(); }
                 }
             }
-            Operand::Offset(offs) => {
-                if *offs < 0 {
-                    write!(fmt, "$-{:#x}", offs.wrapping_neg())
-                } else {
-                    write!(fmt, "$+{:#x}", offs)
-                }
-            }
             Operand::PCOffset(offs) => {
                 if *offs < 0 {
                     write!(fmt, "$-{:#x}", offs.wrapping_neg())
@@ -2906,17 +3100,6 @@ impl Display for Operand {
                     }
                 }
             }
-            Operand::RegOffset(reg, offset) => {
-                if *offset != 0 {
-                    if *offset < 0 {
-                        write!(fmt, "[{}, #-{:#x}]", Operand::RegisterOrSP(SizeCode::X, *reg), -*offset)
-                    } else {
-                        write!(fmt, "[{}, #{:#x}]", Operand::RegisterOrSP(SizeCode::X, *reg), offset)
-                    }
-                } else {
-                    write!(fmt, "[{}]", Operand::RegisterOrSP(SizeCode::X, *reg))
-                }
-            }
             Operand::RegRegOffset(reg, index_reg, index_size, extend, amount) => {
                 if extend == &ShiftStyle::LSL && *amount == 0 {
                     write!(fmt, "[{}, {}]", Operand::RegisterOrSP(SizeCode::X, *reg), Operand::Register(*index_size, *index_reg))
@@ -2958,7 +3141,14 @@ impl Display for Operand {
     }
 }
 
-#[derive(Default, Debug)]
+/// an `aarch64` instruction decoder.
+///
+/// there are no options or levels of decoding support, yet. as a result, any
+/// `armv8::a64::InstDecoder` will decode as much of the a64 instruction set as is implemented.
+///
+/// `InstDecoder` is currently zero-size, but users should not rely on this being the case in the
+/// future.
+#[derive(Default, Debug, PartialEq, Eq, Copy, Clone, Hash, PartialOrd, Ord)]
 pub struct InstDecoder {}
 
 #[allow(non_snake_case)]
@@ -7684,7 +7874,7 @@ impl Decoder<ARMv8> for InstDecoder {
                             let extended_offset = (offset << 11) >> 11;
                             inst.operands = [
                                 Operand::Register(SizeCode::X, (word & 0x1f) as u16),
-                                Operand::Offset((extended_offset as i64) << 12),
+                                Operand::PCOffset((extended_offset as i64) << 12),
                                 Operand::Nothing,
                                 Operand::Nothing
                             ];
@@ -7694,7 +7884,7 @@ impl Decoder<ARMv8> for InstDecoder {
                             let extended_offset = (offset << 11) >> 11;
                             inst.operands = [
                                 Operand::Register(SizeCode::X, (word & 0x1f) as u16),
-                                Operand::Offset(extended_offset as i64),
+                                Operand::PCOffset(extended_offset as i64),
                                 Operand::Nothing,
                                 Operand::Nothing
                             ];
@@ -8022,7 +8212,7 @@ impl Decoder<ARMv8> for InstDecoder {
                             inst.operands = [
                                 Operand::RegisterPair(size_code, Rs),
                                 Operand::RegisterPair(size_code, Rt),
-                                Operand::RegOffset(Rn, 0),
+                                Operand::RegPreIndex(Rn, 0, false),
                                 Operand::Nothing,
                             ];
                             return Ok(());
@@ -8035,14 +8225,14 @@ impl Decoder<ARMv8> for InstDecoder {
                                     inst.operands = [
                                         Operand::Register(SizeCode::W, Rs),
                                         Operand::Register(SizeCode::W, Rt),
-                                        Operand::RegOffset(Rn, 0),
+                                        Operand::RegPreIndex(Rn, 0, false),
                                         Operand::Nothing,
                                     ];
                                 } else if Lo1 == 0b10 {
                                     // load ops
                                     inst.operands = [
                                         Operand::Register(SizeCode::W, Rt),
-                                        Operand::RegOffset(Rn, 0),
+                                        Operand::RegPreIndex(Rn, 0, false),
                                         Operand::Nothing,
                                         Operand::Nothing,
                                     ];
@@ -8088,7 +8278,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                         inst.operands = [
                                             Operand::Register(SizeCode::W, Rs),
                                             Operand::Register(size_code, Rt),
-                                            Operand::RegOffset(Rn, 0),
+                                            Operand::RegPreIndex(Rn, 0, false),
                                             Operand::Nothing,
                                         ];
                                         match o0 {
@@ -8102,7 +8292,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                             Operand::Register(SizeCode::W, Rs),
                                             Operand::Register(size_code, Rt),
                                             Operand::Register(size_code, Rt2),
-                                            Operand::RegOffset(Rn, 0),
+                                            Operand::RegPreIndex(Rn, 0, false),
                                         ];
                                         match o0 {
                                             0b0 => Opcode::STXP,
@@ -8113,7 +8303,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                     0b10 => {
                                         inst.operands = [
                                             Operand::Register(size_code, Rt),
-                                            Operand::RegOffset(Rn, 0),
+                                            Operand::RegPreIndex(Rn, 0, false),
                                             Operand::Nothing,
                                             Operand::Nothing,
                                         ];
@@ -8127,7 +8317,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                         inst.operands = [
                                             Operand::Register(size_code, Rt),
                                             Operand::Register(size_code, Rt2),
-                                            Operand::RegOffset(Rn, 0),
+                                            Operand::RegPreIndex(Rn, 0, false),
                                             Operand::Nothing,
                                         ];
                                         match o0 {
@@ -8176,7 +8366,7 @@ impl Decoder<ARMv8> for InstDecoder {
                             inst.operands = [
                                 Operand::Register(size_code, Rs),
                                 Operand::Register(size_code, Rt),
-                                Operand::RegOffset(Rn, 0),
+                                Operand::RegPreIndex(Rn, 0, false),
                                 Operand::Nothing,
                             ];
                             return Ok(());
@@ -8219,7 +8409,7 @@ impl Decoder<ARMv8> for InstDecoder {
 
                         inst.operands = [
                             Operand::Register(size_code, Rt),
-                            Operand::RegOffset(Rn, 0),
+                            Operand::RegPreIndex(Rn, 0, false),
                             Operand::Nothing,
                             Operand::Nothing,
                         ];
@@ -8283,7 +8473,7 @@ impl Decoder<ARMv8> for InstDecoder {
                             let Rn = ((word >> 5) & 0b11111) as u16;
                             let Rt = ((word >> 0) & 0b11111) as u16;
 
-                            let simm = ((imm9 as i16) << 7) >> 7;
+                            let simm = (((imm9 as i16) << 7) >> 7) as i32;
                             let index = (size << 2) | opc;
 
                             if index == 0b1011 || index >= 0b1110 {
@@ -8306,7 +8496,7 @@ impl Decoder<ARMv8> for InstDecoder {
                             inst.opcode = *opcode;
                             inst.operands = [
                                 Operand::Register(size, Rt),
-                                Operand::RegOffset(Rn, simm),
+                                Operand::RegPreIndex(Rn, simm, false),
                                 Operand::Nothing,
                                 Operand::Nothing,
                             ];
@@ -8321,7 +8511,7 @@ impl Decoder<ARMv8> for InstDecoder {
                             let Rn = ((word >> 5) & 0b11111) as u16;
                             let Rt = ((word >> 0) & 0b11111) as u16;
 
-                            let simm = ((imm9 as i16) << 7) >> 7;
+                            let simm = (((imm9 as i16) << 7) >> 7) as i32;
 
                             let opcode = &[
                                 Opcode::STZGM, Opcode::STG, Opcode::STG, Opcode::STG,
@@ -8337,7 +8527,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                     // ldg
                                     inst.operands = [
                                         Operand::Register(SizeCode::X, Rt),
-                                        Operand::RegOffset(Rn, simm),
+                                        Operand::RegPreIndex(Rn, simm, false),
                                         Operand::Nothing,
                                         Operand::Nothing,
                                     ];
@@ -8354,13 +8544,13 @@ impl Decoder<ARMv8> for InstDecoder {
                                     Operand::RegisterOrSP(SizeCode::X, Rt)
                                 },
                                 if op2 == 0b00 {
-                                    Operand::RegOffset(Rn, 0)
+                                    Operand::RegPreIndex(Rn, 0, false)
                                 } else if op2 == 0b01 {
-                                    Operand::RegPostIndex(Rn, simm as i32)
+                                    Operand::RegPostIndex(Rn, simm)
                                 } else if op2 == 0b10 {
-                                    Operand::RegOffset(Rn, simm)
+                                    Operand::RegPreIndex(Rn, simm, false)
                                 } else {
-                                    Operand::RegPreIndex(Rn, simm as i32, true)
+                                    Operand::RegPreIndex(Rn, simm, true)
                                 },
                                 Operand::Nothing,
                                 Operand::Nothing,
@@ -8585,7 +8775,7 @@ impl Decoder<ARMv8> for InstDecoder {
                         let Rt = (word & 0x1f) as u16;
                         let Rn = ((word >> 5) & 0x1f) as u16;
                         let Rt2 = ((word >> 10) & 0x1f) as u16;
-                        let mut imm7 = ((((word >> 15) & 0x7f) as i16) << 9) >> 9;
+                        let mut imm7 = (((((word >> 15) & 0x7f) as i16) << 9) >> 9) as i32;
                         let opc_L = ((word >> 22) & 1) | ((word >> 29) & 0x6);
                         let size = match opc_L {
                             0b000 => {
@@ -8627,7 +8817,7 @@ impl Decoder<ARMv8> for InstDecoder {
                         inst.operands = [
                             Operand::Register(size, Rt),
                             Operand::Register(size, Rt2),
-                            Operand::RegOffset(Rn, imm7),
+                            Operand::RegPreIndex(Rn, imm7, false),
                             Operand::Nothing
                         ];
                     },
@@ -8863,7 +9053,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                         inst.operands = [
                                             Operand::Register(size, Rs as u16),
                                             Operand::Register(size, Rt as u16),
-                                            Operand::RegOffset(Rn, 0),
+                                            Operand::RegPreIndex(Rn, 0, false),
                                             Operand::Nothing,
                                         ];
                                     } else {
@@ -8881,7 +9071,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                             inst.operands = [
                                                 Operand::Register(size, Rs as u16),
                                                 Operand::Register(size, Rt as u16),
-                                                Operand::RegOffset(Rn, 0),
+                                                Operand::RegPreIndex(Rn, 0, false),
                                                 Operand::Nothing,
                                             ];
                                         } else if opcode == 0b100 {
@@ -8900,7 +9090,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                             // TOOD: should_is_must, Rs = 11111
                                             inst.operands = [
                                                 Operand::Register(size, Rt as u16),
-                                                Operand::RegOffset(Rn, 0),
+                                                Operand::RegPreIndex(Rn, 0, false),
                                                 Operand::Nothing,
                                                 Operand::Nothing,
                                             ];
@@ -8915,7 +9105,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                     // V==0
                                     let w = (word >> 11) & 1;
                                     let imm9 = ((word >> 12) & 0b1_1111_1111) as i16;
-                                    let imm9 = (imm9 << 7) >> 7;
+                                    let imm9 = ((imm9 << 7) >> 7) as i32;
                                     let imm9 = imm9 << 3; // `simm` is stored as a multiple of 8
                                     let m = (word >> 23) & 1;
                                     let size = (word >> 30) & 0b11;
@@ -8932,9 +9122,9 @@ impl Decoder<ARMv8> for InstDecoder {
                                     inst.operands = [
                                         Operand::Register(SizeCode::X, Rt),
                                         if w == 0 {
-                                            Operand::RegOffset(Rn, imm9)
+                                            Operand::RegPreIndex(Rn, imm9, false)
                                         } else {
-                                            Operand::RegPreIndex(Rn, imm9 as i32, true)
+                                            Operand::RegPreIndex(Rn, imm9, true)
                                         },
                                         Operand::Nothing,
                                         Operand::Nothing,
@@ -9008,7 +9198,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                 }
                             }
                         } else {
-                            let imm9 = ((((word >> 12) & 0x1ff) as i16) << 7) >> 7;
+                            let imm9 = (((((word >> 12) & 0x1ff) as i16) << 7) >> 7) as i32;
                             match category {
                                 0b00 => {
                                     // Load/store register (unscaled immediate)
@@ -9040,7 +9230,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                         } else {
                                             Operand::Register(size, Rt)
                                         },
-                                        Operand::RegOffset(Rn, imm9),
+                                        Operand::RegPreIndex(Rn, imm9, false),
                                         Operand::Nothing,
                                         Operand::Nothing,
                                     ];
@@ -9320,14 +9510,14 @@ impl Decoder<ARMv8> for InstDecoder {
                         // V == 0
                         let Rt = (word & 0x1f) as u16;
                         let Rn = ((word >> 5) & 0x1f) as u16;
-                        let imm12 = ((word >> 10) & 0x0fff) as i16;
+                        let imm12 = ((word >> 10) & 0x0fff) as i16 as i32;
                         let size_opc = ((word >> 22) & 0x3) | ((word >> 28) & 0xc);
                         match size_opc {
                             0b0000 => {
                                 inst.opcode = Opcode::STRB;
                                 inst.operands = [
                                     Operand::Register(SizeCode::W, Rt),
-                                    Operand::RegOffset(Rn, imm12),
+                                    Operand::RegPreIndex(Rn, imm12, false),
                                     Operand::Nothing,
                                     Operand::Nothing,
                                 ];
@@ -9336,7 +9526,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                 inst.opcode = Opcode::LDRB;
                                 inst.operands = [
                                     Operand::Register(SizeCode::W, Rt),
-                                    Operand::RegOffset(Rn, imm12),
+                                    Operand::RegPreIndex(Rn, imm12, false),
                                     Operand::Nothing,
                                     Operand::Nothing,
                                 ];
@@ -9345,7 +9535,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                 inst.opcode = Opcode::LDRSB;
                                 inst.operands = [
                                     Operand::Register(SizeCode::X, Rt),
-                                    Operand::RegOffset(Rn, imm12),
+                                    Operand::RegPreIndex(Rn, imm12, false),
                                     Operand::Nothing,
                                     Operand::Nothing,
                                 ];
@@ -9354,7 +9544,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                 inst.opcode = Opcode::LDRSB;
                                 inst.operands = [
                                     Operand::Register(SizeCode::W, Rt),
-                                    Operand::RegOffset(Rn, imm12),
+                                    Operand::RegPreIndex(Rn, imm12, false),
                                     Operand::Nothing,
                                     Operand::Nothing,
                                 ];
@@ -9363,7 +9553,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                 inst.opcode = Opcode::STRH;
                                 inst.operands = [
                                     Operand::Register(SizeCode::W, Rt),
-                                    Operand::RegOffset(Rn, imm12 << 1),
+                                    Operand::RegPreIndex(Rn, imm12 << 1, false),
                                     Operand::Nothing,
                                     Operand::Nothing,
                                 ];
@@ -9372,7 +9562,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                 inst.opcode = Opcode::LDRH;
                                 inst.operands = [
                                     Operand::Register(SizeCode::W, Rt),
-                                    Operand::RegOffset(Rn, imm12 << 1),
+                                    Operand::RegPreIndex(Rn, imm12 << 1, false),
                                     Operand::Nothing,
                                     Operand::Nothing,
                                 ];
@@ -9381,7 +9571,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                 inst.opcode = Opcode::LDRSH;
                                 inst.operands = [
                                     Operand::Register(SizeCode::X, Rt),
-                                    Operand::RegOffset(Rn, imm12 << 1),
+                                    Operand::RegPreIndex(Rn, imm12 << 1, false),
                                     Operand::Nothing,
                                     Operand::Nothing,
                                 ];
@@ -9390,7 +9580,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                 inst.opcode = Opcode::LDRSH;
                                 inst.operands = [
                                     Operand::Register(SizeCode::W, Rt),
-                                    Operand::RegOffset(Rn, imm12 << 1),
+                                    Operand::RegPreIndex(Rn, imm12 << 1, false),
                                     Operand::Nothing,
                                     Operand::Nothing,
                                 ];
@@ -9399,7 +9589,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                 inst.opcode = Opcode::STR;
                                 inst.operands = [
                                     Operand::Register(SizeCode::W, Rt),
-                                    Operand::RegOffset(Rn, imm12 << 2),
+                                    Operand::RegPreIndex(Rn, imm12 << 2, false),
                                     Operand::Nothing,
                                     Operand::Nothing,
                                 ];
@@ -9408,7 +9598,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                 inst.opcode = Opcode::LDR;
                                 inst.operands = [
                                     Operand::Register(SizeCode::W, Rt),
-                                    Operand::RegOffset(Rn, imm12 << 2),
+                                    Operand::RegPreIndex(Rn, imm12 << 2, false),
                                     Operand::Nothing,
                                     Operand::Nothing,
                                 ];
@@ -9417,7 +9607,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                 inst.opcode = Opcode::LDRSW;
                                 inst.operands = [
                                     Operand::Register(SizeCode::X, Rt),
-                                    Operand::RegOffset(Rn, imm12 << 2),
+                                    Operand::RegPreIndex(Rn, imm12 << 2, false),
                                     Operand::Nothing,
                                     Operand::Nothing,
                                 ];
@@ -9427,7 +9617,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                 inst.opcode = Opcode::STR;
                                 inst.operands = [
                                     Operand::Register(SizeCode::X, Rt),
-                                    Operand::RegOffset(Rn, imm12 << 3),
+                                    Operand::RegPreIndex(Rn, imm12 << 3, false),
                                     Operand::Nothing,
                                     Operand::Nothing,
                                 ];
@@ -9436,7 +9626,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                 inst.opcode = Opcode::LDR;
                                 inst.operands = [
                                     Operand::Register(SizeCode::X, Rt),
-                                    Operand::RegOffset(Rn, imm12 << 3),
+                                    Operand::RegPreIndex(Rn, imm12 << 3, false),
                                     Operand::Nothing,
                                     Operand::Nothing,
                                 ];
@@ -9445,7 +9635,7 @@ impl Decoder<ARMv8> for InstDecoder {
                                 inst.opcode = Opcode::PRFM;
                                 inst.operands = [
                                     Operand::PrefetchOp(Rt),
-                                    Operand::RegOffset(Rn, imm12 << 3),
+                                    Operand::RegPreIndex(Rn, imm12 << 3, false),
                                     Operand::Nothing,
                                     Operand::Nothing,
                                 ];
@@ -9571,7 +9761,7 @@ impl Decoder<ARMv8> for InstDecoder {
                         ];
                         inst.operands = [
                             Operand::SIMDRegisterGroup(datasize, Rt as u16, SIZES[size as usize], num_regs),
-                            Operand::RegOffset(Rn as u16, 0),
+                            Operand::RegPreIndex(Rn as u16, 0, false),
                             Operand::Nothing,
                             Operand::Nothing,
                         ];
@@ -9702,7 +9892,7 @@ impl Decoder<ARMv8> for InstDecoder {
                             ];
                             inst.operands = [
                                 Operand::SIMDRegisterGroup(datasize, Rt as u16, SIZES[size as usize], opc_idx as u8 + 1),
-                                Operand::RegOffset(Rn as u16, 0),
+                                Operand::RegPreIndex(Rn as u16, 0, false),
                                 Operand::Nothing,
                                 Operand::Nothing,
                             ];
@@ -9766,7 +9956,7 @@ impl Decoder<ARMv8> for InstDecoder {
                         };
                         inst.operands = [
                             Operand::SIMDRegisterGroupLane(Rt as u16, item_size, group_size, index as u8),
-                            Operand::RegOffset(Rn as u16, 0),
+                            Operand::RegPreIndex(Rn as u16, 0, false),
                             Operand::Nothing,
                             Operand::Nothing,
                         ];
@@ -9922,7 +10112,7 @@ impl Decoder<ARMv8> for InstDecoder {
                         let extended_offset = (offset << 4) >> 4;
                         inst.opcode = Opcode::B;
                         inst.operands = [
-                            Operand::Offset(extended_offset as i64),
+                            Operand::PCOffset(extended_offset as i64),
                             Operand::Nothing,
                             Operand::Nothing,
                             Operand::Nothing
@@ -9935,7 +10125,7 @@ impl Decoder<ARMv8> for InstDecoder {
                         let Rt = word & 0x1f;
                         inst.operands = [
                             Operand::Register(SizeCode::W, Rt as u16),
-                            Operand::Offset(extended_offset as i64),
+                            Operand::PCOffset(extended_offset as i64),
                             Operand::Nothing,
                             Operand::Nothing
                         ];
@@ -9947,7 +10137,7 @@ impl Decoder<ARMv8> for InstDecoder {
                         let Rt = word & 0x1f;
                         inst.operands = [
                             Operand::Register(SizeCode::W, Rt as u16),
-                            Operand::Offset(extended_offset as i64),
+                            Operand::PCOffset(extended_offset as i64),
                             Operand::Nothing,
                             Operand::Nothing
                         ];
@@ -9961,7 +10151,7 @@ impl Decoder<ARMv8> for InstDecoder {
                         inst.operands = [
                             Operand::Register(SizeCode::W, Rt as u16),
                             Operand::Imm16(b as u16),
-                            Operand::Offset(extended_offset as i64),
+                            Operand::PCOffset(extended_offset as i64),
                             Operand::Nothing
                         ];
                     },
@@ -9974,7 +10164,7 @@ impl Decoder<ARMv8> for InstDecoder {
                         inst.operands = [
                             Operand::Register(SizeCode::W, Rt as u16),
                             Operand::Imm16(b as u16),
-                            Operand::Offset(extended_offset as i64),
+                            Operand::PCOffset(extended_offset as i64),
                             Operand::Nothing
                         ];
                     },
@@ -9984,7 +10174,7 @@ impl Decoder<ARMv8> for InstDecoder {
                         let cond = word & 0x0f;
                         inst.opcode = Opcode::Bcc(cond as u8);
                         inst.operands = [
-                            Operand::Offset(extended_offset as i64),
+                            Operand::PCOffset(extended_offset as i64),
                             Operand::Nothing,
                             Operand::Nothing,
                             Operand::Nothing
@@ -10003,7 +10193,7 @@ impl Decoder<ARMv8> for InstDecoder {
                         let extended_offset = (offset << 4) >> 4;
                         inst.opcode = Opcode::BL;
                         inst.operands = [
-                            Operand::Offset(extended_offset as i64),
+                            Operand::PCOffset(extended_offset as i64),
                             Operand::Nothing,
                             Operand::Nothing,
                             Operand::Nothing
@@ -10016,7 +10206,7 @@ impl Decoder<ARMv8> for InstDecoder {
                         let Rt = word & 0x1f;
                         inst.operands = [
                             Operand::Register(SizeCode::X, Rt as u16),
-                            Operand::Offset(extended_offset as i64),
+                            Operand::PCOffset(extended_offset as i64),
                             Operand::Nothing,
                             Operand::Nothing
                         ];
@@ -10028,7 +10218,7 @@ impl Decoder<ARMv8> for InstDecoder {
                         let Rt = word & 0x1f;
                         inst.operands = [
                             Operand::Register(SizeCode::X, Rt as u16),
-                            Operand::Offset(extended_offset as i64),
+                            Operand::PCOffset(extended_offset as i64),
                             Operand::Nothing,
                             Operand::Nothing
                         ];
@@ -10042,7 +10232,7 @@ impl Decoder<ARMv8> for InstDecoder {
                         inst.operands = [
                             Operand::Register(SizeCode::X, Rt as u16),
                             Operand::Imm16((b as u16) | 0x20),
-                            Operand::Offset(extended_offset as i64),
+                            Operand::PCOffset(extended_offset as i64),
                             Operand::Nothing
                         ];
                     },
@@ -10055,7 +10245,7 @@ impl Decoder<ARMv8> for InstDecoder {
                         inst.operands = [
                             Operand::Register(SizeCode::X, Rt as u16),
                             Operand::Imm16((b as u16) | 0x20),
-                            Operand::Offset(extended_offset as i64),
+                            Operand::PCOffset(extended_offset as i64),
                             Operand::Nothing
                         ];
                     },
diff --git a/src/armv8/mod.rs b/src/armv8/mod.rs
index e3fc54a..3d46f33 100644
--- a/src/armv8/mod.rs
+++ b/src/armv8/mod.rs
@@ -1 +1,2 @@
+/// `yaxpeax-arm`'s `ARMv8/aarch64` decoder and `Arch` implementation.
 pub mod a64;
diff --git a/src/lib.rs b/src/lib.rs
index ad2eb01..58a7667 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,4 +1,52 @@
+//! # `yaxpeax-arm`, a decoder for `arm` instruction sets.
+//!
+//! `yaxpeax-arm` provides `armv7` (and below) decoders, including `thumb` support, as well a
+//! decoder for `armv8`/`a64`.
+//!
+//! ## usage
+//!
+//! `yaxpeax-arm` is currently only usable through `yaxpeax-arch` traits:
+//! ```
+//! mod decoder {
+//!     use yaxpeax_arch::{Arch, AddressDisplay, Decoder, Reader, ReaderBuilder};
+//!
+//!     pub fn decode_stream<
+//!         'data,
+//!         A: yaxpeax_arch::Arch,
+//!         U: ReaderBuilder<A::Address, A::Word>,
+//!     >(data: U) where
+//!         A::Instruction: std::fmt::Display,
+//!     {
+//!         let mut reader = ReaderBuilder::read_from(data);
+//!         let mut address: A::Address = reader.total_offset();
+//!
+//!         let decoder = A::Decoder::default();
+//!         let mut decode_res = decoder.decode(&mut reader);
+//!         loop {
+//!             match decode_res {
+//!                 Ok(ref inst) => {
+//!                     println!("{}: {}", address.show(), inst);
+//!                     decode_res = decoder.decode(&mut reader);
+//!                     address = reader.total_offset();
+//!                 }
+//!                 Err(e) => {
+//!                     println!("{}: decode error: {}", address.show(), e);
+//!                     break;
+//!                 }
+//!             }
+//!         }
+//!     }
+//! }
+//!
+//! use yaxpeax_arm::armv8::a64::Arch;
+//! use yaxpeax_arch::{ReaderBuilder, U8Reader};
+//! let data: &[u8] = &[0x94, 0x02, 0x1e, 0x32];
+//! // would display `orr w20, w20, #0x4`.
+//! decoder::decode_stream::<x86_64, _>(data);
+//! ```
+
 #![no_std]
+#![deny(missing_docs)]
 
 #[cfg(feature="use-serde")]
 #[macro_use] extern crate serde_derive;
@@ -7,5 +55,7 @@ extern crate serde;
 extern crate yaxpeax_arch;
 extern crate bitvec;
 
+/// `yaxpeax-arm`'s `ARMv7` decoder and `Arch` implementation.
 pub mod armv7;
+/// `yaxpeax-arm`'s `ARMv8` decoder and `Arch` implementation.
 pub mod armv8;
-- 
cgit v1.1