diff --git a/src/disasm.rs b/src/disasm.rs index 4d87bf4..3027054 100644 --- a/src/disasm.rs +++ b/src/disasm.rs @@ -798,19 +798,19 @@ impl Disassembler { // Group 2 0xD0 => { - let (target, reg) = self.parse_modrm_byte(None)?; + let (target, reg) = self.parse_modrm_byte(Some(InstructionWidth::Byte))?; Self::modrm_reg_to_grp2_1(reg, target)? } 0xD1 => { - let (target, reg) = self.parse_modrm_byte(None)?; + let (target, reg) = self.parse_modrm_byte(Some(InstructionWidth::Word))?; Self::modrm_reg_to_grp2_1(reg, target)? } 0xD2 => { - let (target, reg) = self.parse_modrm_byte(None)?; + let (target, reg) = self.parse_modrm_byte(Some(InstructionWidth::Byte))?; Self::modrm_reg_to_grp2_cl(reg, target)? } 0xD3 => { - let (target, reg) = self.parse_modrm_byte(None)?; + let (target, reg) = self.parse_modrm_byte(Some(InstructionWidth::Word))?; Self::modrm_reg_to_grp2_cl(reg, target)? } diff --git a/src/interpreter/computer.rs b/src/interpreter/computer.rs index 6e7af7d..07042b6 100644 --- a/src/interpreter/computer.rs +++ b/src/interpreter/computer.rs @@ -235,6 +235,47 @@ impl Computer { ModRmTarget::Register(reg) => self.regs.read(reg), } } + + pub fn rotate( + &mut self, + target: ModRmTarget, + rotations: usize, // how many rotations + carry_usage: CarryUsage, // if carry should be included, or should just receive a copy + rotation_direction: RotationDirection, // direction of rotation + ) { + let mut bits = self.read_modrm(target).bits(); + match carry_usage { + CarryUsage::FullRotation => bits.push(self.flags.cf), + _ => {} + } + match rotation_direction { + RotationDirection::Left => { + bits.rotate_left(rotations); + match carry_usage { + CarryUsage::ReceiveCopy => self.flags.cf = bits[7], + CarryUsage::FullRotation => self.flags.cf = bits.pop().unwrap(), + } + } + RotationDirection::Right => { + bits.rotate_right(rotations); + match carry_usage { + CarryUsage::ReceiveCopy => self.flags.cf = bits[0], + CarryUsage::FullRotation => self.flags.cf = bits.pop().unwrap(), + } + } + } + self.write_modrm(target, ImmediateOperand::from(bits)); + } +} + +pub enum RotationDirection { + Left, + Right, +} + +pub enum CarryUsage { + ReceiveCopy, // dont add when rotating, but copy bit that was rotated to other side + FullRotation, // include in full rotation } impl fmt::Display for Computer { diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index a169496..88aa355 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -3,7 +3,11 @@ use std::{fmt::Debug, process::exit}; use crate::{ instructions::{Instruction, Mnemonic}, - interpreter::{interrupt::Mess1, memory::Memory}, + interpreter::{ + computer::{CarryUsage, RotationDirection}, + interrupt::Mess1, + memory::Memory, + }, operands::{Byte, ImmediateOperand, ModRmTarget, Word}, }; @@ -597,8 +601,76 @@ impl Interpreter { } /* - * Shift and Rotate + * Rotate */ + Mnemonic::ROL_b(target, b) => self.computer.rotate( + target, + b.into(), + CarryUsage::ReceiveCopy, + RotationDirection::Left, + ), + Mnemonic::ROR_b(target, b) => self.computer.rotate( + target, + b.into(), + CarryUsage::ReceiveCopy, + RotationDirection::Right, + ), + Mnemonic::RCL_b(target, b) => self.computer.rotate( + target, + b.into(), + CarryUsage::FullRotation, + RotationDirection::Left, + ), + Mnemonic::RCR_b(target, b) => self.computer.rotate( + target, + b.into(), + CarryUsage::FullRotation, + RotationDirection::Right, + ), + Mnemonic::ROL_fromReg(target, reg) => self.computer.rotate( + target, + self.computer.regs.read(reg).into(), + CarryUsage::ReceiveCopy, + RotationDirection::Left, + ), + Mnemonic::ROR_fromReg(target, reg) => self.computer.rotate( + target, + self.computer.regs.read(reg).into(), + CarryUsage::ReceiveCopy, + RotationDirection::Right, + ), + Mnemonic::RCL_fromReg(target, reg) => self.computer.rotate( + target, + self.computer.regs.read(reg).into(), + CarryUsage::FullRotation, + RotationDirection::Left, + ), + Mnemonic::RCR_fromReg(target, reg) => self.computer.rotate( + target, + self.computer.regs.read(reg).into(), + CarryUsage::FullRotation, + RotationDirection::Right, + ), + + /* + * Shfit + */ + Mnemonic::SHL_b(target, b) => self + .computer + .write_modrm(target, self.computer.read_modrm(target) << b), + Mnemonic::SHR_b(target, b) => self + .computer + .write_modrm(target, self.computer.read_modrm(target) >> b), + Mnemonic::SAR_b(target, b) => todo!(), + Mnemonic::SHL_fromReg(target, reg) => self.computer.write_modrm( + target, + self.computer.read_modrm(target) << self.computer.regs.read(reg), + ), + Mnemonic::SHR_fromReg(target, reg) => self.computer.write_modrm( + target, + self.computer.read_modrm(target) >> self.computer.regs.read(reg), + ), + Mnemonic::SAR_fromReg(target, reg) => todo!(), /* * IN diff --git a/src/operands.rs b/src/operands.rs index 01de654..c3091fe 100644 --- a/src/operands.rs +++ b/src/operands.rs @@ -7,7 +7,7 @@ use crate::register::SegmentRegister; use crate::{disasm::DisasmError, register::Register}; use core::fmt; -use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Not, Sub}; +use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Not, Shl, Shr, Sub}; pub type Byte = u8; // b pub type IByte = i8; // used for displacements of memory access @@ -28,6 +28,14 @@ pub enum ImmediateOperand { } impl ImmediateOperand { + /// Return bits of internal value. + pub fn bits(self) -> Vec { + match self { + ImmediateOperand::Byte(b) => (0..8).map(|i| (b & (1 << i)) != 0).collect(), + ImmediateOperand::Word(w) => (0..8).map(|i| (w & (1 << i)) != 0).collect(), + } + } + /// Sign-extend [`Self::Byte`] into [`Self::Word`]. /// Returns [`Self::Word`], if already a word. pub fn sign_extend(self) -> Self { @@ -98,6 +106,26 @@ impl ImmediateOperand { } } +impl From> for ImmediateOperand { + fn from(bits: Vec) -> Self { + if bits.len() == 8 { + let val = bits + .iter() + .enumerate() + .fold(0, |acc, (i, &bit)| acc | ((bit as u8) << i)); + Self::Byte(val) + } else if bits.len() == 16 { + let val = bits + .iter() + .enumerate() + .fold(0, |acc, (i, &bit)| acc | ((bit as u16) << i)); + Self::Word(val) + } else { + panic!("Invalid bit length"); + } + } +} + impl From for ImmediateOperand { fn from(value: Byte) -> Self { Self::Byte(value) @@ -252,6 +280,62 @@ impl Mul for ImmediateOperand { } } +impl Shl for ImmediateOperand { + type Output = Self; + + fn shl(self, rhs: Self) -> Self::Output { + match self { + Self::Byte(b) => match rhs { + ImmediateOperand::Byte(sb) => Self::Byte(b << sb), + ImmediateOperand::Word(sw) => Self::Byte(b << sw), + }, + Self::Word(w) => match rhs { + ImmediateOperand::Byte(sb) => Self::Word(w << sb), + ImmediateOperand::Word(sw) => Self::Word(w << sw), + }, + } + } +} + +impl Shl for ImmediateOperand { + type Output = Self; + + fn shl(self, rhs: u8) -> Self::Output { + match self { + Self::Byte(b) => Self::Byte(b << rhs), + Self::Word(w) => Self::Word(w << rhs), + } + } +} + +impl Shr for ImmediateOperand { + type Output = Self; + + fn shr(self, rhs: Self) -> Self::Output { + match self { + Self::Byte(b) => match rhs { + ImmediateOperand::Byte(sb) => Self::Byte(b >> sb), + ImmediateOperand::Word(sw) => Self::Byte(b >> sw), + }, + Self::Word(w) => match rhs { + ImmediateOperand::Byte(sb) => Self::Word(w >> sb), + ImmediateOperand::Word(sw) => Self::Word(w >> sw), + }, + } + } +} + +impl Shr for ImmediateOperand { + type Output = Self; + + fn shr(self, rhs: u8) -> Self::Output { + match self { + Self::Byte(b) => Self::Byte(b >> rhs), + Self::Word(w) => Self::Word(w >> rhs), + } + } +} + impl Div for ImmediateOperand { type Output = Self;