Testing & bugstomping
This commit is contained in:
parent
8ef06a7e1a
commit
93476015c5
13 changed files with 655 additions and 164 deletions
330
Cargo.lock
generated
330
Cargo.lock
generated
|
@ -2,6 +2,164 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea"
|
||||
|
||||
[[package]]
|
||||
name = "futures-timer"
|
||||
version = "3.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"futures-macro",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.139"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "nofmt"
|
||||
version = "1.0.0"
|
||||
|
@ -9,42 +167,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "b06910a54adb901a01dfd9c475e7959c41acd55a078101ec70fb180f01b7435f"
|
||||
|
||||
[[package]]
|
||||
name = "num_enum"
|
||||
version = "0.5.7"
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9"
|
||||
dependencies = [
|
||||
"num_enum_derive",
|
||||
]
|
||||
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
||||
|
||||
[[package]]
|
||||
name = "num_enum_derive"
|
||||
version = "0.5.7"
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
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",
|
||||
]
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
|
@ -55,6 +187,17 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quickcheck"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6"
|
||||
dependencies = [
|
||||
"env_logger",
|
||||
"log",
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.23"
|
||||
|
@ -65,10 +208,89 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.151"
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
|
||||
|
||||
[[package]]
|
||||
name = "rstest"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b07f2d176c472198ec1e6551dc7da28f1c089652f66a7b722676c2238ebc0edf"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"futures-timer",
|
||||
"rstest_macros",
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rstest_macros"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7229b505ae0706e64f37ffc54a9c163e11022a6636d58fe1f3f52018257ff9f7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc_version",
|
||||
"syn",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
|
@ -81,35 +303,6 @@ dependencies = [
|
|||
"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"
|
||||
|
@ -121,5 +314,12 @@ name = "uxn"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nofmt",
|
||||
"num_enum",
|
||||
"quickcheck",
|
||||
"rstest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
|
13
Cargo.toml
13
Cargo.toml
|
@ -3,8 +3,17 @@ name = "uxn"
|
|||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[[bin]]
|
||||
name = "uxncli"
|
||||
path = "src/bin/uxncli/main.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "uxnsym"
|
||||
path = "src/bin/uxnsym/main.rs"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
[dev-dependencies]
|
||||
quickcheck = "1.0.3"
|
||||
rstest = "0.16.0"
|
||||
nofmt = "1.0"
|
||||
num_enum = "0.5.7"
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
use std::env::args;
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
use std::io::Read;
|
||||
|
||||
use uxn::vm::Uxn;
|
||||
|
||||
fn main() -> Result<(), std::io::Error> {
|
||||
let mut vm = Uxn::new();
|
||||
|
||||
let argv: Vec<String> = args().collect();
|
||||
let f: File = File::open(&argv[1])?;
|
||||
let reader = BufReader::new(f);
|
||||
|
||||
let mut i = 0x0100u16;
|
||||
for b in reader.bytes() {
|
||||
vm.sta1(i, b?).expect("Write failed");
|
||||
i += 1;
|
||||
}
|
||||
|
||||
println!("{:?}", vm);
|
||||
|
||||
Ok(())
|
||||
}
|
71
src/bin/uxncli/main.rs
Normal file
71
src/bin/uxncli/main.rs
Normal file
|
@ -0,0 +1,71 @@
|
|||
use std::env::args;
|
||||
use std::ffi::CStr;
|
||||
use std::fs::File;
|
||||
use std::io::BufRead;
|
||||
use std::io::BufReader;
|
||||
use std::io::Read;
|
||||
|
||||
use uxn::vm::{Uxn, UxnError};
|
||||
|
||||
fn main() -> Result<(), std::io::Error> {
|
||||
let mut vm = Uxn::new();
|
||||
|
||||
let argv: Vec<String> = args().collect();
|
||||
|
||||
// Load a bytecode file
|
||||
let f: File = File::open(&argv[1])?;
|
||||
let reader = BufReader::new(f);
|
||||
|
||||
let mut i = 0x0100u16;
|
||||
for b in reader.bytes() {
|
||||
vm.sta1(i, b?).expect("Write failed");
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// Load a symbol table
|
||||
if argv.len() > 2 {
|
||||
let f: File = File::open(&argv[2])?;
|
||||
let mut reader: BufReader<File> = BufReader::new(f);
|
||||
|
||||
loop {
|
||||
let mut addr_buff = [0u8; 2];
|
||||
match reader.read_exact(&mut addr_buff) {
|
||||
Ok(_) => (),
|
||||
Err(_) => break,
|
||||
}
|
||||
let addr = u16::from_le_bytes(addr_buff);
|
||||
|
||||
let mut sym_buff: Vec<u8> = Vec::new();
|
||||
reader.read_until(0u8, &mut sym_buff)?;
|
||||
let label = CStr::from_bytes_with_nul(sym_buff.as_slice())
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string();
|
||||
|
||||
eprintln!("#{:04X} {}", addr, label);
|
||||
vm.symbols.insert(addr, label);
|
||||
}
|
||||
}
|
||||
|
||||
// Execute the VM
|
||||
loop {
|
||||
if vm.is_halted() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match vm.run(1024) {
|
||||
Ok(()) => return Ok(()),
|
||||
|
||||
Err(UxnError::Break) => {
|
||||
eprintln!("Interpreter broke; continuing...");
|
||||
continue;
|
||||
}
|
||||
Err(UxnError::ExecutionLimit(_)) => continue,
|
||||
|
||||
Err(e) => {
|
||||
panic!("Got unexpected interpretation error {:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
38
src/bin/uxnsym/main.rs
Normal file
38
src/bin/uxnsym/main.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
use std::env::args;
|
||||
use std::fs::File;
|
||||
use std::io::BufRead;
|
||||
use std::io::BufReader;
|
||||
use std::io::Read;
|
||||
|
||||
use uxn::vm::{Uxn, UxnError};
|
||||
|
||||
fn main() -> Result<(), std::io::Error> {
|
||||
let mut vm = Uxn::new();
|
||||
|
||||
let argv: Vec<String> = args().collect();
|
||||
let f: File = File::open(&argv[1])?;
|
||||
let mut reader = BufReader::new(f);
|
||||
|
||||
loop {
|
||||
let mut addr_buff = [0u8; 2];
|
||||
match reader.read_exact(&mut addr_buff) {
|
||||
Ok(_) => (),
|
||||
Err(_) => break,
|
||||
}
|
||||
let addr = u16::from_le_bytes(addr_buff);
|
||||
|
||||
let mut sym_buff: Vec<u8> = Vec::new();
|
||||
reader.read_until(0u8, &mut sym_buff)?;
|
||||
|
||||
vm.symbols.insert(
|
||||
addr,
|
||||
std::str::from_utf8(sym_buff.as_slice())
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
vm.debug_symbols();
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -18,11 +18,18 @@ impl BuffDevice {
|
|||
|
||||
impl Device for BuffDevice {
|
||||
fn dei1(&mut self, _vm: &mut Uxn, port: u8) -> Result<u8, DeviceError> {
|
||||
let slot = (port & 0xF) as usize;
|
||||
let slot = (port & 0x0F) as usize;
|
||||
let port = port & 0xF0;
|
||||
println!("Got read from device {:02X} slot {:02X}", port, slot);
|
||||
Ok(self.buffer[slot])
|
||||
}
|
||||
fn deo1(&mut self, _vm: &mut Uxn, port: u8, val: u8) -> Result<(), DeviceError> {
|
||||
let slot = (port & 0xF) as usize;
|
||||
let slot = (port & 0x0F) as usize;
|
||||
let port = port & 0xF0;
|
||||
println!(
|
||||
"Got write to device {:02X} slot {:02X} val {:02X}",
|
||||
port, slot, val
|
||||
);
|
||||
self.buffer[slot as usize] = val;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::io::{stderr, stdout, Write};
|
||||
|
||||
use crate::device::{Device, DeviceError};
|
||||
use crate::vm::Uxn;
|
||||
|
||||
|
@ -59,8 +61,31 @@ impl Device for ConsoleDevice {
|
|||
/**
|
||||
* Callback used by UXN to do output through a "device".
|
||||
*/
|
||||
fn deo1(&mut self, vm: &mut Uxn, port: u8, val: u8) -> Result<(), DeviceError> {
|
||||
Ok(())
|
||||
fn deo1(&mut self, _vm: &mut Uxn, port: u8, val: u8) -> Result<(), DeviceError> {
|
||||
let slot = port & 0xF;
|
||||
match slot {
|
||||
0x08 => {
|
||||
stdout().write_all(&[val]).unwrap();
|
||||
if val == 0x0A {
|
||||
stdout().flush().unwrap();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
0x09 => {
|
||||
stderr().write_all(&[val]).unwrap();
|
||||
if val == 0x0A {
|
||||
stderr().flush().unwrap();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
_ => {
|
||||
eprintln!(
|
||||
"Got write #{:02X} to unexpected slot #{:02X} (port #{:02X})",
|
||||
val, slot, port
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn deo2(&mut self, vm: &mut Uxn, port: u8, val: u16) -> Result<(), DeviceError> {
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
use std::borrow::Borrow;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::device::{Device, DeviceError};
|
||||
use crate::stack::Stack;
|
||||
use crate::vm::Uxn;
|
||||
|
||||
/**
|
||||
|
@ -35,8 +40,16 @@ impl Device for SystemDevice {
|
|||
0x0 => (self.vector >> 8) as u8,
|
||||
0x1 => (self.vector & 0xFF) as u8,
|
||||
// The stack ports (somewhat nonstandard)
|
||||
0x2 => vm.wst.borrow().idx(),
|
||||
0x3 => vm.rst.borrow().idx(),
|
||||
0x2 => {
|
||||
let wst: Rc<RefCell<dyn Stack>> = vm.wst.clone();
|
||||
let val = wst.borrow_mut().idx();
|
||||
val
|
||||
}
|
||||
0x3 => {
|
||||
let rst: Rc<RefCell<dyn Stack>> = vm.rst.clone();
|
||||
let val = rst.borrow_mut().idx();
|
||||
val
|
||||
}
|
||||
|
||||
// Red
|
||||
0x8 => (self.red >> 8) as u8,
|
||||
|
@ -52,7 +65,7 @@ impl Device for SystemDevice {
|
|||
|
||||
// The state ports
|
||||
0xe => self.debug,
|
||||
0xf => self.state,
|
||||
0xf => 0,
|
||||
_ => unreachable!(),
|
||||
})
|
||||
}
|
||||
|
@ -108,7 +121,9 @@ impl Device for SystemDevice {
|
|||
}
|
||||
|
||||
// The state ports
|
||||
0xe => self.debug = val,
|
||||
0xe => {
|
||||
vm.debug();
|
||||
}
|
||||
0xf => self.state = val,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
|
51
src/isa.rs
51
src/isa.rs
|
@ -4,7 +4,8 @@ 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 LIT: u8 = 0b10000000; // AKA keep Yes really. Per spec;
|
||||
pub const LIT2: u8 = 0b10100000; // AKA keep Yes really. Per spec;
|
||||
pub const INC: u8 = 0x01;
|
||||
pub const POP: u8 = 0x02;
|
||||
pub const NIP: u8 = 0x03;
|
||||
|
@ -38,9 +39,9 @@ impl Icode {
|
|||
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;
|
||||
pub const SHORT: u8 = 0x20;
|
||||
pub const RETURN: u8 = 0x40;
|
||||
pub const KEEP: u8 = 0x80;
|
||||
|
||||
// Hacking around the official names for some things
|
||||
pub const XOR: u8 = Icode::EOR;
|
||||
|
@ -58,4 +59,46 @@ impl Icode {
|
|||
let icode: u8 = opcode & 0x1F;
|
||||
(kflag, rflag, sflag, icode)
|
||||
}
|
||||
|
||||
pub const fn nameof(opcode: u8) -> &'static str {
|
||||
match opcode {
|
||||
// Nonstandard icodes + extensions
|
||||
Icode::LIT | Icode::LIT2 => &"LIT", // AKA keep Yes really. Per spec,
|
||||
Icode::NOP => &"NOP",
|
||||
// Standard icodes
|
||||
Icode::BRK => &"BRK",
|
||||
Icode::INC => &"INC",
|
||||
Icode::POP => &"POP",
|
||||
Icode::NIP => &"NIP",
|
||||
Icode::SWP => &"SWP",
|
||||
Icode::ROT => &"ROT",
|
||||
Icode::DUP => &"DUP",
|
||||
Icode::OVR => &"OVR",
|
||||
Icode::EQL => &"EQL",
|
||||
Icode::NEQ => &"NEQ",
|
||||
Icode::GTH => &"GTH",
|
||||
Icode::LTH => &"LTH",
|
||||
Icode::JMP => &"JMP",
|
||||
Icode::JCN => &"JNC",
|
||||
Icode::JSR => &"JSR",
|
||||
Icode::STH => &"STH",
|
||||
Icode::LDZ => &"LDZ",
|
||||
Icode::STZ => &"STZ",
|
||||
Icode::LDR => &"LDR",
|
||||
Icode::STR => &"STR",
|
||||
Icode::LDA => &"LDA",
|
||||
Icode::STA => &"STA",
|
||||
Icode::DEI => &"DEI",
|
||||
Icode::DEO => &"DEO",
|
||||
Icode::ADD => &"ADD",
|
||||
Icode::SUB => &"SUB",
|
||||
Icode::MUL => &"MUL",
|
||||
Icode::DIV => &"DIV",
|
||||
Icode::AND => &"AND",
|
||||
Icode::ORA => &"ORA",
|
||||
Icode::EOR => &"EOR",
|
||||
Icode::SFT => &"SFT",
|
||||
_ => Icode::nameof(opcode & 0x1F),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,3 +3,7 @@ pub mod isa;
|
|||
pub mod memory;
|
||||
pub mod stack;
|
||||
pub mod vm;
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
extern crate quickcheck;
|
||||
|
|
|
@ -91,6 +91,8 @@ impl Stack for ArrayStack {
|
|||
#[cfg(test)]
|
||||
mod arrs_test {
|
||||
use super::*;
|
||||
use quickcheck::*;
|
||||
use rstest::*;
|
||||
|
||||
#[test]
|
||||
fn test_push_pop() {
|
||||
|
@ -167,4 +169,41 @@ mod arrs_test {
|
|||
Err(_) => assert!(false, "poppoing stack of size 0 didn't underflow"),
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn set1_get1_round_trip_quick(val: u8) -> bool {
|
||||
let mut s = ArrayStack::new();
|
||||
s.push1(val).unwrap();
|
||||
s.pop1() == Ok(val)
|
||||
}
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case(0x00)]
|
||||
#[case(0x80)]
|
||||
#[case(0xFF)]
|
||||
fn set1_get1_round_trip_manual(#[case] val: u8) {
|
||||
let mut s = ArrayStack::new();
|
||||
s.push1(val).unwrap();
|
||||
assert_eq!(s.pop1(), Ok(val))
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn set2_get2_round_trip_quick(val: u16) -> bool {
|
||||
let mut s = ArrayStack::new();
|
||||
s.push2(val).unwrap();
|
||||
s.pop2() == Ok(val)
|
||||
}
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case(0x00)]
|
||||
#[case(0x8000)]
|
||||
#[case(0x0080)]
|
||||
#[case(0xFFFF)]
|
||||
fn set2_get2_round_trip_manual(#[case] val: u16) {
|
||||
let mut s = ArrayStack::new();
|
||||
s.push2(val).unwrap();
|
||||
assert_eq!(s.pop2(), Ok(val))
|
||||
}
|
||||
}
|
||||
|
|
173
src/vm.rs
173
src/vm.rs
|
@ -1,7 +1,10 @@
|
|||
use std::borrow::Borrow;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use std::*;
|
||||
|
||||
use crate::device::console::ConsoleDevice;
|
||||
use crate::device::null::NullDevice;
|
||||
use crate::device::system::SystemDevice;
|
||||
use crate::device::*;
|
||||
|
@ -46,37 +49,43 @@ pub struct Uxn {
|
|||
pub memory: Rc<RefCell<TrivialMemory>>,
|
||||
// Note: Using Rc so we can start with many NullDevs and replace them
|
||||
pub devices: [Rc<RefCell<dyn Device>>; 16],
|
||||
pub pc: u16, // Program counter
|
||||
pub wst: Rc<RefCell<dyn Stack>>, // Data stack
|
||||
pub rst: Rc<RefCell<dyn Stack>>, // Return stack pointer
|
||||
pub pc: u16, // Program counter
|
||||
pub clock: u64, // Executed instructions count
|
||||
pub wst: Rc<RefCell<dyn Stack>>, // Data stack
|
||||
pub rst: Rc<RefCell<dyn Stack>>, // Return stack pointer
|
||||
pub symbols: HashMap<u16, String>, // Symbol table
|
||||
}
|
||||
|
||||
impl Uxn {
|
||||
pub fn new() -> Uxn {
|
||||
Uxn {
|
||||
let mut uxn = Uxn {
|
||||
memory: Rc::new(RefCell::new(TrivialMemory::new())),
|
||||
devices: [
|
||||
Rc::new(RefCell::new(SystemDevice::new())), // #00
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #01
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #02
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #03
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #04
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #05
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #06
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #07
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #08
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #09
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #0a
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #0b
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #0c
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #0d
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #0e
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #0f
|
||||
Rc::new(RefCell::new(SystemDevice::new())), // #00
|
||||
Rc::new(RefCell::new(ConsoleDevice::new())), // #01
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #02
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #03
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #04
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #05
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #06
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #07
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #08
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #09
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #0a
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #0b
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #0c
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #0d
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #0e
|
||||
Rc::new(RefCell::new(NullDevice::new())), // #0f
|
||||
],
|
||||
pc: 0x0100,
|
||||
clock: 0,
|
||||
wst: Rc::new(RefCell::new(ArrayStack::new())),
|
||||
rst: Rc::new(RefCell::new(ArrayStack::new())),
|
||||
}
|
||||
symbols: HashMap::new(),
|
||||
};
|
||||
uxn.symbols.insert(0x0100u16, "main".into());
|
||||
uxn
|
||||
}
|
||||
|
||||
pub fn of1(program: &[u8]) -> Uxn {
|
||||
|
@ -93,8 +102,35 @@ impl Uxn {
|
|||
self.dei1(0x0f).unwrap() != 0
|
||||
}
|
||||
|
||||
pub fn debug(&mut self) {
|
||||
let wst = self.wst.clone();
|
||||
let rst = self.rst.clone();
|
||||
|
||||
eprint!(
|
||||
"<clock> #{:04X}\n<pc> #{:04X}\n<data stack>",
|
||||
self.clock, self.pc
|
||||
);
|
||||
let wst_idx = wst.borrow_mut().idx();
|
||||
for i in 0..wst_idx {
|
||||
eprint!(" #{:02X}", self.wst.borrow_mut().get1(i).unwrap());
|
||||
}
|
||||
eprint!("\n<return stack>");
|
||||
let rst_idx = rst.borrow_mut().idx();
|
||||
for i in 0..rst_idx {
|
||||
eprint!(" #{:02X}", self.rst.borrow_mut().get1(i).unwrap());
|
||||
}
|
||||
eprint!("\n");
|
||||
}
|
||||
|
||||
pub fn debug_symbols(&self) {
|
||||
for (k, v) in self.symbols.borrow().into_iter() {
|
||||
println!(" #{:02X} {}", k, v);
|
||||
}
|
||||
}
|
||||
|
||||
fn device(&self, port: u8) -> Rc<RefCell<dyn Device>> {
|
||||
Rc::clone(&self.devices[(port & 0xF0 >> 4) as usize])
|
||||
let devnum = ((port & 0xF0) >> 4) as usize;
|
||||
Rc::clone(&self.devices[devnum])
|
||||
}
|
||||
|
||||
pub fn dei1(&mut self, port: u8) -> Result<u8, DeviceError> {
|
||||
|
@ -124,11 +160,24 @@ impl Uxn {
|
|||
}
|
||||
|
||||
pub fn lda1(&mut self, address: u16) -> Result<u8, MemoryError> {
|
||||
self.memory.borrow().get1(address)
|
||||
self.memory.clone().borrow_mut().get1(address)
|
||||
}
|
||||
|
||||
pub fn lda2(&mut self, address: u16) -> Result<u16, MemoryError> {
|
||||
self.memory.borrow().get2(address)
|
||||
self.memory.clone().borrow_mut().get2(address)
|
||||
}
|
||||
|
||||
pub fn branch(&mut self, address: u16) {
|
||||
match self.symbols.get(&address) {
|
||||
Some(label) => eprintln!(
|
||||
"Branch #{:04X} to {} (#{:04X})",
|
||||
self.pc - 1,
|
||||
label,
|
||||
address
|
||||
),
|
||||
None => (),
|
||||
}
|
||||
self.pc = address;
|
||||
}
|
||||
|
||||
// Run one clock cycle (instruction)
|
||||
|
@ -136,20 +185,33 @@ impl Uxn {
|
|||
match self.lda1(self.pc) {
|
||||
Err(e) => Err(UxnError::MemoryError(e)),
|
||||
Ok(icode) => {
|
||||
match self.symbols.get(&self.pc) {
|
||||
Some(sym) => eprintln!("{}:", sym),
|
||||
None => (),
|
||||
}
|
||||
|
||||
// The value of PC is defined to be the value of the NEXT pc ala Mips
|
||||
self.pc += 1;
|
||||
self.clock += 1;
|
||||
|
||||
// Short circuit for cheap NOPs (POPk, POPkr)
|
||||
if icode & Icode::NOP == Icode::NOP {
|
||||
if (icode & !Icode::RETURN) == Icode::NOP {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Extract flags
|
||||
let (kflag, rflag, sflag, icode) = Icode::parse(icode);
|
||||
let (kflag, rflag, sflag, icode5) = Icode::parse(icode);
|
||||
|
||||
println!(
|
||||
"pc #{:04X}: #{:02x} ( {:05b} s: {:1x} r: {:1x} k: {:1x} )",
|
||||
self.pc, icode, icode, sflag, rflag, kflag
|
||||
eprintln!(
|
||||
" cycle #{:04X}; pc #{:04X}, rom pc: #{:04X}: {} ( {:05b} s: {:1x} r: {:1x} k: {:1x} )",
|
||||
self.clock,
|
||||
self.pc - 1,
|
||||
self.pc - 0x0101,
|
||||
Icode::nameof(icode),
|
||||
icode5,
|
||||
sflag,
|
||||
rflag,
|
||||
kflag
|
||||
);
|
||||
|
||||
// Swizzle the stacks as needed
|
||||
|
@ -206,19 +268,25 @@ impl Uxn {
|
|||
}
|
||||
};
|
||||
|
||||
match (kflag, rflag, sflag, icode) {
|
||||
match (kflag, rflag, sflag, icode5) {
|
||||
(0, 0, 0, Icode::BRK) => {
|
||||
// BRK --
|
||||
return Err(UxnError::Break);
|
||||
}
|
||||
(1, _, _, Icode::BRK) => {
|
||||
// BRKk aka LIT -- a
|
||||
push(wst.clone(), load(self.pc)?)?;
|
||||
self.pc += if sflag == 1 { 2 } else { 1 };
|
||||
let val = load(self.pc)?;
|
||||
if sflag == 0 {
|
||||
eprintln!(" LIT #{:02X}", val);
|
||||
} else {
|
||||
eprintln!(" LIT #{:04X}", val);
|
||||
}
|
||||
push(wst.clone(), val)?;
|
||||
self.branch(self.pc + if sflag == 1 { 2 } else { 1 });
|
||||
}
|
||||
(_, _, _, Icode::INC) => {
|
||||
// INC a -- a
|
||||
push(wst.clone(), pop(wst.clone())? + 1)?;
|
||||
push(wst.clone(), pop(wst.clone())?.wrapping_add(1))?;
|
||||
}
|
||||
(_, _, _, Icode::POP) => {
|
||||
// POP a --
|
||||
|
@ -287,19 +355,19 @@ impl Uxn {
|
|||
(_, _, 0, Icode::JMP) => {
|
||||
// JMP1 a --
|
||||
let delta = wst.borrow_mut().pop1()? as i8;
|
||||
self.pc = self.pc.wrapping_add(delta as u16);
|
||||
self.branch(self.pc.wrapping_add(delta as u16));
|
||||
}
|
||||
(_, _, 1, Icode::JMP) => {
|
||||
// JMP2 a --
|
||||
let delta = wst.borrow_mut().pop2()?;
|
||||
self.pc = delta;
|
||||
let target = wst.borrow_mut().pop2()?;
|
||||
self.branch(target);
|
||||
}
|
||||
(_, _, 0, Icode::JCN) => {
|
||||
// JCN1 cnd8 addr8 (relative)
|
||||
let delta = wst.borrow_mut().pop1()? as i8;
|
||||
let cnd = wst.borrow_mut().pop1()?;
|
||||
if cnd != 0 {
|
||||
self.pc = self.pc.wrapping_add(delta as u16);
|
||||
self.branch(self.pc.wrapping_add(delta as u16));
|
||||
}
|
||||
}
|
||||
(_, _, 1, Icode::JCN) => {
|
||||
|
@ -307,19 +375,19 @@ impl Uxn {
|
|||
let addr = wst.borrow_mut().pop2()?;
|
||||
let cnd = wst.borrow_mut().pop1()?;
|
||||
if cnd != 0 {
|
||||
self.pc = addr;
|
||||
self.branch(addr);
|
||||
}
|
||||
}
|
||||
(_, _, 0, Icode::JSR) => {
|
||||
// JSR1 addr8 (relative)
|
||||
rst.borrow_mut().push2(self.pc)?;
|
||||
let delta = wst.borrow_mut().pop1()? as i8;
|
||||
self.pc = self.pc.wrapping_add(delta as u16);
|
||||
self.branch(self.pc.wrapping_add(delta as u16));
|
||||
}
|
||||
(_, _, 1, Icode::JSR) => {
|
||||
// JSR2 addr16 (absolute)
|
||||
rst.borrow_mut().push2(self.pc)?;
|
||||
self.pc = wst.borrow_mut().pop2()?;
|
||||
self.branch(wst.borrow_mut().pop2()?);
|
||||
}
|
||||
(_, _, _, Icode::STH) => {
|
||||
// STH a
|
||||
|
@ -345,11 +413,6 @@ impl Uxn {
|
|||
// STR val addr8 --
|
||||
let delta = wst.borrow_mut().pop1()?;
|
||||
let addr = self.pc.wrapping_add(delta as u16);
|
||||
println!(
|
||||
"STR] Got delta {}, effective store address #{:04x}",
|
||||
delta, addr
|
||||
);
|
||||
|
||||
store(addr, pop(wst)?)?;
|
||||
}
|
||||
(_, _, _, Icode::LDA) => {
|
||||
|
@ -366,12 +429,14 @@ impl Uxn {
|
|||
// DEI port8 -- a8
|
||||
let mut wst = wst.borrow_mut();
|
||||
let port = wst.pop1()?;
|
||||
eprintln!(" DEI got port {:02X}", port);
|
||||
wst.push1(self.dei1(port)?)?;
|
||||
}
|
||||
(_, _, 1, Icode::DEI) => {
|
||||
// DEI2 port8 -- a16
|
||||
let mut wst = wst.borrow_mut();
|
||||
let port = wst.pop1()?;
|
||||
eprintln!(" DEI2 got port {:02X}", port);
|
||||
wst.push2(self.dei2(port)?)?;
|
||||
}
|
||||
(_, _, 0, Icode::DEO) => {
|
||||
|
@ -379,37 +444,39 @@ impl Uxn {
|
|||
let mut wst = wst.borrow_mut();
|
||||
let port = wst.pop1()?;
|
||||
let val = wst.pop1()?;
|
||||
self.deo1(port, val);
|
||||
self.deo1(port, val).unwrap();
|
||||
}
|
||||
(_, _, 1, Icode::DEO) => {
|
||||
// DEO2 a16 port8 --
|
||||
let mut wst = wst.borrow_mut();
|
||||
let port = wst.pop1()?;
|
||||
let val = wst.pop2()?;
|
||||
self.deo2(port, val);
|
||||
self.deo2(port, val).unwrap();
|
||||
}
|
||||
(_, _, _, Icode::ADD) => {
|
||||
// ADD a b -- c
|
||||
let b = pop(wst.clone())?;
|
||||
let a = pop(wst.clone())?;
|
||||
push(wst.clone(), a + b)?;
|
||||
push(wst.clone(), a.wrapping_add(b))?;
|
||||
}
|
||||
(_, _, _, Icode::SUB) => {
|
||||
// SUB a b -- c
|
||||
let b = pop(wst.clone())?;
|
||||
let a = pop(wst.clone())?;
|
||||
push(wst.clone(), a - b)?;
|
||||
push(wst.clone(), a.wrapping_sub(b))?;
|
||||
}
|
||||
(_, _, _, Icode::MUL) => {
|
||||
// MUL a b -- c
|
||||
let b = pop(wst.clone())?;
|
||||
let a = pop(wst.clone())?;
|
||||
push(wst.clone(), a * b)?;
|
||||
push(wst.clone(), a.wrapping_mul(b))?;
|
||||
}
|
||||
(_, _, _, Icode::DIV) => {
|
||||
// DIV a b -- c
|
||||
self.debug();
|
||||
let b = pop(wst.clone())?;
|
||||
let a = pop(wst.clone())?;
|
||||
eprintln!(" DIV {:04X} {:04X}", a, b);
|
||||
push(wst.clone(), a / b)?;
|
||||
}
|
||||
(_, _, _, Icode::AND) => {
|
||||
|
@ -451,11 +518,6 @@ impl Uxn {
|
|||
if executed == limit {
|
||||
return Err(UxnError::ExecutionLimit(executed));
|
||||
}
|
||||
|
||||
if self.is_halted() {
|
||||
break;
|
||||
}
|
||||
|
||||
executed += 1;
|
||||
|
||||
match self.step() {
|
||||
|
@ -463,6 +525,5 @@ impl Uxn {
|
|||
Ok(()) => continue,
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -722,12 +722,13 @@ fn test_sta2() {
|
|||
fn test_dei() {
|
||||
nofmt::pls! {
|
||||
let mut vm = Uxn::of1(&[
|
||||
Icode::LIT, 0x30, Icode::DEI, Icode::BRK,
|
||||
Icode::LIT, 0x30,
|
||||
Icode::DEI,
|
||||
Icode::BRK,
|
||||
]);
|
||||
let dev = Rc::new(RefCell::new(BuffDevice::new()));
|
||||
vm.deo1(0x30, 0xFF).unwrap();
|
||||
vm.deo1(0x31, 0xEE).unwrap();
|
||||
vm.devices[3] = dev.clone();
|
||||
vm.deo1(0x30, 0xFF).unwrap();
|
||||
}
|
||||
assert_eq!(vm.run(64), Err(UxnError::Break));
|
||||
assert_eq!(vm.wst.borrow().idx(), 1);
|
||||
|
@ -738,11 +739,13 @@ fn test_dei() {
|
|||
fn test_dei2() {
|
||||
nofmt::pls! {
|
||||
let mut vm = Uxn::of1(&[
|
||||
Icode::LIT, 0x30, Icode::DEI | Icode::SHORT, Icode::BRK,
|
||||
Icode::LIT, 0x30,
|
||||
Icode::DEI | Icode::SHORT,
|
||||
Icode::BRK,
|
||||
]);
|
||||
let dev = Rc::new(RefCell::new(BuffDevice::new()));
|
||||
vm.deo2(0x30, 0xFFEE).unwrap();
|
||||
vm.devices[3] = dev.clone();
|
||||
vm.deo2(0x30, 0xFFEE).unwrap();
|
||||
}
|
||||
assert_eq!(vm.run(64), Err(UxnError::Break));
|
||||
assert_eq!(vm.wst.borrow().idx(), 2);
|
||||
|
|
Loading…
Reference in a new issue