ft(interpreter): impl simple stack init
This commit is contained in:
@@ -1,6 +1,10 @@
|
|||||||
|
use clap::Parser;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
use crate::operands::{ImmediateOperand, ImmediateOperandSigned, MemoryIndex, ModRmTarget, Word};
|
use crate::{
|
||||||
|
Args,
|
||||||
|
operands::{ImmediateOperand, ImmediateOperandSigned, MemoryIndex, ModRmTarget, Word},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
flags::Flags, interpreter::InterpreterError, memory::Memory, register::Register,
|
flags::Flags, interpreter::InterpreterError, memory::Memory, register::Register,
|
||||||
@@ -28,17 +32,80 @@ pub struct Computer {
|
|||||||
|
|
||||||
impl Computer {
|
impl Computer {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
let mut computer = Self {
|
||||||
regs: Register::new(),
|
regs: Register::new(),
|
||||||
sregs: SegmentRegister::new(),
|
sregs: SegmentRegister::new(),
|
||||||
flags: Flags::new(),
|
flags: Flags::new(),
|
||||||
memory: Memory::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.
|
/// 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_sp()?;
|
self.regs.push_sp();
|
||||||
self.memory.write_raw(
|
self.memory.write_raw(
|
||||||
self.mem_addr(
|
self.mem_addr(
|
||||||
ImmediateOperand::from(self.regs.sp).into(),
|
ImmediateOperand::from(self.regs.sp).into(),
|
||||||
@@ -54,7 +121,7 @@ impl Computer {
|
|||||||
ImmediateOperand::from(self.regs.sp).into(),
|
ImmediateOperand::from(self.regs.sp).into(),
|
||||||
&crate::register::SegmentRegister::SS,
|
&crate::register::SegmentRegister::SS,
|
||||||
))?;
|
))?;
|
||||||
self.regs.pop_sp()?;
|
self.regs.pop_sp();
|
||||||
Ok(word)
|
Ok(word)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,7 +462,7 @@ mod tests {
|
|||||||
fn test_push() {
|
fn test_push() {
|
||||||
let mut c = Computer::new();
|
let mut c = Computer::new();
|
||||||
let val = ImmediateOperand::Word(0x1234);
|
let val = ImmediateOperand::Word(0x1234);
|
||||||
c.push_stack(val).unwrap();
|
println!("{}", c.regs);
|
||||||
assert_eq!(val, c.pop_stack().unwrap().into())
|
assert_eq!(val, c.pop_stack().unwrap().into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ pub enum InterpreterError {
|
|||||||
InvalidSyscall(Byte),
|
InvalidSyscall(Byte),
|
||||||
InstructionNotFound(Word),
|
InstructionNotFound(Word),
|
||||||
MemoryOutOfBound(Word),
|
MemoryOutOfBound(Word),
|
||||||
InvalidRegisterState(crate::interpreter::register::Register),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for InterpreterError {
|
impl fmt::Display for InterpreterError {
|
||||||
@@ -43,9 +42,6 @@ impl fmt::Display for InterpreterError {
|
|||||||
"Attempted memory write out of physical bounds: ({addr:#04x})"
|
"Attempted memory write out of physical bounds: ({addr:#04x})"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
InterpreterError::InvalidRegisterState(reg) => {
|
|
||||||
write!(f, "Invalid Register State: {reg:?}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ const MEMORY_SIZE: usize = 1048576;
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Memory {
|
pub struct Memory {
|
||||||
memory: [Byte; MEMORY_SIZE as usize],
|
pub raw: [Byte; MEMORY_SIZE as usize],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Memory {
|
impl Memory {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
memory: [0; MEMORY_SIZE as usize],
|
raw: [0; MEMORY_SIZE as usize],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,12 +25,12 @@ impl Memory {
|
|||||||
} else {
|
} else {
|
||||||
match val {
|
match val {
|
||||||
ImmediateOperand::Byte(b) => {
|
ImmediateOperand::Byte(b) => {
|
||||||
self.memory[addr as usize] = b;
|
self.raw[addr as usize] = b;
|
||||||
}
|
}
|
||||||
ImmediateOperand::Word(w) => {
|
ImmediateOperand::Word(w) => {
|
||||||
let [low, high] = w.to_le_bytes();
|
let [low, high] = w.to_le_bytes();
|
||||||
self.memory[addr as usize] = low;
|
self.raw[addr as usize] = low;
|
||||||
self.memory[(addr + 1) as usize] = high;
|
self.raw[(addr + 1) as usize] = high;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -41,12 +41,12 @@ impl Memory {
|
|||||||
/// Warning: Does access at `addr`, not `DS:addr`!
|
/// Warning: Does access at `addr`, not `DS:addr`!
|
||||||
pub fn read_raw(&self, addr: Word) -> Result<Word, InterpreterError> {
|
pub fn read_raw(&self, addr: Word) -> Result<Word, InterpreterError> {
|
||||||
let b1 = self
|
let b1 = self
|
||||||
.memory
|
.raw
|
||||||
.get(addr as usize)
|
.get(addr as usize)
|
||||||
.ok_or(InterpreterError::MemoryOutOfBound(addr))?
|
.ok_or(InterpreterError::MemoryOutOfBound(addr))?
|
||||||
.to_owned();
|
.to_owned();
|
||||||
let b2 = self
|
let b2 = self
|
||||||
.memory
|
.raw
|
||||||
.get((addr + 1) as usize)
|
.get((addr + 1) as usize)
|
||||||
.ok_or(InterpreterError::MemoryOutOfBound(addr))?
|
.ok_or(InterpreterError::MemoryOutOfBound(addr))?
|
||||||
.to_owned();
|
.to_owned();
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ impl Register {
|
|||||||
bx: BX::new(),
|
bx: BX::new(),
|
||||||
cx: CX::new(),
|
cx: CX::new(),
|
||||||
dx: DX::new(),
|
dx: DX::new(),
|
||||||
sp: 0xffda,
|
sp: 0,
|
||||||
bp: 0,
|
bp: 0,
|
||||||
si: 0,
|
si: 0,
|
||||||
di: 0,
|
di: 0,
|
||||||
@@ -30,23 +30,17 @@ impl Register {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Decrement stack pointer
|
/// Decrement stack pointer
|
||||||
pub fn push_sp(&mut self) -> Result<(), InterpreterError> {
|
pub fn push_sp(&mut self) {
|
||||||
if self.sp < 2 {
|
log::debug!("SP before push: {:04x}", self.sp);
|
||||||
return Err(InterpreterError::InvalidRegisterState(*self));
|
self.sp = self.sp.wrapping_sub(2);
|
||||||
} else {
|
log::debug!("SP after push: {:04x}", self.sp);
|
||||||
self.sp -= 2;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Increment stack pointer
|
/// Increment stack pointer
|
||||||
pub fn pop_sp(&mut self) -> Result<(), InterpreterError> {
|
pub fn pop_sp(&mut self) {
|
||||||
if self.sp > 0xffff - 2 {
|
log::debug!("SP before pop: {:04x}", self.sp);
|
||||||
return Err(InterpreterError::InvalidRegisterState(*self));
|
self.sp = self.sp.wrapping_add(2);
|
||||||
} else {
|
log::debug!("SP after pop: {:04x}", self.sp);
|
||||||
self.sp += 2;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read value from a [`crate::register::Register`].
|
/// Read value from a [`crate::register::Register`].
|
||||||
|
|||||||
14
src/main.rs
14
src/main.rs
@@ -36,11 +36,23 @@ struct Args {
|
|||||||
/// Dump progress of disassembly, in case of encountering an error.
|
/// Dump progress of disassembly, in case of encountering an error.
|
||||||
#[arg(short, long, global = true, action)]
|
#[arg(short, long, global = true, action)]
|
||||||
dump: bool,
|
dump: bool,
|
||||||
|
|
||||||
|
/// argv passed to the program, which will be interpreted
|
||||||
|
#[arg(trailing_var_arg = true, global = true)]
|
||||||
|
argv: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
Builder::new()
|
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()
|
.parse_default_env()
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user