ft(interpreter): impl SAR
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
use clap::Parser;
|
||||
use core::fmt;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::{
|
||||
Args,
|
||||
@@ -463,29 +462,59 @@ impl Computer {
|
||||
Ok(imm)
|
||||
}
|
||||
|
||||
/// Shift bits of data, pointed to by a [`ModRMTarget`]
|
||||
/// Shift bits of data, pointed to by a [`ModRMTarget`].
|
||||
/// SHL: Direction::Left, false
|
||||
/// SHR: Direction::Right, false
|
||||
/// SAR: Direction::Right, true
|
||||
pub fn shift(
|
||||
&mut self,
|
||||
target: ModRmTarget,
|
||||
shift: ImmediateOperand, // how many shifts
|
||||
shift_direction: Direction, // direction of shifting
|
||||
arithmetic_right: bool, // arithmetic shift yes/no
|
||||
) -> Result<(), InterpreterError> {
|
||||
let result = match shift_direction {
|
||||
Direction::Left => {
|
||||
let imm = self.read_modrm(target)? << (shift - 1);
|
||||
|
||||
// CF is last bit, which is shifted out
|
||||
self.flags.cf = imm.msb();
|
||||
let result = imm << 1;
|
||||
|
||||
// OF only affected for 1 bit shifts
|
||||
if shift == 1_u8.into() {
|
||||
self.flags.of = if result.msb() == self.flags.cf {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
};
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
Direction::Right => {
|
||||
let imm = self.read_modrm(target)? >> (shift - 1);
|
||||
self.flags.cf = imm.msb();
|
||||
imm >> 1
|
||||
let target_val = self.read_modrm(target)?;
|
||||
let imm = target_val >> (shift - 1);
|
||||
|
||||
// OF only affected for 1 bit shifts
|
||||
if shift == 1_u8.into() {
|
||||
if arithmetic_right {
|
||||
self.flags.of = false;
|
||||
} else {
|
||||
self.flags.of = target_val.msb();
|
||||
}
|
||||
}
|
||||
|
||||
// CF is last bit, which is shifted out
|
||||
self.flags.cf = imm.lsb();
|
||||
let result = imm >> 1;
|
||||
|
||||
// preserve sign for SAR
|
||||
if arithmetic_right {
|
||||
result.set_sign(imm.msb())
|
||||
} else {
|
||||
result
|
||||
}
|
||||
}
|
||||
};
|
||||
self.write_modrm(target, result)?;
|
||||
|
||||
@@ -770,35 +770,37 @@ impl Interpreter {
|
||||
* Shfit
|
||||
*/
|
||||
Mnemonic::SHL_b(target, b) => {
|
||||
self.computer.shift(target, b.into(), Direction::Left)?
|
||||
self.computer
|
||||
.shift(target, b.into(), Direction::Left, false)?
|
||||
}
|
||||
Mnemonic::SHR_b(target, b) => {
|
||||
self.computer.shift(target, b.into(), Direction::Right)?;
|
||||
// For the SHR instruction, the OF flag is set to the most-significant bit of the original operand.
|
||||
self.computer.flags.of = self.computer.read_modrm(target)?.msb();
|
||||
self.computer
|
||||
.shift(target, b.into(), Direction::Right, false)?;
|
||||
}
|
||||
Mnemonic::SAR_b(_, _) => todo!(),
|
||||
// Mnemonic::SAR_b(_, _) => {
|
||||
// For the SAR instruction, the OF flag is cleared for all 1-bit shifts.
|
||||
// if b == 1 {
|
||||
// self.flags.of = 0;
|
||||
// }
|
||||
// },
|
||||
Mnemonic::SAR_b(target, b) => {
|
||||
self.computer
|
||||
.shift(target, b.into(), Direction::Right, true)?
|
||||
}
|
||||
|
||||
Mnemonic::SHL_fromReg(target, reg) => self.computer.shift(
|
||||
target,
|
||||
self.computer.regs.read(reg).into(),
|
||||
Direction::Left,
|
||||
false,
|
||||
)?,
|
||||
Mnemonic::SHR_fromReg(target, reg) => {
|
||||
self.computer.shift(
|
||||
Mnemonic::SHR_fromReg(target, reg) => self.computer.shift(
|
||||
target,
|
||||
self.computer.regs.read(reg).into(),
|
||||
Direction::Right,
|
||||
)?;
|
||||
// For the SHR instruction, the OF flag is set to the most-significant bit of the original operand.
|
||||
self.computer.flags.of = self.computer.read_modrm(target)?.msb();
|
||||
}
|
||||
Mnemonic::SAR_fromReg(_, _) => todo!(),
|
||||
false,
|
||||
)?,
|
||||
|
||||
Mnemonic::SAR_fromReg(target, reg) => self.computer.shift(
|
||||
target,
|
||||
self.computer.regs.read(reg).into(),
|
||||
Direction::Right,
|
||||
true,
|
||||
)?,
|
||||
|
||||
/*
|
||||
* IN
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::{disasm::DisasmError, register::Register};
|
||||
use core::fmt;
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Not, Shl, Shr, Sub},
|
||||
ops::{Add, BitAnd, BitOr, BitXor, Div, Not, Shl, Shr, Sub},
|
||||
};
|
||||
|
||||
pub type Byte = u8; // b
|
||||
@@ -72,6 +72,20 @@ impl ImmediateOperand {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets or removes sign.
|
||||
pub fn set_sign(self, sign: bool) -> Self {
|
||||
match self {
|
||||
Self::Byte(b) => {
|
||||
let msb = 1 << 7;
|
||||
Self::Byte(if sign { b | msb } else { b & !msb })
|
||||
}
|
||||
Self::Word(w) => {
|
||||
let msb = 1 << 15;
|
||||
Self::Word(if sign { w | msb } else { w & !msb })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if inner value is zero.
|
||||
pub fn zero(&self) -> bool {
|
||||
match self {
|
||||
@@ -92,7 +106,7 @@ impl ImmediateOperand {
|
||||
}
|
||||
|
||||
/// Check if least significant bit is set.
|
||||
pub fn _lsb(&self) -> bool {
|
||||
pub fn lsb(&self) -> bool {
|
||||
match self {
|
||||
Self::Byte(byte) => return byte & 1 == 1,
|
||||
Self::Word(word) => return word & 1 == 1,
|
||||
|
||||
Reference in New Issue
Block a user