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.
pub fn push_stack(&mut self, val: ImmediateOperand) -> Result<(), InterpreterError> {
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.
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()?;
Ok(word)
}
@@ -153,7 +154,7 @@ impl Computer {
ArithmeticOperand::ModRmTarget(mod_rm_target) => {
ArithmeticOperand::Immediate(match mod_rm_target {
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,
})
@@ -181,7 +182,7 @@ impl Computer {
ArithmeticOperand::ModRmTarget(mod_rm_target) => {
ArithmeticOperand::Immediate(match mod_rm_target {
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,
})
@@ -228,7 +229,7 @@ impl Computer {
/// Write an [`ImmediateOperand`] into [`Self::memory`] or [`Self::regs`].
pub fn write_modrm(&mut self, target: ModRmTarget, val: ImmediateOperand) {
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),
};
}
@@ -236,7 +237,7 @@ impl Computer {
/// Read an [`ImmediateOperand`] from [`Self::memory`] or [`Self::regs`].
pub fn read_modrm(&self, target: ModRmTarget) -> ImmediateOperand {
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),
}
}

View File

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

View File

@@ -1,6 +1,7 @@
use crate::operands::{Byte, Displacement, ImmediateOperand, MemoryIndex, Word};
use super::interpreter::InterpreterError;
use crate::interpreter::register::{Register, SegmentRegister};
/// 2*20 = 1MiB
const MEMORY_SIZE: usize = 1048576;
@@ -18,28 +19,30 @@ impl Memory {
}
/// Safely writes a [`Word`] into an index of memory.
pub fn write_raw(&mut self, idx: Word, val: Word) -> Result<(), InterpreterError> {
if (idx + 1) as usize > MEMORY_SIZE {
return Err(InterpreterError::MemoryOutOfBound(idx));
/// Warning: Does access at `addr`, not `DS:addr`!
pub fn write_raw(&mut self, addr: Word, val: Word) -> Result<(), InterpreterError> {
if (addr + 1) as usize > MEMORY_SIZE {
return Err(InterpreterError::MemoryOutOfBound(addr));
} else {
let [low, high] = val.to_le_bytes();
self.memory[idx as usize] = low;
self.memory[(idx + 1) as usize] = high;
self.memory[addr as usize] = low;
self.memory[(addr + 1) as usize] = high;
Ok(())
}
}
/// Safely reads a [`Word`] from an index of memory
pub fn read_raw(&self, idx: Word) -> Result<Word, InterpreterError> {
/// Safely reads a [`Word`] from an index of memory.
/// Warning: Does access at `addr`, not `DS:addr`!
pub fn read_raw(&self, addr: Word) -> Result<Word, InterpreterError> {
let b1 = self
.memory
.get(idx as usize)
.ok_or(InterpreterError::MemoryOutOfBound(idx))?
.get(addr as usize)
.ok_or(InterpreterError::MemoryOutOfBound(addr))?
.to_owned();
let b2 = self
.memory
.get((idx + 1) as usize)
.ok_or(InterpreterError::MemoryOutOfBound(idx))?
.get((addr + 1) as usize)
.ok_or(InterpreterError::MemoryOutOfBound(addr))?
.to_owned();
Ok(Word::from_be_bytes([b2, b1]))
}
@@ -47,11 +50,12 @@ impl Memory {
/// Write an [`ImmediateOperand`] to a memory location indexed by a [`MemoryIndex`].
pub fn write(
&mut self,
regs: &crate::interpreter::register::Register,
regs: &Register,
sregs: &SegmentRegister,
idx: MemoryIndex,
val: ImmediateOperand,
) {
let idx = Memory::calc_memidx(regs, idx);
let idx = Memory::absolute_addr_from_idx(regs, sregs, idx);
match val {
ImmediateOperand::Byte(b) => {
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.
/// Always reads a whole word.
pub fn read(&self, regs: &crate::interpreter::register::Register, idx: MemoryIndex) -> Word {
let idx = Self::calc_memidx(regs, idx);
pub fn read(&self, regs: &Register, sregs: &SegmentRegister, idx: MemoryIndex) -> Word {
let idx = Self::absolute_addr_from_idx(regs, sregs, idx);
let byte1 = idx / 2;
let byte2 = idx / 2 + 1;
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]])
}
/// 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.
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 index = ImmediateOperand::Word(0);
let mut disp = Displacement::IWord(0);
@@ -96,6 +109,6 @@ impl Memory {
disp = displacement;
}
(base + index + disp).into()
Self::addr_offset((base + index + disp).into(), sregs)
}
}