Almost out of power on the plane

This commit is contained in:
Reid 'arrdem' McKenzie 2022-12-23 20:41:44 -07:00
parent e74e2458ef
commit 5fa72b2112
10 changed files with 1004 additions and 71 deletions

118
Cargo.lock generated
View file

@ -2,6 +2,124 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "nofmt"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b06910a54adb901a01dfd9c475e7959c41acd55a078101ec70fb180f01b7435f"
[[package]]
name = "num_enum"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9"
dependencies = [
"num_enum_derive",
]
[[package]]
name = "num_enum_derive"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "once_cell"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "proc-macro-crate"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9"
dependencies = [
"once_cell",
"thiserror",
"toml",
]
[[package]]
name = "proc-macro2"
version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
dependencies = [
"proc-macro2",
]
[[package]]
name = "serde"
version = "1.0.151"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0"
[[package]]
name = "syn"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "toml"
version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f"
dependencies = [
"serde",
]
[[package]]
name = "unicode-ident"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]] [[package]]
name = "uxn" name = "uxn"
version = "0.1.0" version = "0.1.0"
dependencies = [
"nofmt",
"num_enum",
]

View file

@ -6,3 +6,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
nofmt = "1.0"
num_enum = "0.5.7"

4
src/asm.rs Normal file
View file

@ -0,0 +1,4 @@
/**
* A woefully incomplete implementation of the TAL assembler.
* Mostly intended to make writing test cases easy.
*/

61
src/isa.rs Normal file
View file

@ -0,0 +1,61 @@
// icodes
pub struct Icode {}
impl Icode {
// Official names
pub const BRK: u8 = 0x00u8;
pub const LIT: u8 = 0x1 << 7; // AKA keep Yes really. Per spec;
pub const INC: u8 = 0x01;
pub const POP: u8 = 0x02;
pub const NIP: u8 = 0x03;
pub const SWP: u8 = 0x04;
pub const ROT: u8 = 0x05;
pub const DUP: u8 = 0x06;
pub const OVR: u8 = 0x07;
pub const EQL: u8 = 0x08;
pub const NEQ: u8 = 0x09;
pub const GTH: u8 = 0x0a;
pub const LTH: u8 = 0x0b;
pub const JMP: u8 = 0x0c;
pub const JCN: u8 = 0x0d;
pub const JSR: u8 = 0x0e;
pub const STH: u8 = 0x0f;
pub const LDZ: u8 = 0x10;
pub const STZ: u8 = 0x11;
pub const LDR: u8 = 0x12;
pub const STR: u8 = 0x13;
pub const LDA: u8 = 0x14;
pub const STA: u8 = 0x15;
pub const DEI: u8 = 0x16;
pub const DEO: u8 = 0x17;
pub const ADD: u8 = 0x18;
pub const SUB: u8 = 0x19;
pub const MUL: u8 = 0x1a;
pub const DIV: u8 = 0x1b;
pub const AND: u8 = 0x1c;
pub const ORA: u8 = 0x1d;
pub const EOR: u8 = 0x1e;
pub const SFT: u8 = 0x1f;
// Opcode flags
pub const SHORT: u8 = 0x1 << 5;
pub const RETURN: u8 = 0x1 << 6;
pub const KEEP: u8 = 0x1 << 7;
// Hacking around the weird official names for some things
pub const XOR: u8 = Icode::ORA;
pub const EQ: u8 = Icode::EQL;
pub const NE: u8 = Icode::NEQ;
pub const GT: u8 = Icode::GTH;
pub const LT: u8 = Icode::LTH;
pub const OR: u8 = Icode::ORA;
pub const NOP: u8 = Icode::POP | Icode::KEEP;
pub const fn parse(opcode: u8) -> (u8, u8, u8, u8) {
let kflag: u8 = (opcode >> 7) & 0x1;
let rflag: u8 = (opcode >> 6) & 0x1;
let sflag: u8 = (opcode >> 5) & 0x1;
let icode: u8 = opcode & 0x1F;
(kflag, rflag, sflag, icode)
}
}

View file

@ -1,4 +1,5 @@
pub mod device; pub mod device;
pub mod isa;
pub mod memory; pub mod memory;
pub mod stack; pub mod stack;
pub mod vm; pub mod vm;

View file

