ft(interpreter): impl SAR

This commit is contained in:
2025-07-08 08:54:57 +09:00
parent be0b928a55
commit ecbe478dcd
3 changed files with 78 additions and 33 deletions

View File

@@ -1,6 +1,5 @@
use clap::Parser; use clap::Parser;
use core::fmt; use core::fmt;
use std::path::Path;
use crate::{ use crate::{
Args, Args,
@@ -463,29 +462,59 @@ impl Computer {
Ok(imm) 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( pub fn shift(
&mut self, &mut self,
target: ModRmTarget, target: ModRmTarget,
shift: ImmediateOperand, // how many shifts shift: ImmediateOperand, // how many shifts
shift_direction: Direction, // direction of shifting shift_direction: Direction, // direction of shifting
arithmetic_right: bool, // arithmetic shift yes/no
) -> Result<(), InterpreterError> { ) -> Result<(), InterpreterError> {
let result = match shift_direction { let result = match shift_direction {
Direction::Left => { Direction::Left => {
let imm = self.read_modrm(target)? << (shift - 1); let imm = self.read_modrm(target)? << (shift - 1);
// CF is last bit, which is shifted out
self.flags.cf = imm.msb(); self.flags.cf = imm.msb();
let result = imm << 1; let result = imm << 1;
self.flags.of = if result.msb() == self.flags.cf {
false // OF only affected for 1 bit shifts
} else { if shift == 1_u8.into() {
true self.flags.of = if result.msb() == self.flags.cf {
}; false
} else {
true
};
}
result result
} }
Direction::Right => { Direction::Right => {
let imm = self.read_modrm(target)? >> (shift - 1); let target_val = self.read_modrm(target)?;
self.flags.cf = imm.msb(); let imm = target_val >> (shift - 1);
imm >> 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)?; self.write_modrm(target, result)?;

View File

@@ -770,35 +770,37 @@ impl Interpreter {
* Shfit * Shfit
*/ */
Mnemonic::SHL_b(target, b) => { 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) => { Mnemonic::SHR_b(target, b) => {
self.computer.shift(target, b.into(), Direction::Right)?; self.computer
// For the SHR instruction, the OF flag is set to the most-significant bit of the original operand. .shift(target, b.into(), Direction::Right, false)?;
self.computer.flags.of = self.computer.read_modrm(target)?.msb();
} }
Mnemonic::SAR_b(_, _) => todo!(), Mnemonic::SAR_b(target, b) => {
// Mnemonic::SAR_b(_, _) => { self.computer
// For the SAR instruction, the OF flag is cleared for all 1-bit shifts. .shift(target, b.into(), Direction::Right, true)?
// if b == 1 { }
// self.flags.of = 0;
// }
// },
Mnemonic::SHL_fromReg(target, reg) => self.computer.shift( Mnemonic::SHL_fromReg(target, reg) => self.computer.shift(
target, target,
self.computer.regs.read(reg).into(), self.computer.regs.read(reg).into(),
Direction::Left, Direction::Left,
false,
)?,
Mnemonic::SHR_fromReg(target, reg) => self.computer.shift(
target,
self.computer.regs.read(reg).into(),
Direction::Right,
false,
)?,
Mnemonic::SAR_fromReg(target, reg) => self.computer.shift(
target,
self.computer.regs.read(reg).into(),
Direction::Right,
true,
)?, )?,
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!(),
/* /*
* IN * IN

View File

@@ -9,7 +9,7 @@ use crate::{disasm::DisasmError, register::Register};
use core::fmt; use core::fmt;
use std::{ use std::{
cmp::Ordering, 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 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. /// Check if inner value is zero.
pub fn zero(&self) -> bool { pub fn zero(&self) -> bool {
match self { match self {
@@ -92,7 +106,7 @@ impl ImmediateOperand {
} }
/// Check if least significant bit is set. /// Check if least significant bit is set.
pub fn _lsb(&self) -> bool { pub fn lsb(&self) -> bool {
match self { match self {
Self::Byte(byte) => return byte & 1 == 1, Self::Byte(byte) => return byte & 1 == 1,
Self::Word(word) => return word & 1 == 1, Self::Word(word) => return word & 1 == 1,