ft(interpreter): impl simple stack init

This commit is contained in:
2025-06-25 16:19:23 +09:00
parent 0db309b668
commit 13cb907977
5 changed files with 101 additions and 32 deletions

View File

@@ -1,6 +1,10 @@
use clap::Parser;
use core::fmt;
use crate::operands::{ImmediateOperand, ImmediateOperandSigned, MemoryIndex, ModRmTarget, Word};
use crate::{
Args,
operands::{ImmediateOperand, ImmediateOperandSigned, MemoryIndex, ModRmTarget, Word},
};
use super::{
flags::Flags, interpreter::InterpreterError, memory::Memory, register::Register,
@@ -28,17 +32,80 @@ pub struct Computer {
impl Computer {
pub fn new() -> Self {
Self {
let mut computer = Self {
regs: Register::new(),
sregs: SegmentRegister::new(),
flags: Flags::new(),
memory: Memory::new(),
};
// Initialization cannot fail
computer.init_stack().unwrap();
// for (idx, val) in computer.memory.raw.iter().enumerate() {
// if idx > 0xfff9 && idx <= 0xffff {
// log::debug!("MEMORY {idx}: {val}");
// }
// }
computer
}
fn init_stack(&mut self) -> Result<(), InterpreterError> {
let args = Args::parse();
let argv = args.argv;
let argc = argv.len() + 1;
let mut argv_ptrs = Vec::new();
let envs = Vec::from(["PATH=/usr:/usr/bin".to_string()]);
let mut env_ptrs = Vec::new();
// Padding
let total_len_argv: usize = argv.iter().map(|i| i.len()).sum();
let total_len_env: usize = envs.iter().map(|i| i.len()).sum();
if total_len_argv + total_len_env % 2 != 0 {
self.push_stack(ImmediateOperand::Byte(0))?;
}
// Write env
for env in envs.iter() {
for b in env.chars().rev() {
self.push_stack(ImmediateOperand::Byte(b as u8))?;
}
env_ptrs.push(self.regs.sp);
}
// Write argv
for arg in argv.iter() {
// self.push_stack(ImmediateOperand::Byte(0))?;
for b in arg.chars().rev() {
self.push_stack(ImmediateOperand::Byte(b as u8))?;
}
argv_ptrs.push(self.regs.sp);
}
// add env ptrs
for addr in env_ptrs {
self.push_stack(addr.into())?;
}
// delimiter
self.push_stack(ImmediateOperand::Word(0))?;
// add argv ptrs
for addr in argv_ptrs {
self.push_stack(addr.into())?;
}
// add argc
self.push_stack(ImmediateOperand::Word(argc as Word))?;
Ok(())
}
/// Decrement stack pointer and write `val` onto the stack.
pub fn push_stack(&mut self, val: ImmediateOperand) -> Result<(), InterpreterError> {
self.regs.push_sp()?;
self.regs.push_sp();
self.memory.write_raw(
self.mem_addr(
ImmediateOperand::from(self.regs.sp).into(),
@@ -54,7 +121,7 @@ impl Computer {
ImmediateOperand::from(self.regs.sp).into(),
&crate::register::SegmentRegister::SS,
))?;
self.regs.pop_sp()?;
self.regs.pop_sp();
Ok(word)
}
@@ -395,7 +462,7 @@ mod tests {
fn test_push() {
let mut c = Computer::new();
let val = ImmediateOperand::Word(0x1234);
c.push_stack(val).unwrap();
println!("{}", c.regs);
assert_eq!(val, c.pop_stack().unwrap().into())
}
}

View File

@@ -24,7 +24,6 @@ pub enum InterpreterError {
InvalidSyscall(Byte),
InstructionNotFound(Word),
MemoryOutOfBound(Word),
InvalidRegisterState(crate::interpreter::register::Register),
}
impl fmt::Display for InterpreterError {
@@ -43,9 +42,6 @@ impl fmt::Display for InterpreterError {
"Attempted memory write out of physical bounds: ({addr:#04x})"
)
}
InterpreterError::InvalidRegisterState(reg) => {
write!(f, "Invalid Register State: {reg:?}")
}
}
}
}

View File

@@ -7,13 +7,13 @@ const MEMORY_SIZE: usize = 1048576;
#[derive(Debug, Clone, Copy)]
pub struct Memory {
memory: [Byte; MEMORY_SIZE as usize],
pub raw: [Byte; MEMORY_SIZE as usize],
}
impl Memory {
pub fn new() -> Self {
Self {
memory: [0; MEMORY_SIZE as usize],
raw: [0; MEMORY_SIZE as usize],
}
}
@@ -25,12 +25,12 @@ impl Memory {
} else {
match val {
ImmediateOperand::Byte(b) => {
self.memory[addr as usize] = b;
self.raw[addr as usize] = b;
}
ImmediateOperand::Word(w) => {
let [low, high] = w.to_le_bytes();
self.memory[addr as usize] = low;
self.memory[(addr + 1) as usize] = high;
self.raw[addr as usize] = low;
self.raw[(addr + 1) as usize] = high;
}
}
}
@@ -41,12 +41,12 @@ impl Memory {
/// Warning: Does access at `addr`, not `DS:addr`!
pub fn read_raw(&self, addr: Word) -> Result<Word, InterpreterError> {
let b1 = self
.memory
.raw
.get(addr as usize)
.ok_or(InterpreterError::MemoryOutOfBound(addr))?
.to_owned();
let b2 = self
.memory
.raw
.get((addr + 1) as usize)
.ok_or(InterpreterError::MemoryOutOfBound(addr))?
.to_owned();

View File

@@ -22,7 +22,7 @@ impl Register {
bx: BX::new(),
cx: CX::new(),
dx: DX::new(),
sp: 0xffda,
sp: 0,
bp: 0,
si: 0,
di: 0,
@@ -30,23 +30,17 @@ impl Register {
}
/// Decrement stack pointer
pub fn push_sp(&mut self) -> Result<(), InterpreterError> {
if self.sp < 2 {
return Err(InterpreterError::InvalidRegisterState(*self));
} else {
self.sp -= 2;
Ok(())
}
pub fn push_sp(&mut self) {
log::debug!("SP before push: {:04x}", self.sp);
self.sp = self.sp.wrapping_sub(2);
log::debug!("SP after push: {:04x}", self.sp);
}
/// Increment stack pointer
pub fn pop_sp(&mut self) -> Result<(), InterpreterError> {
if self.sp > 0xffff - 2 {
return Err(InterpreterError::InvalidRegisterState(*self));
} else {
self.sp += 2;
Ok(())
}
pub fn pop_sp(&mut self) {
log::debug!("SP before pop: {:04x}", self.sp);
self.sp = self.sp.wrapping_add(2);
log::debug!("SP after pop: {:04x}", self.sp);
}
/// Read value from a [`crate::register::Register`].

View File

@@ -36,11 +36,23 @@ struct Args {
/// Dump progress of disassembly, in case of encountering an error.
#[arg(short, long, global = true, action)]
dump: bool,
/// argv passed to the program, which will be interpreted
#[arg(trailing_var_arg = true, global = true)]
argv: Vec<String>,
}
fn main() {
Builder::new()
.format(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args()))
.format(|buf, record| {
writeln!(
buf,
"{} {}: {}",
record.target(),
record.level(),
record.args()
)
})
.parse_default_env()
.init();