From 4cc97cffbf689d4b695c3210156f8138afccd5e3 Mon Sep 17 00:00:00 2001 From: Marco Thomas Date: Thu, 24 Jul 2025 11:43:08 +0900 Subject: [PATCH] ft(interpreter): impl stosb/stosw --- src/disasm.rs | 2 + src/instructions.rs | 15 +++- src/interpreter/computer.rs | 125 ++++++++++++++++++++++++--------- src/interpreter/interpreter.rs | 4 +- 4 files changed, 110 insertions(+), 36 deletions(-) diff --git a/src/disasm.rs b/src/disasm.rs index 8146c3f..0b168e1 100644 --- a/src/disasm.rs +++ b/src/disasm.rs @@ -252,6 +252,8 @@ impl Disassembler { ); let byte = self.parse_byte()?; let mnemonic = match byte { + 0xAA => RepeatableStringOperation::STOSB(Mnemonic::STOSB), + 0xAB => RepeatableStringOperation::STOSW(Mnemonic::STOSW), 0xA4 => RepeatableStringOperation::MOVSB(Mnemonic::MOVSB), 0xA5 => RepeatableStringOperation::MOVSW(Mnemonic::MOVSW), 0xA6 => RepeatableStringOperation::CMPSB(Mnemonic::CMPSB), diff --git a/src/instructions.rs b/src/instructions.rs index 02f08cd..4df22f9 100644 --- a/src/instructions.rs +++ b/src/instructions.rs @@ -53,6 +53,8 @@ pub enum RepeatableStringOperation { SCASW(Mnemonic), MOVSB(Mnemonic), MOVSW(Mnemonic), + STOSB(Mnemonic), + STOSW(Mnemonic), } impl RepeatableStringOperation { @@ -64,13 +66,24 @@ impl RepeatableStringOperation { RepeatableStringOperation::SCASW(mnemonic) => mnemonic, RepeatableStringOperation::MOVSB(mnemonic) => mnemonic, RepeatableStringOperation::MOVSW(mnemonic) => mnemonic, + RepeatableStringOperation::STOSB(mnemonic) => mnemonic, + RepeatableStringOperation::STOSW(mnemonic) => mnemonic, } } } impl fmt::Display for RepeatableStringOperation { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "self.0") + match self { + RepeatableStringOperation::CMPSB(mnemonic) => write!(f, "{}", mnemonic), + RepeatableStringOperation::CMPSW(mnemonic) => write!(f, "{}", mnemonic), + RepeatableStringOperation::SCASB(mnemonic) => write!(f, "{}", mnemonic), + RepeatableStringOperation::SCASW(mnemonic) => write!(f, "{}", mnemonic), + RepeatableStringOperation::MOVSB(mnemonic) => write!(f, "{}", mnemonic), + RepeatableStringOperation::MOVSW(mnemonic) => write!(f, "{}", mnemonic), + RepeatableStringOperation::STOSB(mnemonic) => write!(f, "{}", mnemonic), + RepeatableStringOperation::STOSW(mnemonic) => write!(f, "{}", mnemonic), + } } } diff --git a/src/interpreter/computer.rs b/src/interpreter/computer.rs index e02e7a9..8f8453e 100644 --- a/src/interpreter/computer.rs +++ b/src/interpreter/computer.rs @@ -471,52 +471,92 @@ impl Computer { rep_op: RepeatableStringOperation, z: bool, ) -> Result<(), InterpreterError> { - while self.regs.cx.read() != 0 { - self.string_ops(rep_op.clone().get())?; - - if self.flags.zf == z { - return Ok(()); + loop { + if self.regs.cx.read() == 0 { + break; } + self.string_ops(rep_op.clone().get())?; self.regs.cx.write(self.regs.cx.read() - 1); - self.regs.di -= 1; + + // REPZ stop if zf == 0 + // REPNZ stop if zf == 1 + match rep_op { + RepeatableStringOperation::CMPSB(_) + | RepeatableStringOperation::CMPSW(_) + | RepeatableStringOperation::SCASB(_) + | RepeatableStringOperation::SCASW(_) => { + if self.flags.zf != z { + break; + } + } + _ => {} + } } Ok(()) } /// Execute string operations. pub fn string_ops(&mut self, mnemonic: Mnemonic) -> Result<(), InterpreterError> { + fn adjust_sidi(computer: &mut Computer, val: Word) { + if computer.flags.df { + computer.regs.si -= val; + computer.regs.di -= val; + } else { + computer.regs.si += val; + computer.regs.di += val; + } + } + // TODO: can i write this more compact? match mnemonic { - Mnemonic::CMPSB => self.cmp( - ModRmTarget::Register(crate::register::Register::AL), - ArithmeticOperand::Immediate(ImmediateOperand::Byte(self.read_esdi()? as Byte)), - ), - Mnemonic::CMPSW => self.cmp( - ModRmTarget::Register(crate::register::Register::AL), - ArithmeticOperand::Immediate(self.read_esdi()?.into()), - ), - Mnemonic::SCASB => self.cmp( - ModRmTarget::Memory(self.regs.si.into()), - ArithmeticOperand::Immediate(ImmediateOperand::Byte(self.read_esdi()? as Byte)), - ), - Mnemonic::SCASW => self.cmp( - ModRmTarget::Memory(self.regs.si.into()), - ArithmeticOperand::Immediate(ImmediateOperand::Byte(self.read_esdi()? as Byte)), - ), + Mnemonic::CMPSB => { + self.cmp( + ModRmTarget::Register(crate::register::Register::AL), + ArithmeticOperand::Immediate(ImmediateOperand::Byte(self.read_esdi()? as Byte)), + )?; + adjust_sidi(self, 1); + Ok(()) + } + Mnemonic::CMPSW => { + self.cmp( + ModRmTarget::Register(crate::register::Register::AL), + ArithmeticOperand::Immediate(self.read_esdi()?.into()), + )?; + adjust_sidi(self, 2); + Ok(()) + } + Mnemonic::SCASB => { + self.cmp( + ModRmTarget::Register(crate::register::Register::AL), + ArithmeticOperand::Immediate(ImmediateOperand::Byte(self.read_esdi()? as Byte)), + )?; + if self.flags.df { + self.regs.di -= 1; + } else { + self.regs.di += 1; + } + Ok(()) + } + Mnemonic::SCASW => { + self.cmp( + ModRmTarget::Register(crate::register::Register::AX), + ArithmeticOperand::Immediate(ImmediateOperand::Byte(self.read_esdi()? as Byte)), + )?; + if self.flags.df { + self.regs.di -= 2; + } else { + self.regs.di += 2; + } + + Ok(()) + } Mnemonic::MOVSB => { let addr = self.mem_addr(self.regs.di.into(), &crate::register::SegmentRegister::ES); let val = self.read(self.regs.si.into())?; self.memory .write_raw(addr, ImmediateOperand::Byte(val as u8))?; - - if self.flags.df { - self.regs.si -= 1; - self.regs.di -= 1; - } else { - self.regs.si += 1; - self.regs.di += 1; - } + adjust_sidi(self, 1); Ok(()) } @@ -525,14 +565,33 @@ impl Computer { self.mem_addr(self.regs.di.into(), &crate::register::SegmentRegister::ES); let val = self.read(self.regs.si.into())?; self.memory.write_raw(addr, val.into())?; + adjust_sidi(self, 2); + Ok(()) + } + Mnemonic::STOSB => { + let addr = + self.mem_addr(self.regs.di.into(), &crate::register::SegmentRegister::ES); + let val = self.regs.ax.lower; + self.memory.write_raw(addr, val.into())?; + if self.flags.df { + self.regs.di -= 1; + } else { + self.regs.di += 1; + }; + + Ok(()) + } + Mnemonic::STOSW => { + let addr = + self.mem_addr(self.regs.di.into(), &crate::register::SegmentRegister::ES); + let val = self.regs.ax.read(); + self.memory.write_raw(addr, val.into())?; if self.flags.df { - self.regs.si -= 2; self.regs.di -= 2; } else { - self.regs.si += 2; self.regs.di += 2; - } + }; Ok(()) } diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index 0526042..55433ff 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -643,8 +643,6 @@ impl Interpreter { /* * String Byte Operations */ - Mnemonic::STOSB => todo!(), - Mnemonic::STOSW => todo!(), Mnemonic::LODSB => todo!(), Mnemonic::LODSW => todo!(), @@ -654,6 +652,8 @@ impl Interpreter { Mnemonic::CMPSW => self.computer.string_ops(current_instruction.mnemonic)?, Mnemonic::MOVSB => self.computer.string_ops(current_instruction.mnemonic)?, Mnemonic::MOVSW => self.computer.string_ops(current_instruction.mnemonic)?, + Mnemonic::STOSB => self.computer.string_ops(current_instruction.mnemonic)?, + Mnemonic::STOSW => self.computer.string_ops(current_instruction.mnemonic)?, /* * RET