@ -1,4 +1,4 @@
#[derive(Debug)] #[derive(Debug, PartialEq)]
pub enum MemoryError { pub enum MemoryError {
AddressOverflow, AddressOverflow,
AddressUnderflow, AddressUnderflow,

View file

@ -5,7 +5,7 @@ pub mod wal;
use std; use std;
use std::result::Result; use std::result::Result;
#[derive(Debug)] #[derive(Debug, PartialEq)]
pub enum StackError { pub enum StackError {
StackOverflow, StackOverflow,
StackUnderflow, StackUnderflow,

View file

@ -1,4 +1,4 @@
use super::{Stack, StackError}; use crate::stack::{Stack, StackError};
#[derive(Debug)] #[derive(Debug)]
pub struct ArrayStack { pub struct ArrayStack {
@ -69,7 +69,6 @@ impl Stack for ArrayStack {
} 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);
Ok((high << 8) + low) Ok((high << 8) + low)
} }
} }

167
src/vm.rs
View file

@ -5,11 +5,13 @@ use std::*;
use crate::device::null::NullDevice; use crate::device::null::NullDevice;
use crate::device::system::SystemDevice; use crate::device::system::SystemDevice;
use crate::device::*; use crate::device::*;
use crate::isa::Icode;
use crate::memory::*; use crate::memory::*;
use crate::stack::arrs::ArrayStack; use crate::stack::arrs::ArrayStack;
use crate::stack::pop::PopStack; use crate::stack::pop::PopStack;
use crate::stack::*; use crate::stack::*;
#[derive(Debug, PartialEq)]
pub enum UxnError { pub enum UxnError {
StackError(StackError), StackError(StackError),
MemoryError(MemoryError), MemoryError(MemoryError),
@ -70,6 +72,16 @@ impl Uxn {
} }
} }
pub fn of1(program: &[u8]) -> Uxn {
let mut vm = Uxn::new();
let mut pc = vm.pc;
for icode in program.iter() {
vm.sta1(pc, *icode).unwrap();
pc += 1;
}
vm
}
pub fn is_halted(&mut self) -> bool { pub fn is_halted(&mut self) -> bool {
self.dei1(0x0f) != 0 self.dei1(0x0f) != 0
} }
@ -95,12 +107,12 @@ impl Uxn {
} }
pub fn sta1(&mut self, address: u16, val: u8) -> Result<(), MemoryError> { pub fn sta1(&mut self, address: u16, val: u8) -> Result<(), MemoryError> {
self.memory.borrow_mut().set1(address, val)?; self.memory.clone().borrow_mut().set1(address, val)?;
Ok(()) Ok(())
} }
pub fn sta2(&mut self, address: u16, val: u16) -> Result<(), MemoryError> { pub fn sta2(&mut self, address: u16, val: u16) -> Result<(), MemoryError> {
self.memory.borrow_mut().set2(address, val)?; self.memory.clone().borrow_mut().set2(address, val)?;
Ok(()) Ok(())
} }
@ -115,16 +127,23 @@ impl Uxn {
// Run one clock cycle (instruction) // Run one clock cycle (instruction)
pub fn step(&mut self) -> Result<(), UxnError> { pub fn step(&mut self) -> Result<(), UxnError> {
match self.lda1(self.pc) { match self.lda1(self.pc) {
Err(e) => return Err(UxnError::MemoryError(e)), Err(e) => Err(UxnError::MemoryError(e)),
Ok(opcode) => { Ok(icode) => {
// The value of PC is defined to be the value of the NEXT pc ala Mips // The value of PC is defined to be the value of the NEXT pc ala Mips
self.pc += 1; self.pc += 1;
// Short circuit for fast NOP
if icode == Icode::NOP {
return Ok(());
}
// Extract flags // Extract flags
let sflag: u8 = opcode & 0x20 >> 5; let (kflag, rflag, sflag, icode) = Icode::parse(icode);
let rflag: u8 = opcode & 0x40 >> 6;
let kflag: u8 = opcode & 0x80 >> 7; println!(
let icode: u8 = opcode & 0x1F; "pc #{:04X}: #{:02x} ( {:05b} s: {:1x} r: {:1x} k: {:1x} )",
self.pc, icode, icode, sflag, rflag, kflag
);
// Swizzle the stacks as needed // Swizzle the stacks as needed
let [wst, rst]: [Rc<RefCell<dyn Stack>>; 2] = { let [wst, rst]: [Rc<RefCell<dyn Stack>>; 2] = {
@ -181,52 +200,52 @@ impl Uxn {
}; };
match (kflag, rflag, sflag, icode) { match (kflag, rflag, sflag, icode) {
(0, 0, 0, 0x00) => { (0, 0, 0, Icode::BRK) => {
// BRK // BRK --
return Err(UxnError::Break); return Err(UxnError::Break);
} }
(_, _, _, 0x00) => { (1, _, _, Icode::BRK) => {
// LIT // BRKk aka LIT -- a
push(wst.clone(), load(self.pc)?)?; push(wst.clone(), load(self.pc)?)?;
self.pc += if sflag == 1 { 2 } else { 1 }; self.pc += if sflag == 1 { 2 } else { 1 };
} }
(_, _, _, 0x01) => { (_, _, _, Icode::INC) => {
// INC // INC a -- a
push(wst.clone(), pop(wst.clone())? + 1)?; push(wst.clone(), pop(wst.clone())? + 1)?;
} }
(_, _, _, 0x02) => { (_, _, _, Icode::POP) => {
// POP // POP a --
pop(wst)?; pop(wst)?;
} }
(_, _, _, 0x03) => { (_, _, _, Icode::NIP) => {
// NIP a b -- a // NIP a b -- b
let keep = pop(wst.clone())?; let keep = pop(wst.clone())?;
pop(wst.clone())?; pop(wst.clone())?;
push(wst.clone(), keep)?; push(wst.clone(), keep)?;
} }
(_, _, _, 0x04) => { (_, _, _, Icode::SWP) => {
// SWP // SWP a b -- b a
let a = pop(wst.clone())?;
let b = pop(wst.clone())?; let b = pop(wst.clone())?;
let a = pop(wst.clone())?;
push(wst.clone(), b)?; push(wst.clone(), b)?;
push(wst.clone(), a)?; push(wst.clone(), a)?;
} }
(_, _, _, 0x05) => { (_, _, _, Icode::ROT) => {
// ROT // ROT a b c -- b c a
let a = pop(wst.clone())?;
let b = pop(wst.clone())?;
let c = pop(wst.clone())?; let c = pop(wst.clone())?;
let b = pop(wst.clone())?;
let a = pop(wst.clone())?;
push(wst.clone(), b)?; push(wst.clone(), b)?;
push(wst.clone(), c)?; push(wst.clone(), c)?;
push(wst.clone(), a)?; push(wst.clone(), a)?;
} }
(_, _, _, 0x06) => { (_, _, _, Icode::DUP) => {
// DUP // DUP a -- a a
let a = pop(wst.clone())?; let a = pop(wst.clone())?;
push(wst.clone(), a)?; push(wst.clone(), a)?;
push(wst.clone(), a)?; push(wst.clone(), a)?;
} }
(_, _, _, 0x07) => { (_, _, _, Icode::OVR) => {
// OVR a b -- a b a // OVR a b -- a b a
let b = pop(wst.clone())?; let b = pop(wst.clone())?;
let a = pop(wst.clone())?; let a = pop(wst.clone())?;
@ -234,36 +253,41 @@ impl Uxn {
push(wst.clone(), b)?; push(wst.clone(), b)?;
push(wst.clone(), a)?; push(wst.clone(), a)?;
} }
(_, _, _, 0x08) => { (_, _, _, Icode::EQL) => {
// EQU // EQU a b -- c
let b = pop(wst.clone())?; let b = pop(wst.clone())?;
let a = pop(wst.clone())?; let a = pop(wst.clone())?;
wst.borrow_mut().push1(if a == b { 1 } else { 0 })?; wst.borrow_mut().push1(if a == b { 1 } else { 0 })?;
} }
(_, _, _, 0x09) => { (_, _, _, Icode::NEQ) => {
// NEQ // NEQ a b -- c
let b = pop(wst.clone())?; let b = pop(wst.clone())?;
let a = pop(wst.clone())?; let a = pop(wst.clone())?;
wst.borrow_mut().push1(if a == b { 0 } else { 1 })?; wst.borrow_mut().push1(if a == b { 0 } else { 1 })?;
} }
(_, _, _, 0x0a) => { (_, _, _, Icode::GTH) => {
// GTH a b // GTH a b -- c
let b = pop(wst.clone())?; let b = pop(wst.clone())?;
let a = pop(wst.clone())?; let a = pop(wst.clone())?;
wst.borrow_mut().push1(if a > b { 1 } else { 0 })?; wst.borrow_mut().push1(if a > b { 1 } else { 0 })?;
} }
(_, _, _, 0x0b) => { (_, _, _, Icode::LTH) => {
// LTH a b // LTH a b -- c
let b = pop(wst.clone())?; let b = pop(wst.clone())?;
let a = pop(wst.clone())?; let a = pop(wst.clone())?;
wst.borrow_mut().push1(if a < b { 1 } else { 0 })?; wst.borrow_mut().push1(if a < b { 1 } else { 0 })?;
} }
(_, _, _, 0x0c) => { (_, _, 0, Icode::JMP) => {
// JMP // JMP1 a --
let delta = wst.borrow_mut().pop1()? as i8; let delta = wst.borrow_mut().pop1()? as i8;
self.pc = self.pc.wrapping_add(delta as u16); self.pc = self.pc.wrapping_add(delta as u16);
} }
(_, _, 0, 0x0d) => { (_, _, 1, Icode::JMP) => {
// JMP2 a --
let delta = wst.borrow_mut().pop2()?;
self.pc = delta;
}
(_, _, 0, Icode::JCN) => {
// JCN1 cnd8 addr8 (relative) // JCN1 cnd8 addr8 (relative)
let delta = wst.borrow_mut().pop1()? as i8; let delta = wst.borrow_mut().pop1()? as i8;
let cnd = wst.borrow_mut().pop1()?; let cnd = wst.borrow_mut().pop1()?;
@ -271,7 +295,7 @@ impl Uxn {
self.pc = self.pc.wrapping_add(delta as u16); self.pc = self.pc.wrapping_add(delta as u16);
} }
} }
(_, _, 2, 0x0d) => { (_, _, 1, Icode::JCN) => {
// JCN2 cnd8 addr16 (absolute) // JCN2 cnd8 addr16 (absolute)
let addr = wst.borrow_mut().pop2()?; let addr = wst.borrow_mut().pop2()?;
let cnd = wst.borrow_mut().pop1()?; let cnd = wst.borrow_mut().pop1()?;
@ -279,119 +303,127 @@ impl Uxn {
self.pc = addr; self.pc = addr;
} }
} }
(_, _, 0, 0x0e) => { (_, _, 0, Icode::JSR) => {
// JSR1 addr8 (relative) // JSR1 addr8 (relative)
rst.borrow_mut().push2(self.pc)?; rst.borrow_mut().push2(self.pc)?;
let delta = wst.borrow_mut().pop1()? as i8; let delta = wst.borrow_mut().pop1()? as i8;
self.pc = self.pc.wrapping_add(delta as u16); self.pc = self.pc.wrapping_add(delta as u16);
} }
(_, _, 1, 0x0e) => { (_, _, 1, Icode::JSR) => {
// JSR2 addr16 (absolute) // JSR2 addr16 (absolute)
rst.borrow_mut().push2(self.pc)?; rst.borrow_mut().push2(self.pc)?;
self.pc = wst.borrow_mut().pop2()?; self.pc = wst.borrow_mut().pop2()?;
} }
(_, _, _, 0x0f) => { (_, _, _, Icode::STH) => {
// STH a // STH a
push(rst, pop(wst)?)?; push(rst, pop(wst)?)?;
} }
(_, _, _, 0x10) => { (_, _, _, Icode::LDZ) => {
// LDZ a -- b8 // LDZ a8 -- b
push(wst.clone(), load(wst.borrow_mut().pop1()? as u16)?)?; let addr = wst.borrow_mut().pop1()? as u16;
push(wst.clone(), load(addr)?)?;
} }
(_, _, _, 0x11) => { (_, _, _, Icode::STZ) => {
// STZ val addr8 -- // STZ val addr8 --
let addr = wst.borrow_mut().pop1()? as u16; let addr = wst.borrow_mut().pop1()? as u16;
store(addr, pop(wst.clone())?)?; store(addr, pop(wst.clone())?)?;
} }
(_, _, _, 0x12) => { (_, _, _, Icode::LDR) => {
// LDR addr8 -- a8 // LDR addr8 -- a8
let delta = wst.borrow_mut().pop1()? as i8; let delta = wst.borrow_mut().pop1()? as i8;
push(wst.clone(), load(self.pc.wrapping_add(delta as u16))?)?; let addr = self.pc.wrapping_add(delta as u16);
push(wst, load(addr)?)?;
} }
(_, _, _, 0x13) => { (_, _, _, Icode::STR) => {
// STR val8 addr8 // STR val addr8 --
let delta = wst.borrow_mut().pop1()?; let delta = wst.borrow_mut().pop1()?;
store(self.pc.wrapping_add(delta as u16), pop(wst.clone())?)?; let addr = self.pc.wrapping_add(delta as u16);
println!(
"STR] Got delta {}, effective store address #{:04x}",
delta, addr
);
store(addr, pop(wst)?)?;
} }
(_, _, _, 0x14) => { (_, _, _, Icode::LDA) => {
// LDA a16 // LDA a16
let addr = wst.borrow_mut().pop2()?; let addr = wst.borrow_mut().pop2()?;
push(wst.clone(), load(addr)?)?; push(wst.clone(), load(addr)?)?;
} }
(_, _, _, 0x15) => { (_, _, _, Icode::STA) => {
// STA val a16 -- // STA val a16 --
let addr = wst.borrow_mut().pop2()?; let addr = wst.borrow_mut().pop2()?;
store(addr, pop(wst.clone())?)?; store(addr, pop(wst.clone())?)?;
} }
(_, _, 0, 0x16) => { (_, _, 0, Icode::DEI) => {
// DEI port8 -- a8 // DEI port8 -- a8
let mut wst = wst.borrow_mut(); let mut wst = wst.borrow_mut();
let port = wst.pop1()?; let port = wst.pop1()?;
wst.push1(self.dei1(port))?; wst.push1(self.dei1(port))?;
} }
(_, _, 1, 0x16) => { (_, _, 1, Icode::DEI) => {
// DEI2 port8 -- a16 // DEI2 port8 -- a16
let mut wst = wst.borrow_mut(); let mut wst = wst.borrow_mut();
let port = wst.pop1()?; let port = wst.pop1()?;
wst.push2(self.dei2(port))?; wst.push2(self.dei2(port))?;
} }
(_, _, 0, 0x17) => { (_, _, 0, Icode::DEO) => {
// DEO1 a8 port8 -- // DEO1 a8 port8 --
let mut wst = wst.borrow_mut(); let mut wst = wst.borrow_mut();
let port = wst.pop1()?; let port = wst.pop1()?;
let val = wst.pop1()?; let val = wst.pop1()?;
self.deo1(port, val); self.deo1(port, val);
} }
(_, _, 1, 0x17) => { (_, _, 1, Icode::DEO) => {
// DEO2 a16 port8 -- // DEO2 a16 port8 --
let mut wst = wst.borrow_mut(); let mut wst = wst.borrow_mut();
let port = wst.pop1()?; let port = wst.pop1()?;
let val = wst.pop2()?; let val = wst.pop2()?;
self.deo2(port, val); self.deo2(port, val);
} }
(_, _, _, 0x18) => { (_, _, _, Icode::ADD) => {
// ADD a b -- c // ADD a b -- c
let b = pop(wst.clone())?; let b = pop(wst.clone())?;
let a = pop(wst.clone())?; let a = pop(wst.clone())?;
push(wst.clone(), a + b)?; push(wst.clone(), a + b)?;
} }
(_, _, _, 0x19) => { (_, _, _, Icode::SUB) => {
// SUB a b -- c // SUB a b -- c
let b = pop(wst.clone())?; let b = pop(wst.clone())?;
let a = pop(wst.clone())?; let a = pop(wst.clone())?;
push(wst.clone(), a - b)?; push(wst.clone(), a - b)?;
} }
(_, _, _, 0x1a) => { (_, _, _, Icode::MUL) => {
// MUL a b -- c // MUL a b -- c
let b = pop(wst.clone())?; let b = pop(wst.clone())?;
let a = pop(wst.clone())?; let a = pop(wst.clone())?;
push(wst.clone(), a * b)?; push(wst.clone(), a * b)?;
} }
(_, _, _, 0x1b) => { (_, _, _, Icode::DIV) => {
// DIV a b -- c // DIV a b -- c
let b = pop(wst.clone())?; let b = pop(wst.clone())?;
let a = pop(wst.clone())?; let a = pop(wst.clone())?;
push(wst.clone(), a / b)?; push(wst.clone(), a / b)?;
} }
(_, _, _, 0x1c) => { (_, _, _, Icode::AND) => {
// AND a b -- c // AND a b -- c
let b = pop(wst.clone())?; let b = pop(wst.clone())?;
let a = pop(wst.clone())?; let a = pop(wst.clone())?;
push(wst.clone(), a & b)?; push(wst.clone(), a & b)?;
} }
(_, _, _, 0x1d) => { (_, _, _, Icode::ORA) => {
// OR a b -- c // OR a b -- c
let b = pop(wst.clone())?; let b = pop(wst.clone())?;
let a = pop(wst.clone())?; let a = pop(wst.clone())?;
push(wst.clone(), a | b)?; push(wst.clone(), a | b)?;
} }
(_, _, _, 0x1e) => { (_, _, _, Icode::EOR) => {
// XOR a8 b8 -- c8 // XOR a8 b8 -- c8
let b = pop(wst.clone())?; let b = pop(wst.clone())?;
let a = pop(wst.clone())?; let a = pop(wst.clone())?;
push(wst.clone(), a ^ b)?; push(wst.clone(), a ^ b)?;
} }
(_, _, _, 0x1f) => { (_, _, _, Icode::SFT) => {
// SFT a shift8 -- b // SFT a shift8 -- b
let shift = wst.borrow_mut().pop1()?; let shift = wst.borrow_mut().pop1()?;
let [left, right] = [shift >> 4, shift & 0xF]; let [left, right] = [shift >> 4, shift & 0xF];
@ -400,9 +432,10 @@ impl Uxn {
} }
_ => unreachable!(), _ => unreachable!(),
} }
Ok(())
} }
} }
Ok(())
} }
pub fn run(&mut self, limit: u16) -> Result<(), UxnError> { pub fn run(&mut self, limit: u16) -> Result<(), UxnError> {

715
tests/vm_tests.rs Normal file
View file

@ -0,0 +1,715 @@
use uxn::isa::Icode;
use uxn::vm::*;
#[test]
fn test_brk() {
let mut vm = Uxn::of1(&[Icode::BRK]);
assert_eq!(vm.step(), Err(UxnError::Break));
}
#[test]
fn test_lit() {
let mut vm = Uxn::of1(&[Icode::LIT, 0x01, Icode::BRK]);
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().peek1(), Ok(0x01));
}
#[test]
fn test_lit2() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT | Icode::SHORT, 0xFF, 0xAA,
Icode::BRK, // BRK
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().peek2(), Ok(0xFFAA));
}
#[test]
fn test_litr() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT | Icode::RETURN, 0xAA,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.rst.borrow().peek1(), Ok(0xAA));
}
#[test]
fn test_inc() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT | Icode::SHORT, 0xFF, 0xAA,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().peek2(), Ok(0xFFAA));
}
#[test]
fn test_pop1() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0xFF,
Icode::LIT, 0xAA,
Icode::POP,
Icode::LIT, 0xBB,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().peek2(), Ok(0xFFBB));
}
#[test]
fn test_pop2() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0xFF,
Icode::LIT, 0xAA,
Icode::LIT, 0xBB,
Icode::POP | Icode::SHORT,
Icode::LIT, 0xCC,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().peek2(), Ok(0xFFCC));
}
#[test]
fn test_popk() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0xFF,
Icode::POP | Icode::KEEP,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().peek1(), Ok(0xFF));
}
#[test]
fn test_nip() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0xAA,
Icode::LIT, 0xBB,
Icode::NIP,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().peek1(), Ok(0xBB));
}
#[test]
fn test_nip2() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT | Icode::SHORT, 0xAA, 0x00,
Icode::LIT | Icode::SHORT, 0xBB, 0x00,
Icode::NIP | Icode::SHORT,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().peek2(), Ok(0xBB00));
}
#[test]
fn test_nipk() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0xAA,
Icode::LIT, 0xBB,
Icode::NIP | Icode::KEEP,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get1(0), Ok(0xAA));
assert_eq!(vm.wst.borrow().get1(1), Ok(0xBB));
assert_eq!(vm.wst.borrow().get1(2), Ok(0xBB));
assert_eq!(vm.wst.borrow().peek1(), Ok(0xBB));
}
#[test]
fn test_swp() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0xAA,
Icode::LIT, 0xBB,
Icode::SWP,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get1(0), Ok(0xBB));
assert_eq!(vm.wst.borrow().get1(1), Ok(0xAA));
assert_eq!(vm.wst.borrow().peek1(), Ok(0xAA));
}
#[test]
fn test_swp2() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT | Icode::SHORT, 0xAA, 0x00,
Icode::LIT | Icode::SHORT, 0xBB, 0x00,
Icode::SWP | Icode::SHORT,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get2(0), Ok(0xBB00));
assert_eq!(vm.wst.borrow().get2(2), Ok(0xAA00));
assert_eq!(vm.wst.borrow().peek2(), Ok(0xAA00));
}
#[test]
fn test_swpk() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0xAA,
Icode::LIT, 0xBB,
Icode::SWP | Icode::KEEP,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get1(0), Ok(0xAA));
assert_eq!(vm.wst.borrow().get1(1), Ok(0xBB));
assert_eq!(vm.wst.borrow().get1(2), Ok(0xBB));
assert_eq!(vm.wst.borrow().get1(3), Ok(0xAA));
assert_eq!(vm.wst.borrow().peek1(), Ok(0xAA));
}
#[test]
fn test_rot() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0xAA,
Icode::LIT, 0xBB,
Icode::LIT, 0xCC,
Icode::ROT,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get1(0), Ok(0xBB));
assert_eq!(vm.wst.borrow().get1(1), Ok(0xCC));
assert_eq!(vm.wst.borrow().get1(2), Ok(0xAA));
assert_eq!(vm.wst.borrow().peek1(), Ok(0xAA));
}
#[test]
fn test_rot_cycle() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0xAA,
Icode::LIT, 0xBB,
Icode::LIT, 0xCC,
Icode::ROT,
Icode::ROT,
Icode::ROT,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get1(0), Ok(0xAA));
assert_eq!(vm.wst.borrow().get1(1), Ok(0xBB));
assert_eq!(vm.wst.borrow().get1(2), Ok(0xCC));
assert_eq!(vm.wst.borrow().peek1(), Ok(0xCC));
}
#[test]
fn test_dup() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0xAA,
Icode::LIT, 0xBB,
Icode::DUP,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get1(0), Ok(0xAA));
assert_eq!(vm.wst.borrow().get1(1), Ok(0xBB));
assert_eq!(vm.wst.borrow().get1(2), Ok(0xBB));
assert_eq!(vm.wst.borrow().peek1(), Ok(0xBB));
}
#[test]
fn test_ovr() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0xAA,
Icode::LIT, 0xBB,
Icode::OVR,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get1(0), Ok(0xAA));
assert_eq!(vm.wst.borrow().get1(1), Ok(0xBB));
assert_eq!(vm.wst.borrow().get1(2), Ok(0xAA));
assert_eq!(vm.wst.borrow().peek1(), Ok(0xAA));
}
#[test]
fn test_eql_neg() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0xAA,
Icode::LIT, 0xBB,
Icode::EQL,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get1(0), Ok(0x00));
assert_eq!(vm.wst.borrow().peek1(), Ok(0x00));
}
#[test]
fn test_eql_pos() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0xAA,
Icode::LIT, 0xAA,
Icode::EQL,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get1(0), Ok(0x01));
assert_eq!(vm.wst.borrow().peek1(), Ok(0x01));
}
#[test]
fn test_neq_neg() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0xAA,
Icode::LIT, 0xAA,
Icode::NEQ,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get1(0), Ok(0x00));
assert_eq!(vm.wst.borrow().peek1(), Ok(0x00));
}
#[test]
fn test_neq_pos() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0xAA,
Icode::LIT, 0xBB,
Icode::NEQ,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get1(0), Ok(0x01));
assert_eq!(vm.wst.borrow().peek1(), Ok(0x01));
}
#[test]
fn test_gth_neg() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0x00,
Icode::LIT, 0x01,
Icode::GTH,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get1(0), Ok(0x00));
assert_eq!(vm.wst.borrow().peek1(), Ok(0x00));
}
#[test]
fn test_gth_pos() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0x01,
Icode::LIT, 0x00,
Icode::GTH,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get1(0), Ok(0x01));
assert_eq!(vm.wst.borrow().peek1(), Ok(0x01));
}
#[test]
fn test_lth_neg() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0x01,
Icode::LIT, 0x00,
Icode::LTH,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get1(0), Ok(0x00));
assert_eq!(vm.wst.borrow().peek1(), Ok(0x00));
}
#[test]
fn test_lth_pos() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0x00,
Icode::LIT, 0x01,
Icode::LTH,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get1(0), Ok(0x01));
assert_eq!(vm.wst.borrow().peek1(), Ok(0x01));
}
#[test]
fn test_jmprp() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0xAA,
Icode::LIT, 0x03,
Icode::JMP,
Icode::POP,
Icode::LIT, 0xFF,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get1(0), Ok(0xAA));
assert_eq!(vm.wst.borrow().peek1(), Ok(0xAA));
}
#[test]
fn test_jmpa() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT | Icode::SHORT, 0x01, 0x10, Icode::JMP | Icode::SHORT,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
Icode::LIT, 0xAA,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get1(0), Ok(0xAA));
assert_eq!(vm.wst.borrow().peek1(), Ok(0xAA));
}
#[test]
fn test_jmprn() {
// Negative relative jup
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT | Icode::SHORT, 0x01, 0x10, Icode::JMP | Icode::SHORT,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
// Negative relative jump target
Icode::LIT, 0xAA, Icode::BRK, 0x00,
// Absolute jump target
Icode::LIT, -7i8 as u8, Icode::JMP,
// Wrong arm
Icode::LIT, 0xFF,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get1(0), Ok(0xAA));
assert_eq!(vm.wst.borrow().peek1(), Ok(0xAA));
}
#[test]
fn test_jmpc_true() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0x01,
Icode::LIT, 0x03,
Icode::JCN,
// Fall through
Icode::LIT, 0xFF, Icode::BRK,
// Target
Icode::LIT, 0xAA, Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get1(0), Ok(0xAA));
assert_eq!(vm.wst.borrow().peek1(), Ok(0xAA));
}
#[test]
fn test_jmpc_false() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0x00,
Icode::LIT, 0x03,
Icode::JCN,
// Fall through
Icode::LIT, 0xFF, Icode::BRK,
// Target
Icode::LIT, 0xAA, Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get1(0), Ok(0xFF));
assert_eq!(vm.wst.borrow().peek1(), Ok(0xFF));
}
#[test]
fn test_jsr() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0x05, Icode::JSR, 0x00,
// Fall through
0x00, 0x00, 0x00, 0x00,
// Target
Icode::LIT, 0xAA, Icode::BRK, 0x00,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get1(0), Ok(0xAA));
assert_eq!(vm.wst.borrow().peek1(), Ok(0xAA));
assert_eq!(vm.rst.borrow().get2(0), Ok(0x0103));
assert_eq!(vm.rst.borrow().peek2(), Ok(0x0103));
}
#[test]
fn test_jsra() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT | Icode::SHORT, 0x01, 0x08, Icode::JSR | Icode::SHORT,
// Fall through
0x00, 0x00, 0x00, 0x00,
// Target
Icode::LIT, 0xAA, Icode::BRK, 0x00,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get1(0), Ok(0xAA));
assert_eq!(vm.wst.borrow().peek1(), Ok(0xAA));
assert_eq!(vm.rst.borrow().get2(0), Ok(0x0104));
assert_eq!(vm.rst.borrow().peek2(), Ok(0x0104));
}
#[test]
fn test_sth() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT | Icode::SHORT, 0x01, 0x08, Icode::STH,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().get1(0), Ok(0x01));
assert_eq!(vm.wst.borrow().peek1(), Ok(0x01));
assert_eq!(vm.rst.borrow().get1(0), Ok(0x08));
assert_eq!(vm.rst.borrow().peek1(), Ok(0x08));
}
#[test]
fn test_sth2() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT | Icode::SHORT, 0x01, 0x08, Icode::STH | Icode::SHORT,
Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.rst.borrow().get2(0), Ok(0x0108));
assert_eq!(vm.rst.borrow().peek2(), Ok(0x0108));
}
#[test]
fn test_ldz() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0x0b, Icode::LDZ, Icode::BRK,
]);
vm.sta1(0x000b, 0xFF).unwrap();
}
// Make sure the write took
assert_eq!(vm.lda1(0x00b).unwrap(), 0xFF);
// Run the example
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().idx(), 1);
assert_eq!(vm.wst.borrow().peek1(), Ok(0xFF));
}
#[test]
fn test_ldz2() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0x0b, Icode::LDZ | Icode::SHORT, Icode::BRK,
]);
vm.sta2(0x000b, 0xFFEE).unwrap();
}
// Make sure the write took
assert_eq!(vm.lda1(0x00b).unwrap(), 0xFF);
// Run the example
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().idx(), 2);
assert_eq!(vm.wst.borrow().peek2(), Ok(0xFFEE));
}
#[test]
fn test_stz() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0xFF, Icode::LIT, 0x0b,
Icode::STZ, Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().idx(), 0);
assert_eq!(vm.lda1(0x000b), Ok(0xFF));
}
#[test]
fn test_stz2() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0xFF, Icode::LIT, 0x0b,
Icode::STZ, Icode::BRK,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().idx(), 0);
assert_eq!(vm.lda1(0x000b), Ok(0xFF));
}
#[test]
fn test_ldr() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0x01, Icode::LDR, Icode::BRK,
0xFF,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().idx(), 1);
assert_eq!(vm.wst.borrow().peek1(), Ok(0xFF));
}
#[test]
fn test_ldr2() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0x01, Icode::LDR | Icode::SHORT, Icode::BRK,
0xFF, 0xEE
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().idx(), 2);
assert_eq!(vm.wst.borrow().peek2(), Ok(0xFFEE));
}
#[test]
fn test_str() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0xEE, Icode::LIT, 0x03,
Icode::STR, Icode::BRK, 0x00, 0x00,
0xFF, // Will be overwritten
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().idx(), 0);
assert_eq!(vm.lda1(0x0108), Ok(0xEE));
}
#[test]
fn test_str2() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT | Icode::SHORT, 0xEE, 0xDD, Icode::LIT,
0x02, Icode::STR | Icode::SHORT, Icode::BRK, 0x00,
0xFF, 0xFF // Will be overwritten
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().idx(), 0);
assert_eq!(vm.lda2(0x0108), Ok(0xEEDD));
}
#[test]
fn test_lda() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT | Icode::SHORT, 0x01, 0x08, Icode::LDA,
Icode::BRK, 0x00, 0x00, 0x00,
0xEE,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().idx(), 1);
assert_eq!(vm.wst.borrow().peek1(), Ok(0xEE));
}
#[test]
fn test_lda2() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT | Icode::SHORT, 0x01, 0x08, Icode::LDA | Icode::SHORT,
Icode::BRK, 0x00, 0x00, 0x00,
0xEE, 0xDD,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().idx(), 2);
assert_eq!(vm.wst.borrow().peek2(), Ok(0xEEDD));
}
#[test]
fn test_sta() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT, 0xFF, Icode::NOP, Icode::NOP,
Icode::LIT | Icode::SHORT, 0x01, 0x0c, Icode::NOP,
Icode::STA, Icode::BRK, 0x00, 0x00,
0x00,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().idx(), 0);
assert_eq!(vm.lda1(0x010c), Ok(0xFF));
}
#[test]
fn test_sta2() {
nofmt::pls! {
let mut vm = Uxn::of1(&[
Icode::LIT | Icode::SHORT, 0xFF, 0xEE, Icode::NOP,
Icode::LIT | Icode::SHORT, 0x01, 0x0c, Icode::NOP,
Icode::STA | Icode::SHORT, Icode::BRK, Icode::NOP,
0x00, 0x00,
]);
}
assert_eq!(vm.run(64), Err(UxnError::Break));
assert_eq!(vm.wst.borrow().idx(), 0);
assert_eq!(vm.lda2(0x010c), Ok(0xFFEE));
}