diff --git a/src/interpreter/computer.rs b/src/interpreter/computer.rs index 158f14d..f98bf7f 100644 --- a/src/interpreter/computer.rs +++ b/src/interpreter/computer.rs @@ -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; - self.flags.of = if result.msb() == self.flags.cf { - false - } else { - true - }; + + // 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)?; diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index cec6ad0..b39a815 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -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( + 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 diff --git a/src/operands.rs b/src/operands.rs index 809f10d..eac4c5d 100644 --- a/src/operands.rs +++ b/src/operands.rs @@ -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,