From 8630125e4db56667bcdfe4625e2d270907e7c336 Mon Sep 17 00:00:00 2001 From: Reid 'arrdem' McKenzie Date: Thu, 22 Dec 2022 18:45:20 -0700 Subject: [PATCH] [NO TESTS] WIP --- src/bin/main.rs | 3 +- src/device/system.rs | 4 +- src/stack.rs | 196 ++++++++++++++++++++++++++++++------------- src/vm.rs | 112 ++++++++++++++++++------- 4 files changed, 223 insertions(+), 92 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index 4c27b8e..58a4bbd 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,10 +1,9 @@ use std::env::args; use std::fs::File; -use std::io; use std::io::BufReader; use std::io::Read; -use uxn::Uxn; +use uxn::vm::Uxn; fn main() -> Result<(), std::io::Error> { let mut vm = Uxn::new(); diff --git a/src/device/system.rs b/src/device/system.rs index d29418c..555bf2b 100644 --- a/src/device/system.rs +++ b/src/device/system.rs @@ -19,8 +19,8 @@ impl Device for SystemDevice { fn dei1(&mut self, vm: &mut Uxn, port: u8) -> u8 { let slot = port & 0xF; match slot { - 0x2 => vm.wst.idx, - 0x3 => vm.rst.idx, + 0x2 => vm.wst.borrow().idx(), + 0x3 => vm.rst.borrow().idx(), x => self.buffer[x as usize], } } diff --git a/src/stack.rs b/src/stack.rs index aa37554..5a28970 100644 --- a/src/stack.rs +++ b/src/stack.rs @@ -1,37 +1,66 @@ use std; +use std::cell::RefCell; +use std::rc::Rc; use std::result::Result; -#[derive(Debug)] -pub struct Stack { - buff: [u8; 0xFF], - pub idx: u8, -} - pub enum StackError { StackOverflow, StackUnderflow, } -impl Stack { - pub fn new() -> Stack { - Stack { - buff: [0; 0xFF], - idx: 0, - } +pub trait Stack: std::fmt::Debug { + fn idx(&self) -> u8; + fn push1(&mut self, val: u8) -> Result<(), StackError>; + fn push2(&mut self, val: u16) -> Result<(), StackError>; + fn get1(&self, idx: u8) -> Result; + fn get2(&self, idx: u8) -> Result; + fn peek1(&self) -> Result; + fn peek2(&self) -> Result; + fn pop1(&mut self) -> Result; + fn pop2(&mut self) -> Result; + + fn move1(&mut self, other: &mut dyn Stack) -> Result<(), StackError> { + other.push1(self.pop1()?)?; + Ok(()) } - pub fn push1(&mut self, val: u8) -> Result<(), StackError> { - if self.idx == 255 { + fn move2(&mut self, other: &mut dyn Stack) -> Result<(), StackError> { + other.push2(self.pop2()?)?; + Ok(()) + } +} + +#[derive(Debug)] +pub struct ArrayStack { + buff: [u8; 0xFF], + _idx: u8, +} + +impl ArrayStack { + pub fn new() -> ArrayStack { + ArrayStack { + buff: [0; 0xFF], + _idx: 0, + } + } +} + +impl Stack for ArrayStack { + fn idx(&self) -> u8 { + return self._idx; + } + fn push1(&mut self, val: u8) -> Result<(), StackError> { + if self._idx == 255 { Err(StackError::StackOverflow) } else { - self.buff[self.idx as usize] = val; - self.idx += 1; + self.buff[self._idx as usize] = val; + self._idx += 1; Ok(()) } } - pub fn push2(&mut self, val: u16) -> Result<(), StackError> { - if self.idx > 254 { + fn push2(&mut self, val: u16) -> Result<(), StackError> { + if self._idx > 254 { Err(StackError::StackOverflow) } else { val.to_be_bytes().map(|x| self.push1(x).ok()); @@ -39,133 +68,123 @@ impl Stack { } } - pub fn get1(&self, idx: u8) -> Result { - Ok(self.buff[idx as usize]) + fn get1(&self, _idx: u8) -> Result { + Ok(self.buff[_idx as usize]) } - pub fn peek1(&self) -> Result { - if self.idx == 0 { + fn peek1(&self) -> Result { + if self._idx == 0 { Err(StackError::StackUnderflow) } else { - Ok(self.get1(self.idx - 1)?) + Ok(self.get1(self._idx - 1)?) } } - pub fn pop1(&mut self) -> Result { + fn pop1(&mut self) -> Result { let val = self.peek1()?; - self.idx -= 1; + self._idx -= 1; Ok(val) } - pub fn get2(&self, idx: u8) -> Result { - if idx == 255 { + 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; - println!("idx {}; high {:#02x}; low {:#02x};", idx, high, low); + let high = self.buff[_idx as usize] as u16; + let low = self.buff[(_idx + 1) as usize] as u16; + println!("_idx {}; high {:#02x}; low {:#02x};", _idx, high, low); Ok((high << 8) + low) } } - pub fn peek2(&mut self) -> Result { - if self.idx < 2 { + fn peek2(&self) -> Result { + if self._idx < 2 { Err(StackError::StackUnderflow) } else { - self.get2(self.idx - 2) + self.get2(self._idx - 2) } } - pub fn pop2(&mut self) -> Result { + fn pop2(&mut self) -> Result { let val = self.peek2()?; - self.idx -= 2; + 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(()) - } } #[cfg(test)] -mod stack_test { +mod arraystack_test { use super::*; #[test] fn test_push_pop() { - let mut s = Stack::new(); + let mut s = ArrayStack::new(); match s.push1(0xFF) { Ok(()) => (), Err(_) => assert!(false, "pushing stack of size 0 errored"), } - assert_eq!(s.idx, 1); + assert_eq!(s._idx, 1); match s.peek1() { Ok(val) => assert_eq!(val, 0xFF), Err(_) => assert!(false, "popping stack of size 1 errored"), } - assert_eq!(s.idx, 1); + assert_eq!(s._idx, 1); match s.pop1() { Ok(val) => assert_eq!(val, 0xFF), Err(_) => assert!(false, "popping stack of size 1 errored"), } - assert_eq!(s.idx, 0); + assert_eq!(s._idx, 0); } #[test] fn test_push2_pop2() { - let mut s = Stack::new(); + let mut s = ArrayStack::new(); match s.push2(0xFF00) { Ok(()) => (), Err(_) => assert!(false, "pushing stack of size 0 errored"), } - assert_eq!(s.idx, 2); + assert_eq!(s._idx, 2); match s.peek2() { Ok(val) => assert_eq!(val, 0xFF00), Err(_) => assert!(false, "peek2 stack of size 2 errored"), } - assert_eq!(s.idx, 2); + assert_eq!(s._idx, 2); match s.pop2() { Ok(val) => assert_eq!(val, 0xFF00), Err(_) => assert!(false, "peek2 stack of size 2 errored"), } - assert_eq!(s.idx, 0); + assert_eq!(s._idx, 0); } #[test] fn test_push2_pop1_pop1() { - let mut s = Stack::new(); + let mut s = ArrayStack::new(); match s.push2(0xFF00) { Ok(()) => (), Err(_) => assert!(false, "pushing stack of size 0 errored"), } - assert_eq!(s.idx, 2); + assert_eq!(s._idx, 2); match s.pop1() { Ok(val) => assert_eq!(val, 0x00), Err(_) => assert!(false, "peek1 stack of size 2 errored"), } - assert_eq!(s.idx, 1); + assert_eq!(s._idx, 1); match s.pop1() { Ok(val) => assert_eq!(val, 0xFF), Err(_) => assert!(false, "peek1 stack of size 2 errored"), } - assert_eq!(s.idx, 0); + assert_eq!(s._idx, 0); } #[test] fn test_pop_empty() { - let mut s = Stack::new(); + let mut s = ArrayStack::new(); match s.pop1() { Ok(_) => assert!(false, "popping stack of size 0 succeeded"), Err(StackError::StackUnderflow) => (), @@ -173,3 +192,62 @@ mod stack_test { } } } + +#[derive(Debug)] +enum StackOp { + Push1(u8), + Push2(u16), + Pop1(), + Pop2(), +} + +/** + * A writeahead log wrapping a read copy of another stack. + * Can be committed + */ +#[derive(Debug)] +pub struct StackWAL { + log: Vec, + _idx: u8, + wrapped: Rc>, +} + +impl StackWAL { + pub fn new(wrapped: Rc>) -> StackWAL { + return StackWAL { + log: vec![], + _idx: wrapped.borrow().idx(), + wrapped: wrapped.clone(), + }; + } +} + +impl Stack for StackWAL { + fn idx(&self) -> u8 { + return self._idx; + } + fn push1(&mut self, val: u8) -> Result<(), StackError> { + unimplemented!() + } + fn push2(&mut self, val: u16) -> Result<(), StackError> { + unimplemented!() + } + fn get1(&self, idx: u8) -> Result { + unimplemented!() + } + fn get2(&self, idx: u8) -> Result { + unimplemented!() + } + fn peek1(&self) -> Result { + unimplemented!() + } + fn peek2(&self) -> Result { + unimplemented!() + } + fn pop1(&mut self) -> Result { + unimplemented!() + } + fn pop2(&mut self) -> Result { + unimplemented!() + } +} diff --git a/src/vm.rs b/src/vm.rs index 1a29867..75f9782 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -34,9 +34,9 @@ pub struct Uxn { pub memory: Rc>, // Note: Using Rc so we can start with many NullDevs and replace them pub devices: [Rc>; 16], - pub pc: u16, // Program counter - pub wst: Stack, // Data stack - pub rst: Stack, // Return stack pointer + pub pc: u16, // Program counter + pub wst: Rc>, // Data stack + pub rst: Rc>, // Return stack pointer } impl Uxn { @@ -62,8 +62,8 @@ impl Uxn { Rc::new(RefCell::new(NullDevice::new())), // #0f ], pc: 0x0100, - wst: Stack::new(), - rst: Stack::new(), + wst: Rc::new(RefCell::new(ArrayStack::new())), + rst: Rc::new(RefCell::new(ArrayStack::new())), } } @@ -138,9 +138,9 @@ impl Uxn { let [wst, rst] = { if rflag == 0 { - [&mut self.wst, &mut self.rst] + [self.wst.clone(), self.rst.clone()] } else { - [&mut self.wst, &mut self.rst] + [self.wst.clone(), self.rst.clone()] } }; @@ -152,48 +152,51 @@ impl Uxn { } (_, _, 0, 0x00) => { // LIT1 - wst.push1(self.lda1(self.pc + 1)?); + wst.borrow_mut().push1(self.lda1(self.pc + 1)?); self.pc += 1; continue 'run; } (_, _, 1, 0x00) => { // LIT2 - wst.push2(self.lda2(self.pc + 1)?); + wst.borrow_mut().push2(self.lda2(self.pc + 1)?); self.pc += 2; continue 'run; } (_, _, 0, 0x01) => { // INC1 - let a = wst.pop1()?; - wst.push1(a + 1); + let a = wst.borrow_mut().pop1()?; + wst.borrow_mut().push1(a + 1); } (_, _, 1, 0x01) => { // INC1 - let a = wst.pop2()?; - wst.push2(a + 1); + let a = wst.borrow_mut().pop2()?; + wst.borrow_mut().push2(a + 1); } (_, _, 0, 0x02) => { // POP1 - wst.pop1(); + wst.borrow_mut().pop1(); } (_, _, 1, 0x02) => { // POP2 - wst.pop2(); + wst.borrow_mut().pop2(); } (_, _, 0, 0x03) => { // NIP1 a b -- a + let mut wst = wst.borrow_mut(); let keep = wst.pop1()?; wst.pop1(); wst.push1(keep)?; } (_, _, 1, 0x03) => { // NIP2 a b -- a + let mut wst = wst.borrow_mut(); let keep = wst.pop2()?; wst.pop2()?; wst.push2(keep)?; } (_, _, 0, 0x04) => { // SWP1 + let mut wst = wst.borrow_mut(); let a = wst.pop1()?; let b = wst.pop1()?; wst.push1(a)?; @@ -201,13 +204,15 @@ impl Uxn { } (_, _, 1, 0x04) => { // SWP2 + let mut wst = wst.borrow_mut(); let a = wst.pop2()?; let b = wst.pop2()?; wst.push2(a)?; wst.push2(b)?; } (_, _, 0, 0x05) => { - // ROT + // ROT1 + let mut wst = wst.borrow_mut(); let a = wst.pop1()?; let b = wst.pop1()?; let c = wst.pop1()?; @@ -216,7 +221,8 @@ impl Uxn { wst.push1(a)?; } (_, _, 1, 0x05) => { - // ROT + // ROT2 + let mut wst = wst.borrow_mut(); let a = wst.pop2()?; let b = wst.pop2()?; let c = wst.pop2()?; @@ -226,30 +232,39 @@ impl Uxn { } (_, _, 0, 0x06) => { // DUP2 + let mut wst = wst.borrow_mut(); let a = wst.peek1()?; wst.push1(a)?; } (_, _, 1, 0x06) => { // DUP2 + let mut wst = wst.borrow_mut(); let a = wst.peek2()?; wst.push2(a)?; } (_, _, 0, 0x07) => { // OVR1 a b -- a b a - if wst.idx < 2 { + let mut wst = wst.borrow_mut(); + if wst.idx() < 2 { return Err(UxnError::StackError(StackError::StackUnderflow)); } - wst.push1(wst.get1(wst.idx - 2)?)?; + let i = wst.idx() - 2; + let v = wst.get1(i)?; + wst.push1(v)?; } (_, _, 1, 0x07) => { // OVR2 a b -- a b a - if wst.idx < 4 { + let mut wst = wst.borrow_mut(); + if wst.idx() < 4 { return Err(UxnError::StackError(StackError::StackUnderflow)); } - wst.push2(wst.get2(wst.idx - 4)?)?; + let i = wst.idx() - 4; + let v = wst.get2(i)?; + wst.push2(v)?; } (_, _, 0, 0x08) => { // EQU1 + let mut wst = wst.borrow_mut(); let a = wst.pop1()?; let b = wst.pop1()?; if a == b { @@ -260,6 +275,7 @@ impl Uxn { } (_, _, 1, 0x08) => { // EQU2 + let mut wst = wst.borrow_mut(); let a = wst.pop2()?; let b = wst.pop2()?; if a == b { @@ -270,8 +286,9 @@ impl Uxn { } (_, _, 0, 0x09) => { // NEQ1 - let a = wst.pop1()?; + let mut wst = wst.borrow_mut(); let b = wst.pop1()?; + let a = wst.pop1()?; if a == b { wst.push1(0)?; } else { @@ -280,21 +297,58 @@ impl Uxn { } (_, _, 1, 0x09) => { // NEQ2 - let a = wst.pop2()?; + let mut wst = wst.borrow_mut(); let b = wst.pop2()?; + let a = wst.pop2()?; if a == b { wst.push1(0)?; } else { wst.push1(1)?; } } - (_, _, _, 0x0a) => { - // GTH - () + (_, _, 0, 0x0a) => { + // GTH1 a b + let mut wst = wst.borrow_mut(); + let b = wst.pop1()?; + let a = wst.pop1()?; + if a > b { + wst.push1(0)?; + } else { + wst.push1(1)?; + } } - (_, _, _, 0x0b) => { - // LTH - () + (_, _, 1, 0x0a) => { + // GTH1 a b + let mut wst = wst.borrow_mut(); + let b = wst.pop2()?; + let a = wst.pop2()?; + if a > b { + wst.push1(0)?; + } else { + wst.push1(1)?; + } + } + (_, _, 0, 0x0b) => { + // LTH1 a b + let mut wst = wst.borrow_mut(); + let b = wst.pop1()?; + let a = wst.pop1()?; + if a < b { + wst.push1(0)?; + } else { + wst.push1(1)?; + } + } + (_, _, 1, 0x0b) => { + // LTH2 a b + let mut wst = wst.borrow_mut(); + let b = wst.pop2()?; + let a = wst.pop2()?; + if a < b { + wst.push1(0)?; + } else { + wst.push1(1)?; + } } (_, _, _, 0x0c) => { // JMP