ft(interpreter): impl stosb/stosw
This commit is contained in:
@@ -252,6 +252,8 @@ impl Disassembler {
|
|||||||
);
|
);
|
||||||
let byte = self.parse_byte()?;
|
let byte = self.parse_byte()?;
|
||||||
let mnemonic = match byte {
|
let mnemonic = match byte {
|
||||||
|
0xAA => RepeatableStringOperation::STOSB(Mnemonic::STOSB),
|
||||||
|
0xAB => RepeatableStringOperation::STOSW(Mnemonic::STOSW),
|
||||||
0xA4 => RepeatableStringOperation::MOVSB(Mnemonic::MOVSB),
|
0xA4 => RepeatableStringOperation::MOVSB(Mnemonic::MOVSB),
|
||||||
0xA5 => RepeatableStringOperation::MOVSW(Mnemonic::MOVSW),
|
0xA5 => RepeatableStringOperation::MOVSW(Mnemonic::MOVSW),
|
||||||
0xA6 => RepeatableStringOperation::CMPSB(Mnemonic::CMPSB),
|
0xA6 => RepeatableStringOperation::CMPSB(Mnemonic::CMPSB),
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ pub enum RepeatableStringOperation {
|
|||||||
SCASW(Mnemonic),
|
SCASW(Mnemonic),
|
||||||
MOVSB(Mnemonic),
|
MOVSB(Mnemonic),
|
||||||
MOVSW(Mnemonic),
|
MOVSW(Mnemonic),
|
||||||
|
STOSB(Mnemonic),
|
||||||
|
STOSW(Mnemonic),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RepeatableStringOperation {
|
impl RepeatableStringOperation {
|
||||||
@@ -64,13 +66,24 @@ impl RepeatableStringOperation {
|
|||||||
RepeatableStringOperation::SCASW(mnemonic) => mnemonic,
|
RepeatableStringOperation::SCASW(mnemonic) => mnemonic,
|
||||||
RepeatableStringOperation::MOVSB(mnemonic) => mnemonic,
|
RepeatableStringOperation::MOVSB(mnemonic) => mnemonic,
|
||||||
RepeatableStringOperation::MOVSW(mnemonic) => mnemonic,
|
RepeatableStringOperation::MOVSW(mnemonic) => mnemonic,
|
||||||
|
RepeatableStringOperation::STOSB(mnemonic) => mnemonic,
|
||||||
|
RepeatableStringOperation::STOSW(mnemonic) => mnemonic,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for RepeatableStringOperation {
|
impl fmt::Display for RepeatableStringOperation {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
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),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -471,52 +471,92 @@ impl Computer {
|
|||||||
rep_op: RepeatableStringOperation,
|
rep_op: RepeatableStringOperation,
|
||||||
z: bool,
|
z: bool,
|
||||||
) -> Result<(), InterpreterError> {
|
) -> Result<(), InterpreterError> {
|
||||||
while self.regs.cx.read() != 0 {
|
loop {
|
||||||
self.string_ops(rep_op.clone().get())?;
|
if self.regs.cx.read() == 0 {
|
||||||
|
break;
|
||||||
if self.flags.zf == z {
|
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.string_ops(rep_op.clone().get())?;
|
||||||
self.regs.cx.write(self.regs.cx.read() - 1);
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute string operations.
|
/// Execute string operations.
|
||||||
pub fn string_ops(&mut self, mnemonic: Mnemonic) -> Result<(), InterpreterError> {
|
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 {
|
match mnemonic {
|
||||||
Mnemonic::CMPSB => self.cmp(
|
Mnemonic::CMPSB => {
|
||||||
|
self.cmp(
|
||||||
ModRmTarget::Register(crate::register::Register::AL),
|
ModRmTarget::Register(crate::register::Register::AL),
|
||||||
ArithmeticOperand::Immediate(ImmediateOperand::Byte(self.read_esdi()? as Byte)),
|
ArithmeticOperand::Immediate(ImmediateOperand::Byte(self.read_esdi()? as Byte)),
|
||||||
),
|
)?;
|
||||||
Mnemonic::CMPSW => self.cmp(
|
adjust_sidi(self, 1);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Mnemonic::CMPSW => {
|
||||||
|
self.cmp(
|
||||||
ModRmTarget::Register(crate::register::Register::AL),
|
ModRmTarget::Register(crate::register::Register::AL),
|
||||||
ArithmeticOperand::Immediate(self.read_esdi()?.into()),
|
ArithmeticOperand::Immediate(self.read_esdi()?.into()),
|
||||||
),
|
)?;
|
||||||
Mnemonic::SCASB => self.cmp(
|
adjust_sidi(self, 2);
|
||||||
ModRmTarget::Memory(self.regs.si.into()),
|
Ok(())
|
||||||
|
}
|
||||||
|
Mnemonic::SCASB => {
|
||||||
|
self.cmp(
|
||||||
|
ModRmTarget::Register(crate::register::Register::AL),
|
||||||
ArithmeticOperand::Immediate(ImmediateOperand::Byte(self.read_esdi()? as Byte)),
|
ArithmeticOperand::Immediate(ImmediateOperand::Byte(self.read_esdi()? as Byte)),
|
||||||
),
|
)?;
|
||||||
Mnemonic::SCASW => self.cmp(
|
if self.flags.df {
|
||||||
ModRmTarget::Memory(self.regs.si.into()),
|
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)),
|
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 => {
|
Mnemonic::MOVSB => {
|
||||||
let addr =
|
let addr =
|
||||||
self.mem_addr(self.regs.di.into(), &crate::register::SegmentRegister::ES);
|
self.mem_addr(self.regs.di.into(), &crate::register::SegmentRegister::ES);
|
||||||
let val = self.read(self.regs.si.into())?;
|
let val = self.read(self.regs.si.into())?;
|
||||||
self.memory
|
self.memory
|
||||||
.write_raw(addr, ImmediateOperand::Byte(val as u8))?;
|
.write_raw(addr, ImmediateOperand::Byte(val as u8))?;
|
||||||
|
adjust_sidi(self, 1);
|
||||||
if self.flags.df {
|
|
||||||
self.regs.si -= 1;
|
|
||||||
self.regs.di -= 1;
|
|
||||||
} else {
|
|
||||||
self.regs.si += 1;
|
|
||||||
self.regs.di += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -525,14 +565,33 @@ impl Computer {
|
|||||||
self.mem_addr(self.regs.di.into(), &crate::register::SegmentRegister::ES);
|
self.mem_addr(self.regs.di.into(), &crate::register::SegmentRegister::ES);
|
||||||
let val = self.read(self.regs.si.into())?;
|
let val = self.read(self.regs.si.into())?;
|
||||||
self.memory.write_raw(addr, val.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 {
|
if self.flags.df {
|
||||||
self.regs.si -= 2;
|
|
||||||
self.regs.di -= 2;
|
self.regs.di -= 2;
|
||||||
} else {
|
} else {
|
||||||
self.regs.si += 2;
|
|
||||||
self.regs.di += 2;
|
self.regs.di += 2;
|
||||||
}
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -643,8 +643,6 @@ impl Interpreter {
|
|||||||
/*
|
/*
|
||||||
* String Byte Operations
|
* String Byte Operations
|
||||||
*/
|
*/
|
||||||
Mnemonic::STOSB => todo!(),
|
|
||||||
Mnemonic::STOSW => todo!(),
|
|
||||||
Mnemonic::LODSB => todo!(),
|
Mnemonic::LODSB => todo!(),
|
||||||
Mnemonic::LODSW => todo!(),
|
Mnemonic::LODSW => todo!(),
|
||||||
|
|
||||||
@@ -654,6 +652,8 @@ impl Interpreter {
|
|||||||
Mnemonic::CMPSW => self.computer.string_ops(current_instruction.mnemonic)?,
|
Mnemonic::CMPSW => self.computer.string_ops(current_instruction.mnemonic)?,
|
||||||
Mnemonic::MOVSB => 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::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
|
* RET
|
||||||
|
|||||||
Reference in New Issue
Block a user