ft(interpreter): use DS and SS sregs as correct segment offsets

This commit is contained in:
2025-06-18 17:03:01 +09:00
parent 4aeacc649a
commit 5a61eb5fd6
3 changed files with 58 additions and 32 deletions

View File

@@ -39,12 +39,13 @@ impl Computer {
/// Decrement stack pointer and write `val` onto the stack. /// Decrement stack pointer and write `val` onto the stack.
pub fn push_stack(&mut self, val: ImmediateOperand) -> Result<(), InterpreterError> { pub fn push_stack(&mut self, val: ImmediateOperand) -> Result<(), InterpreterError> {
self.regs.push()?; self.regs.push()?;
self.memory.write_raw(self.regs.sp, val.into()) self.memory
.write_raw(&self.sregs.ss * 16 + self.regs.sp, val.into())
} }
/// Retrieve value from stack and increment stack pointer. /// Retrieve value from stack and increment stack pointer.
pub fn pop_stack(&mut self) -> Result<Word, InterpreterError> { pub fn pop_stack(&mut self) -> Result<Word, InterpreterError> {
let word = self.memory.read_raw(self.regs.sp)?; let word = self.memory.read_raw(&self.sregs.ss * 16 + self.regs.sp)?;
self.regs.pop()?; self.regs.pop()?;
Ok(word) Ok(word)
} }
@@ -153,7 +154,7 @@ impl Computer {
ArithmeticOperand::ModRmTarget(mod_rm_target) => { ArithmeticOperand::ModRmTarget(mod_rm_target) => {
ArithmeticOperand::Immediate(match mod_rm_target { ArithmeticOperand::Immediate(match mod_rm_target {
ModRmTarget::Memory(idx) => { ModRmTarget::Memory(idx) => {
(self.memory.read(&self.regs, idx) + cf as u16).into() (self.memory.read(&self.regs, &self.sregs, idx) + cf as u16).into()
} }
ModRmTarget::Register(reg) => self.regs.read(reg) + cf, ModRmTarget::Register(reg) => self.regs.read(reg) + cf,
}) })
@@ -181,7 +182,7 @@ impl Computer {
ArithmeticOperand::ModRmTarget(mod_rm_target) => { ArithmeticOperand::ModRmTarget(mod_rm_target) => {
ArithmeticOperand::Immediate(match mod_rm_target { ArithmeticOperand::Immediate(match mod_rm_target {
ModRmTarget::Memory(idx) => { ModRmTarget::Memory(idx) => {
(self.memory.read(&self.regs, idx) + cf as u16).into() (self.memory.read(&self.regs, &self.sregs, idx) + cf as u16).into()
} }
ModRmTarget::Register(reg) => self.regs.read(reg) + cf, ModRmTarget::Register(reg) => self.regs.read(reg) + cf,
}) })
@@ -228,7 +229,7 @@ impl Computer {
/// Write an [`ImmediateOperand`] into [`Self::memory`] or [`Self::regs`]. /// Write an [`ImmediateOperand`] into [`Self::memory`] or [`Self::regs`].
pub fn write_modrm(&mut self, target: ModRmTarget, val: ImmediateOperand) { pub fn write_modrm(&mut self, target: ModRmTarget, val: ImmediateOperand) {
match target { match target {
ModRmTarget::Memory(idx) => self.memory.write(&self.regs, idx, val), ModRmTarget::Memory(idx) => self.memory.write(&self.regs, &self.sregs, idx, val),
ModRmTarget::Register(reg) => self.regs.write(reg, val), ModRmTarget::Register(reg) => self.regs.write(reg, val),
}; };
} }
@@ -236,7 +237,7 @@ impl Computer {
/// Read an [`ImmediateOperand`] from [`Self::memory`] or [`Self::regs`]. /// Read an [`ImmediateOperand`] from [`Self::memory`] or [`Self::regs`].
pub fn read_modrm(&self, target: ModRmTarget) -> ImmediateOperand { pub fn read_modrm(&self, target: ModRmTarget) -> ImmediateOperand {
match target { match target {
ModRmTarget::Memory(idx) => self.memory.read(&self.regs, idx).into(), ModRmTarget::Memory(idx) => self.memory.read(&self.regs, &self.sregs, idx).into(),
ModRmTarget::Register(reg) => self.regs.read(reg), ModRmTarget::Register(reg) => self.regs.read(reg),
} }
} }

View File

@@ -125,9 +125,15 @@ impl Interpreter {
} }
Mnemonic::POP_M(idx) => { Mnemonic::POP_M(idx) => {
let val = self.computer.pop_stack()?.into(); let val = self.computer.pop_stack()?.into();
self.computer self.computer.memory.write_raw(
.memory Memory::absolute_addr_from_idx(
.write_raw(Memory::calc_memidx(&self.computer.regs, idx).into(), val)? &self.computer.regs,
&self.computer.sregs,
idx,
)
.into(),
val,
)?
} }
Mnemonic::POP_S(_) => todo!(), Mnemonic::POP_S(_) => todo!(),
@@ -430,7 +436,10 @@ impl Interpreter {
&self.instructions, &self.instructions,
&mut ip, &mut ip,
&self.computer.sregs, &self.computer.sregs,
self.computer.memory.read(&self.computer.regs, idx).into(), self.computer
.memory
.read(&self.computer.regs, &self.computer.sregs, idx)
.into(),
), ),
ModRmTarget::Register(register) => Self::ip_jump( ModRmTarget::Register(register) => Self::ip_jump(
&self.instructions, &self.instructions,
@@ -563,9 +572,12 @@ impl Interpreter {
*/ */
Mnemonic::LEA(target, reg) => { Mnemonic::LEA(target, reg) => {
let val = match target { let val = match target {
ModRmTarget::Memory(idx) => { ModRmTarget::Memory(idx) => Memory::absolute_addr_from_idx(
Memory::calc_memidx(&self.computer.regs, idx).into() &self.computer.regs,
} &self.computer.sregs,
idx,
)
.into(),
ModRmTarget::Register(reg) => self.computer.regs.read(reg), ModRmTarget::Register(reg) => self.computer.regs.read(reg),
}; };
self.computer.regs.write(reg, val); self.computer.regs.write(reg, val);
@@ -709,7 +721,7 @@ impl Interpreter {
Mnemonic::SHR_b(target, b) => self Mnemonic::SHR_b(target, b) => self
.computer .computer
.write_modrm(target, self.computer.read_modrm(target) >> b), .write_modrm(target, self.computer.read_modrm(target) >> b),
Mnemonic::SAR_b(target, b) => todo!(), Mnemonic::SAR_b(_, _) => todo!(),
Mnemonic::SHL_fromReg(target, reg) => self.computer.write_modrm( Mnemonic::SHL_fromReg(target, reg) => self.computer.write_modrm(
target, target,
self.computer.read_modrm(target) << self.computer.regs.read(reg), self.computer.read_modrm(target) << self.computer.regs.read(reg),
@@ -718,7 +730,7 @@ impl Interpreter {
target, target,
self.computer.read_modrm(target) >> self.computer.regs.read(reg), self.computer.read_modrm(target) >> self.computer.regs.read(reg),
), ),
Mnemonic::SAR_fromReg(target, reg) => todo!(), Mnemonic::SAR_fromReg(_, _) => todo!(),
/* /*
* IN * IN

View File

@@ -1,6 +1,7 @@
use crate::operands::{Byte, Displacement, ImmediateOperand, MemoryIndex, Word}; use crate::operands::{Byte, Displacement, ImmediateOperand, MemoryIndex, Word};
use super::interpreter::InterpreterError; use super::interpreter::InterpreterError;
use crate::interpreter::register::{Register, SegmentRegister};
/// 2*20 = 1MiB /// 2*20 = 1MiB
const MEMORY_SIZE: usize = 1048576; const MEMORY_SIZE: usize = 1048576;
@@ -18,28 +19,30 @@ impl Memory {
} }
/// Safely writes a [`Word`] into an index of memory. /// Safely writes a [`Word`] into an index of memory.
pub fn write_raw(&mut self, idx: Word, val: Word) -> Result<(), InterpreterError> { /// Warning: Does access at `addr`, not `DS:addr`!
if (idx + 1) as usize > MEMORY_SIZE { pub fn write_raw(&mut self, addr: Word, val: Word) -> Result<(), InterpreterError> {
return Err(InterpreterError::MemoryOutOfBound(idx)); if (addr + 1) as usize > MEMORY_SIZE {
return Err(InterpreterError::MemoryOutOfBound(addr));
} else { } else {
let [low, high] = val.to_le_bytes(); let [low, high] = val.to_le_bytes();
self.memory[idx as usize] = low; self.memory[addr as usize] = low;
self.memory[(idx + 1) as usize] = high; self.memory[(addr + 1) as usize] = high;
Ok(()) Ok(())
} }
} }
/// Safely reads a [`Word`] from an index of memory /// Safely reads a [`Word`] from an index of memory.
pub fn read_raw(&self, idx: Word) -> Result<Word, InterpreterError> { /// Warning: Does access at `addr`, not `DS:addr`!
pub fn read_raw(&self, addr: Word) -> Result<Word, InterpreterError> {
let b1 = self let b1 = self
.memory .memory
.get(idx as usize) .get(addr as usize)
.ok_or(InterpreterError::MemoryOutOfBound(idx))? .ok_or(InterpreterError::MemoryOutOfBound(addr))?
.to_owned(); .to_owned();
let b2 = self let b2 = self
.memory .memory
.get((idx + 1) as usize) .get((addr + 1) as usize)
.ok_or(InterpreterError::MemoryOutOfBound(idx))? .ok_or(InterpreterError::MemoryOutOfBound(addr))?
.to_owned(); .to_owned();
Ok(Word::from_be_bytes([b2, b1])) Ok(Word::from_be_bytes([b2, b1]))
} }
@@ -47,11 +50,12 @@ impl Memory {
/// Write an [`ImmediateOperand`] to a memory location indexed by a [`MemoryIndex`]. /// Write an [`ImmediateOperand`] to a memory location indexed by a [`MemoryIndex`].
pub fn write( pub fn write(
&mut self, &mut self,
regs: &crate::interpreter::register::Register, regs: &Register,
sregs: &SegmentRegister,
idx: MemoryIndex, idx: MemoryIndex,
val: ImmediateOperand, val: ImmediateOperand,
) { ) {
let idx = Memory::calc_memidx(regs, idx); let idx = Memory::absolute_addr_from_idx(regs, sregs, idx);
match val { match val {
ImmediateOperand::Byte(b) => { ImmediateOperand::Byte(b) => {
log::debug!("Writing byte {b:#04x} to memory location {idx:#04x}"); log::debug!("Writing byte {b:#04x} to memory location {idx:#04x}");
@@ -72,16 +76,25 @@ impl Memory {
/// Read into memory with a [`MemoryIndex`] as index. /// Read into memory with a [`MemoryIndex`] as index.
/// Always reads a whole word. /// Always reads a whole word.
pub fn read(&self, regs: &crate::interpreter::register::Register, idx: MemoryIndex) -> Word { pub fn read(&self, regs: &Register, sregs: &SegmentRegister, idx: MemoryIndex) -> Word {
let idx = Self::calc_memidx(regs, idx); let idx = Self::absolute_addr_from_idx(regs, sregs, idx);
let byte1 = idx / 2; let byte1 = idx / 2;
let byte2 = idx / 2 + 1; let byte2 = idx / 2 + 1;
log::debug!("Reading bytes {byte1:#04x} and {byte2:#04x} from memory"); log::debug!("Reading bytes {byte1:#04x} and {byte2:#04x} from memory");
Word::from_le_bytes([self.memory[byte1 as usize], self.memory[byte2 as usize]]) Word::from_le_bytes([self.memory[byte1 as usize], self.memory[byte2 as usize]])
} }
/// Memory is always accessed with the data segment `ds` register as an offset.
fn addr_offset(addr: Word, sregs: &crate::interpreter::register::SegmentRegister) -> Word {
sregs.ds * 16 + addr
}
/// Calculate the absolute memory address from a [`MemoryIndex`] struct. /// Calculate the absolute memory address from a [`MemoryIndex`] struct.
pub fn calc_memidx(regs: &crate::interpreter::register::Register, idx: MemoryIndex) -> Word { pub fn absolute_addr_from_idx(
regs: &Register,
sregs: &SegmentRegister,
idx: MemoryIndex,
) -> Word {
let mut base = ImmediateOperand::Word(0); let mut base = ImmediateOperand::Word(0);
let mut index = ImmediateOperand::Word(0); let mut index = ImmediateOperand::Word(0);
let mut disp = Displacement::IWord(0); let mut disp = Displacement::IWord(0);
@@ -96,6 +109,6 @@ impl Memory {
disp = displacement; disp = displacement;
} }
(base + index + disp).into() Self::addr_offset((base + index + disp).into(), sregs)
} }
} }