[NO TESTS] WIP

This commit is contained in:
Reid 'arrdem' McKenzie 2022-12-22 18:45:20 -07:00
parent 2bc93922bc
commit 8630125e4d
4 changed files with 223 additions and 92 deletions

View file

@ -1,10 +1,9 @@
use std::env::args; use std::env::args;
use std::fs::File; use std::fs::File;
use std::io;
use std::io::BufReader; use std::io::BufReader;
use std::io::Read; use std::io::Read;
use uxn::Uxn; use uxn::vm::Uxn;
fn main() -> Result<(), std::io::Error> { fn main() -> Result<(), std::io::Error> {
let mut vm = Uxn::new(); let mut vm = Uxn::new();

View file

@ -19,8 +19,8 @@ impl Device for SystemDevice {
fn dei1(&mut self, vm: &mut Uxn, port: u8) -> u8 { fn dei1(&mut self, vm: &mut Uxn, port: u8) -> u8 {
let slot = port & 0xF; let slot = port & 0xF;
match slot { match slot {
0x2 => vm.wst.idx, 0x2 => vm.wst.borrow().idx(),
0x3 => vm.rst.idx, 0x3 => vm.rst.borrow().idx(),
x => self.buffer[x as usize], x => self.buffer[x as usize],
} }
} }

View file

@ -1,37 +1,66 @@
use std; use std;
use std::cell::RefCell;
use std::rc::Rc;
use std::result::Result; use std::result::Result;
#[derive(Debug)]
pub struct Stack {
buff: [u8; 0xFF],
pub idx: u8,
}
pub enum StackError { pub enum StackError {
StackOverflow, StackOverflow,
StackUnderflow, StackUnderflow,
} }
impl Stack { pub trait Stack: std::fmt::Debug {
pub fn new() -> Stack { fn idx(&self) -> u8;
Stack { fn push1(&mut self, val: u8) -> Result<(), StackError>;
buff: [0; 0xFF], fn push2(&mut self, val: u16) -> Result<(), StackError>;
idx: 0, fn get1(&self, idx: u8) -> Result<u8, StackError>;
} fn get2(&self, idx: u8) -> Result<u16, StackError>;
fn peek1(&self) -> Result<u8, StackError>;
fn peek2(&self) -> Result<u16, StackError>;
fn pop1(&mut self) -> Result<u8, StackError>;
fn pop2(&mut self) -> Result<u16, StackError>;
fn move1(&mut self, other: &mut dyn Stack) -> Result<(), StackError> {
other.push1(self.pop1()?)?;
Ok(())
} }
pub fn push1(&mut self, val: u8) -> Result<(), StackError> { fn move2(&mut self, other: &mut dyn Stack) -> Result<(), StackError> {
if self.idx == 255 { 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) Err(StackError::StackOverflow)
} else { } else {
self.buff[self.idx as usize] = val; self.buff[self._idx as usize] = val;
self.idx += 1; self._idx += 1;
Ok(()) Ok(())
} }
} }
pub fn push2(&mut self, val: u16) -> Result<(), StackError> { fn push2(&mut self, val: u16) -> Result<(), StackError> {
if self.idx > 254 { if self._idx > 254 {
Err(StackError::StackOverflow) Err(StackError::StackOverflow)
} else { } else {
val.to_be_bytes().map(|x| self.push1(x).ok()); val.to_be_bytes().map(|x| self.push1(x).ok());
@ -39,133 +68,123 @@ impl Stack {
} }
} }
pub fn get1(&self, idx: u8) -> Result<u8, StackError> { fn get1(&self, _idx: u8) -> Result<u8, StackError> {
Ok(self.buff[idx as usize]) Ok(self.buff[_idx as usize])
} }
pub fn peek1(&self) -> Result<u8, StackError> { fn peek1(&self) -> Result<u8, StackError> {
if self.idx == 0 { if self._idx == 0 {
Err(StackError::StackUnderflow) Err(StackError::StackUnderflow)
} else { } else {
Ok(self.get1(self.idx - 1)?) Ok(self.get1(self._idx - 1)?)
} }
} }
pub fn pop1(&mut self) -> Result<u8, StackError> { fn pop1(&mut self) -> Result<u8, StackError> {
let val = self.peek1()?; let val = self.peek1()?;
self.idx -= 1; self._idx -= 1;
Ok(val) Ok(val)
} }
pub fn get2(&self, idx: u8) -> Result<u16, StackError> { fn get2(&self, _idx: u8) -> Result<u16, StackError> {
if idx == 255 { if _idx == 255 {
Err(StackError::StackOverflow) Err(StackError::StackOverflow)
} else { } else {
let high = self.buff[idx as usize] as u16; let high = self.buff[_idx as usize] as u16;
let low = self.buff[(idx + 1) as usize] as u16; let low = self.buff[(_idx + 1) as usize] as u16;
println!("idx {}; high {:#02x}; low {:#02x};", idx, high, low); println!("_idx {}; high {:#02x}; low {:#02x};", _idx, high, low);
Ok((high << 8) + low) Ok((high << 8) + low)
} }
} }
pub fn peek2(&mut self) -> Result<u16, StackError> { fn peek2(&self) -> Result<u16, StackError> {
if self.idx < 2 { if self._idx < 2 {
Err(StackError::StackUnderflow) Err(StackError::StackUnderflow)
} else { } else {
self.get2(self.idx - 2) self.get2(self._idx - 2)
} }
} }
pub fn pop2(&mut self) -> Result<u16, StackError> { fn pop2(&mut self) -> Result<u16, StackError> {
let val = self.peek2()?; let val = self.peek2()?;
self.idx -= 2; self._idx -= 2;
Ok(val) 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)] #[cfg(test)]
mod stack_test { mod arraystack_test {
use super::*; use super::*;
#[test] #[test]
fn test_push_pop() { fn test_push_pop() {
let mut s = Stack::new(); let mut s = ArrayStack::new();
match s.push1(0xFF) { match s.push1(0xFF) {
Ok(()) => (), Ok(()) => (),
Err(_) => assert!(false, "pushing stack of size 0 errored"), Err(_) => assert!(false, "pushing stack of size 0 errored"),
} }
assert_eq!(s.idx, 1); assert_eq!(s._idx, 1);
match s.peek1() { match s.peek1() {
Ok(val) => assert_eq!(val, 0xFF), Ok(val) => assert_eq!(val, 0xFF),
Err(_) => assert!(false, "popping stack of size 1 errored"), Err(_) => assert!(false, "popping stack of size 1 errored"),
} }
assert_eq!(s.idx, 1); assert_eq!(s._idx, 1);
match s.pop1() { match s.pop1() {
Ok(val) => assert_eq!(val, 0xFF), Ok(val) => assert_eq!(val, 0xFF),
Err(_) => assert!(false, "popping stack of size 1 errored"), Err(_) => assert!(false, "popping stack of size 1 errored"),
} }
assert_eq!(s.idx, 0); assert_eq!(s._idx, 0);
} }
#[test] #[test]
fn test_push2_pop2() { fn test_push2_pop2() {
let mut s = Stack::new(); let mut s = ArrayStack::new();
match s.push2(0xFF00) { match s.push2(0xFF00) {
Ok(()) => (), Ok(()) => (),
Err(_) => assert!(false, "pushing stack of size 0 errored"), Err(_) => assert!(false, "pushing stack of size 0 errored"),
} }
assert_eq!(s.idx, 2); assert_eq!(s._idx, 2);
match s.peek2() { match s.peek2() {
Ok(val) => assert_eq!(val, 0xFF00), Ok(val) => assert_eq!(val, 0xFF00),
Err(_) => assert!(false, "peek2 stack of size 2 errored"), Err(_) => assert!(false, "peek2 stack of size 2 errored"),
} }
assert_eq!(s.idx, 2); assert_eq!(s._idx, 2);
match s.pop2() { match s.pop2() {
Ok(val) => assert_eq!(val, 0xFF00), Ok(val) => assert_eq!(val, 0xFF00),
Err(_) => assert!(false, "peek2 stack of size 2 errored"), Err(_) => assert!(false, "peek2 stack of size 2 errored"),
} }
assert_eq!(s.idx, 0); assert_eq!(s._idx, 0);
} }
#[test] #[test]
fn test_push2_pop1_pop1() { fn test_push2_pop1_pop1() {
let mut s = Stack::new(); let mut s = ArrayStack::new();
match s.push2(0xFF00) { match s.push2(0xFF00) {
Ok(()) => (), Ok(()) => (),
Err(_) => assert!(false, "pushing stack of size 0 errored"), Err(_) => assert!(false, "pushing stack of size 0 errored"),
} }
assert_eq!(s.idx, 2); assert_eq!(s._idx, 2);
match s.pop1() { match s.pop1() {
Ok(val) => assert_eq!(val, 0x00), Ok(val) => assert_eq!(val, 0x00),
Err(_) => assert!(false, "peek1 stack of size 2 errored"), Err(_) => assert!(false, "peek1 stack of size 2 errored"),
} }
assert_eq!(s.idx, 1); assert_eq!(s._idx, 1);
match s.pop1() { match s.pop1() {
Ok(val) => assert_eq!(val, 0xFF), Ok(val) => assert_eq!(val, 0xFF),
Err(_) => assert!(false, "peek1 stack of size 2 errored"), Err(_) => assert!(false, "peek1 stack of size 2 errored"),
} }
assert_eq!(s.idx, 0); assert_eq!(s._idx, 0);
} }
#[test] #[test]
fn test_pop_empty() { fn test_pop_empty() {
let mut s = Stack::new(); let mut s = ArrayStack::new();
match s.pop1() { match s.pop1() {
Ok(_) => assert!(false, "popping stack of size 0 succeeded"), Ok(_) => assert!(false, "popping stack of size 0 succeeded"),
Err(StackError::StackUnderflow) => (), 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<StackOp>,
_idx: u8,
wrapped: Rc<RefCell<dyn Stack>>,
}
impl StackWAL {
pub fn new(wrapped: Rc<RefCell<dyn Stack>>) -> 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<u8, StackError> {
unimplemented!()
}
fn get2(&self, idx: u8) -> Result<u16, StackError> {
unimplemented!()
}
fn peek1(&self) -> Result<u8, StackError> {
unimplemented!()
}
fn peek2(&self) -> Result<u16, StackError> {
unimplemented!()
}
fn pop1(&mut self) -> Result<u8, StackError> {
unimplemented!()
}
fn pop2(&mut self) -> Result<u16, StackError> {
unimplemented!()
}
}

112
src/vm.rs
View file

@ -34,9 +34,9 @@ pub struct Uxn {
pub memory: Rc<RefCell<TrivialMemory>>, pub memory: Rc<RefCell<TrivialMemory>>,
// Note: Using Rc so we can start with many NullDevs and replace them // Note: Using Rc so we can start with many NullDevs and replace them
pub devices: [Rc<RefCell<dyn Device>>; 16], pub devices: [Rc<RefCell<dyn Device>>; 16],
pub pc: u16, // Program counter pub pc: u16, // Program counter
pub wst: Stack, // Data stack pub wst: Rc<RefCell<dyn Stack>>, // Data stack
pub rst: Stack, // Return stack pointer pub rst: Rc<RefCell<dyn Stack>>, // Return stack pointer
} }
impl Uxn { impl Uxn {
@ -62,8 +62,8 @@ impl Uxn {
Rc::new(RefCell::new(NullDevice::new())), // #0f Rc::new(RefCell::new(NullDevice::new())), // #0f
], ],
pc: 0x0100, pc: 0x0100,
wst: Stack::new(), wst: Rc::new(RefCell::new(ArrayStack::new())),
rst: Stack::new(), rst: Rc::new(RefCell::new(ArrayStack::new())),
} }
} }
@ -138,9 +138,9 @@ impl Uxn {
let [wst, rst] = { let [wst, rst] = {
if rflag == 0 { if rflag == 0 {
[&mut self.wst, &mut self.rst] [self.wst.clone(), self.rst.clone()]
} else { } else {
[&mut self.wst, &mut self.rst] [self.wst.clone(), self.rst.clone()]
} }
}; };
@ -152,48 +152,51 @@ impl Uxn {
} }
(_, _, 0, 0x00) => { (_, _, 0, 0x00) => {
// LIT1 // LIT1
wst.push1(self.lda1(self.pc + 1)?); wst.borrow_mut().push1(self.lda1(self.pc + 1)?);
self.pc += 1; self.pc += 1;
continue 'run; continue 'run;
} }
(_, _, 1, 0x00) => { (_, _, 1, 0x00) => {
// LIT2 // LIT2
wst.push2(self.lda2(self.pc + 1)?); wst.borrow_mut().push2(self.lda2(self.pc + 1)?);
self.pc += 2; self.pc += 2;
continue 'run; continue 'run;
} }
(_, _, 0, 0x01) => { (_, _, 0, 0x01) => {
// INC1 // INC1
let a = wst.pop1()?; let a = wst.borrow_mut().pop1()?;
wst.push1(a + 1); wst.borrow_mut().push1(a + 1);
} }
(_, _, 1, 0x01) => { (_, _, 1, 0x01) => {
// INC1 // INC1
let a = wst.pop2()?; let a = wst.borrow_mut().pop2()?;
wst.push2(a + 1); wst.borrow_mut().push2(a + 1);
} }
(_, _, 0, 0x02) => { (_, _, 0, 0x02) => {
// POP1 // POP1
wst.pop1(); wst.borrow_mut().pop1();
} }
(_, _, 1, 0x02) => { (_, _, 1, 0x02) => {
// POP2 // POP2
wst.pop2(); wst.borrow_mut().pop2();
} }
(_, _, 0, 0x03) => { (_, _, 0, 0x03) => {
// NIP1 a b -- a // NIP1 a b -- a
let mut wst = wst.borrow_mut();
let keep = wst.pop1()?; let keep = wst.pop1()?;
wst.pop1(); wst.pop1();
wst.push1(keep)?; wst.push1(keep)?;
} }
(_, _, 1, 0x03) => { (_, _, 1, 0x03) => {
// NIP2 a b -- a // NIP2 a b -- a
let mut wst = wst.borrow_mut();
let keep = wst.pop2()?; let keep = wst.pop2()?;
wst.pop2()?; wst.pop2()?;
wst.push2(keep)?; wst.push2(keep)?;
} }
(_, _, 0, 0x04) => { (_, _, 0, 0x04) => {
// SWP1 // SWP1
let mut wst = wst.borrow_mut();
let a = wst.pop1()?; let a = wst.pop1()?;
let b = wst.pop1()?; let b = wst.pop1()?;
wst.push1(a)?; wst.push1(a)?;
@ -201,13 +204,15 @@ impl Uxn {
} }
(_, _, 1, 0x04) => { (_, _, 1, 0x04) => {
// SWP2 // SWP2
let mut wst = wst.borrow_mut();
let a = wst.pop2()?; let a = wst.pop2()?;
let b = wst.pop2()?; let b = wst.pop2()?;
wst.push2(a)?; wst.push2(a)?;
wst.push2(b)?; wst.push2(b)?;
} }
(_, _, 0, 0x05) => { (_, _, 0, 0x05) => {
// ROT // ROT1
let mut wst = wst.borrow_mut();
let a = wst.pop1()?; let a = wst.pop1()?;
let b = wst.pop1()?; let b = wst.pop1()?;
let c = wst.pop1()?; let c = wst.pop1()?;
@ -216,7 +221,8 @@ impl Uxn {
wst.push1(a)?; wst.push1(a)?;
} }
(_, _, 1, 0x05) => { (_, _, 1, 0x05) => {
// ROT // ROT2
let mut wst = wst.borrow_mut();
let a = wst.pop2()?; let a = wst.pop2()?;
let b = wst.pop2()?; let b = wst.pop2()?;
let c = wst.pop2()?; let c = wst.pop2()?;
@ -226,30 +232,39 @@ impl Uxn {
} }
(_, _, 0, 0x06) => { (_, _, 0, 0x06) => {
// DUP2 // DUP2
let mut wst = wst.borrow_mut();
let a = wst.peek1()?; let a = wst.peek1()?;
wst.push1(a)?; wst.push1(a)?;
} }
(_, _, 1, 0x06) => { (_, _, 1, 0x06) => {
// DUP2 // DUP2
let mut wst = wst.borrow_mut();
let a = wst.peek2()?; let a = wst.peek2()?;
wst.push2(a)?; wst.push2(a)?;
} }
(_, _, 0, 0x07) => { (_, _, 0, 0x07) => {
// OVR1 a b -- a b a // 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)); 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) => { (_, _, 1, 0x07) => {
// OVR2 a b -- a b a // 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)); 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) => { (_, _, 0, 0x08) => {
// EQU1 // EQU1
let mut wst = wst.borrow_mut();
let a = wst.pop1()?; let a = wst.pop1()?;
let b = wst.pop1()?; let b = wst.pop1()?;
if a == b { if a == b {
@ -260,6 +275,7 @@ impl Uxn {
} }
(_, _, 1, 0x08) => { (_, _, 1, 0x08) => {
// EQU2 // EQU2
let mut wst = wst.borrow_mut();
let a = wst.pop2()?; let a = wst.pop2()?;
let b = wst.pop2()?; let b = wst.pop2()?;
if a == b { if a == b {
@ -270,8 +286,9 @@ impl Uxn {
} }
(_, _, 0, 0x09) => { (_, _, 0, 0x09) => {
// NEQ1 // NEQ1
let a = wst.pop1()?; let mut wst = wst.borrow_mut();
let b = wst.pop1()?; let b = wst.pop1()?;
let a = wst.pop1()?;
if a == b { if a == b {
wst.push1(0)?; wst.push1(0)?;
} else { } else {
@ -280,21 +297,58 @@ impl Uxn {
} }
(_, _, 1, 0x09) => { (_, _, 1, 0x09) => {
// NEQ2 // NEQ2
let a = wst.pop2()?; let mut wst = wst.borrow_mut();
let b = wst.pop2()?; let b = wst.pop2()?;
let a = wst.pop2()?;
if a == b { if a == b {
wst.push1(0)?; wst.push1(0)?;
} else { } else {
wst.push1(1)?; wst.push1(1)?;
} }
} }
(_, _, _, 0x0a) => { (_, _, 0, 0x0a) => {
// GTH // 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) => { (_, _, 1, 0x0a) => {
// LTH // 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) => { (_, _, _, 0x0c) => {
// JMP // JMP