diff --git a/src/interpreter/computer.rs b/src/interpreter/computer.rs index a55d2d9..36afb5c 100644 --- a/src/interpreter/computer.rs +++ b/src/interpreter/computer.rs @@ -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()) } } diff --git a/src/interpreter/interpreter.rs b/src/interpreter/interpreter.rs index 57568cd..9cfff84 100644 --- a/src/interpreter/interpreter.rs +++ b/src/interpreter/interpreter.rs @@ -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:?}") - } } } } diff --git a/src/interpreter/memory.rs b/src/interpreter/memory.rs index 10b0905..e8e8eea 100644 --- a/src/interpreter/memory.rs +++ b/src/interpreter/memory.rs @@ -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 { 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(); diff --git a/src/interpreter/register.rs b/src/interpreter/register.rs index 8f88be3..6df45e5 100644 --- a/src/interpreter/register.rs +++ b/src/interpreter/register.rs @@ -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`]. diff --git a/src/main.rs b/src/main.rs index d27047d..018f034 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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, } 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();