diff --git a/src/lib.rs b/src/lib.rs index b42088e..1f641d1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ pub mod memory; pub mod stack; +use std::cell::{Cell, RefCell, RefMut}; use std::rc::Rc; use std::*; @@ -73,8 +74,10 @@ impl Device for SystemDevice { fn deo1(&mut self, vm: &mut Uxn, port: u8, val: u8) { let slot = port & 0xF; match slot { - 0x2 => vm.wst.idx = val, - 0x3 => vm.rst.idx = val, + // Note: This VM does not support mutating the stack pointers. + // This operation is not well defined upstream + 0x2 => panic!("Invoked unsupported mutation of the data stack pointer"), + 0x3 => panic!("Invoked unsupported mutation of the return stack pointer"), x => self.buffer[x as usize] = val, } } @@ -95,9 +98,9 @@ impl Device for SystemDevice { #[derive(Debug)] pub struct Uxn { - memory: Box, + memory: Rc>, // Note: Using Rc so we can start with many NullDevs and replace them - devices: [Box; 16], + devices: [Rc>; 16], pc: u16, // Program counter wst: Stack, // Data stack rst: Stack, // Return stack pointer @@ -106,24 +109,24 @@ pub struct Uxn { impl Uxn { pub fn new() -> Uxn { Uxn { - memory: Box::new(TrivialMemory::new()), + memory: Rc::new(RefCell::new(TrivialMemory::new())), devices: [ - Box::new(SystemDevice::new()), // #00 - Box::new(NullDevice::new()), // #01 - Box::new(NullDevice::new()), // #02 - Box::new(NullDevice::new()), // #03 - Box::new(NullDevice::new()), // #04 - Box::new(NullDevice::new()), // #05 - Box::new(NullDevice::new()), // #06 - Box::new(NullDevice::new()), // #07 - Box::new(NullDevice::new()), // #08 - Box::new(NullDevice::new()), // #09 - Box::new(NullDevice::new()), // #0a - Box::new(NullDevice::new()), // #0b - Box::new(NullDevice::new()), // #0c - Box::new(NullDevice::new()), // #0d - Box::new(NullDevice::new()), // #0e - Box::new(NullDevice::new()), // #0f + Rc::new(RefCell::new(SystemDevice::new())), // #00 + Rc::new(RefCell::new(NullDevice::new())), // #01 + Rc::new(RefCell::new(NullDevice::new())), // #02 + Rc::new(RefCell::new(NullDevice::new())), // #03 + Rc::new(RefCell::new(NullDevice::new())), // #04 + Rc::new(RefCell::new(NullDevice::new())), // #05 + Rc::new(RefCell::new(NullDevice::new())), // #06 + Rc::new(RefCell::new(NullDevice::new())), // #07 + Rc::new(RefCell::new(NullDevice::new())), // #08 + Rc::new(RefCell::new(NullDevice::new())), // #09 + Rc::new(RefCell::new(NullDevice::new())), // #0a + Rc::new(RefCell::new(NullDevice::new())), // #0b + Rc::new(RefCell::new(NullDevice::new())), // #0c + Rc::new(RefCell::new(NullDevice::new())), // #0d + Rc::new(RefCell::new(NullDevice::new())), // #0e + Rc::new(RefCell::new(NullDevice::new())), // #0f ], pc: 0x0100, wst: Stack::new(), @@ -132,27 +135,26 @@ impl Uxn { } pub fn is_halted(&mut self) -> bool { - let dev = self.devices[0].as_mut(); - dev.dei1(self, 0x0f) != 0 + self.dei1(0x0f) != 0 + } + + fn device(&self, port: u8) -> Rc> { + Rc::clone(&self.devices[(port & 0xF0 >> 4) as usize]) } pub fn dei1(&mut self, port: u8) -> u8 { - let dev = self.devices[(port & 0xF0 >> 4) as usize]; - dev.dei1(self, port) + self.device(port).borrow_mut().dei1(self, port) } pub fn dei2(&mut self, port: u8) -> u16 { - let dev = self.devices[(port & 0xF0 >> 4) as usize]; - dev.dei2(self, port) + self.device(port).borrow_mut().dei2(self, port) } pub fn deo1(&mut self, port: u8, val: u8) { - let dev = self.devices[(port & 0xF0 >> 4) as usize].as_mut(); - dev.deo1(self, port, val) + self.device(port).borrow_mut().deo1(self, port, val); } pub fn deo2(&mut self, port: u8, val: u16) { - let dev = self.devices[(port & 0xF0 >> 4) as usize].as_mut(); - dev.deo2(self, port, val) + self.device(port).borrow_mut().deo2(self, port, val); } } diff --git a/src/stack.rs b/src/stack.rs index f496201..d3bfe37 100644 --- a/src/stack.rs +++ b/src/stack.rs @@ -39,20 +39,55 @@ impl Stack { } } - pub fn pop1(&mut self) -> Result { + pub fn get1(&self, idx: u8) -> Result { + Ok(self.buff[idx as usize]) + } + + pub fn peek1(&self) -> Result { if self.idx == 0 { Err(StackError::StackUnderflow) } else { - self.idx -= 1; - Ok(self.buff[self.idx as usize]) + Ok(self.get1(self.idx - 1)?) + } + } + + pub fn pop1(&mut self) -> Result { + let val = self.peek1()?; + self.idx -= 1; + Ok(val) + } + + pub fn get2(&self, idx: u8) -> Result { + if idx == 255 { + Err(StackError::StackOverflow) + } else { + let high = self.buff[idx as usize] as u16; + let low = self.buff[(idx + 1) as usize] as u16; + Ok((high << 8) + low) + } + } + + pub fn peek2(&mut self) -> Result { + if self.idx < 2 { + Err(StackError::StackUnderflow) + } else { + self.get2(self.idx - 2) } } pub fn pop2(&mut self) -> Result { - if self.idx < 2 { - Err(StackError::StackUnderflow) - } else { - Ok(((self.pop1()? as u16) << 8) + self.pop1()? as u16) - } + let val = self.peek2()?; + self.idx -= 2; + Ok(val) + } + + pub fn move1(&mut self, other: &mut Stack) -> Result<(), StackError> { + other.push1(self.pop1()?)?; + Ok(()) + } + + pub fn move2(&mut self, other: &mut Stack) -> Result<(), StackError> { + other.push2(self.pop2()?)?; + Ok(()) } }