ft: abstract and implement ADD::* interpretation

This commit is contained in:
2025-06-04 22:59:41 +09:00
parent ac69d75273
commit ef4663a245
9 changed files with 352 additions and 19 deletions

View File

@@ -7,6 +7,7 @@ use crate::register::SegmentRegister;
use crate::{disasm::DisasmError, register::Register};
use core::fmt;
use std::ops::{Add, Sub};
pub type Byte = u8; // b
pub type IByte = i8; // used for displacements of memory access
@@ -14,7 +15,7 @@ pub type Word = u16; // w or v
pub type IWord = i16; // used for displacement of memory access
pub type DWord = u32;
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Ord, Eq, PartialEq, PartialOrd, Copy)]
/// Encodes either Byte- or Word-sized operands.
/// Also sometimes used to decide if an instruction is Byte- or Word-sized,
/// which is usually indicated by using a value of 0 and the disregarding
@@ -24,6 +25,64 @@ pub enum Operand {
Word(Word),
}
impl Add for Operand {
type Output = Self;
fn add(self, other: Self) -> Self {
match self {
Operand::Byte(lhsb) => match other {
Operand::Byte(rhsb) => Operand::Byte(lhsb.wrapping_add(rhsb)),
_ => panic!("Cannot add Word to Byte"),
},
Operand::Word(lhsw) => match other {
Operand::Word(rhsw) => Operand::Word(lhsw.wrapping_add(rhsw)),
Operand::Byte(rhsb) => Operand::Word(lhsw.wrapping_add(rhsb as Word)),
},
}
}
}
impl Add<Displacement> for Operand {
type Output = Operand;
fn add(self, disp: Displacement) -> Self::Output {
// XXX: ugly hack to add Operand with Displacement
match disp {
Displacement::IByte(byte) => {
if byte < 0 {
return self - Operand::Byte((byte * -1) as Byte);
} else {
return self + Operand::Byte(byte as Byte);
}
}
Displacement::IWord(word) => {
if word < 0 {
return self - Operand::Word((word * -1) as Word);
} else {
return self + Operand::Word(word as Word);
}
}
}
}
}
impl Sub for Operand {
type Output = Self;
fn sub(self, other: Self) -> Self {
match self {
Operand::Byte(lhsb) => match other {
Operand::Byte(rhsb) => Operand::Byte(lhsb.wrapping_sub(rhsb)),
_ => panic!("Cannot substract Word from Byte"),
},
Operand::Word(lhsw) => match other {
Operand::Word(rhsw) => Operand::Word(lhsw.wrapping_sub(rhsw)),
Operand::Byte(rhsb) => Operand::Word(lhsw.wrapping_sub(rhsb as Word)),
},
}
}
}
impl fmt::Display for Operand {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
@@ -42,7 +101,7 @@ impl fmt::LowerHex for Operand {
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
/// ModRM byte can either target a [`MemoryIndex`] (location in memory) or some
/// [`Register`].
pub enum ModRmTarget {
@@ -59,7 +118,7 @@ impl std::fmt::Display for ModRmTarget {
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
/// Memory displacements are signed versions of Byte and Word operands.
/// Encodes either Byte- or Word-sized operands.
/// Generally, a [`Displacement`] is the result of a ModRM byte parse and
@@ -105,7 +164,7 @@ impl std::fmt::Display for Displacement {
/// A memory index operand is usually created by ModRM bytes or words.
/// e.g. [bx+si]
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
pub struct MemoryIndex {
pub base: Option<Register>,
pub index: Option<Register>,
@@ -141,7 +200,7 @@ impl fmt::Display for MemoryIndex {
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
/// 16-bit pointer for access, usually with a [`SegmentRegister`] as segment
/// and [`Pointer16`] as offset.
/// Generally, this type only gets constructed in rare scenarios, when the
@@ -185,7 +244,7 @@ impl TryFrom<ModRmTarget> for Pointer16 {
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Copy)]
/// 32-bit segment:offset pointer for long jumps.
/// Both [`Word`]s are immediately encoded after the instruction
pub struct Pointer32 {