Almost out of power on the plane
This commit is contained in:
parent
e74e2458ef
commit
5fa72b2112
10 changed files with 1004 additions and 71 deletions
118
Cargo.lock
generated
118
Cargo.lock
generated
|
@ -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",
|
||||||
|
]
|
||||||
|
|
|
@ -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
4
src/asm.rs
Normal 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
61
src/isa.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#[derive(Debug)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum MemoryError {
|
pub enum MemoryError {
|
||||||
AddressOverflow,
|
AddressOverflow,
|
||||||
AddressUnderflow,
|
AddressUnderflow,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
167
src/vm.rs
|
@ -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
715
tests/vm_tests.rs
Normal 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));
|
||||||
|
}
|
Loading…
Reference in a new issue