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.
|
/// 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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user