ft(interpreter): use DS and SS sregs as correct segment offsets
This commit is contained in:
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user