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.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
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]]
|
[[package]]
|
||||||
name = "nofmt"
|
name = "nofmt"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -9,42 +167,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b06910a54adb901a01dfd9c475e7959c41acd55a078101ec70fb180f01b7435f"
|
checksum = "b06910a54adb901a01dfd9c475e7959c41acd55a078101ec70fb180f01b7435f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_enum"
|
name = "pin-project-lite"
|
||||||
version = "0.5.7"
|
version = "0.2.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9"
|
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
||||||
dependencies = [
|
|
||||||
"num_enum_derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_enum_derive"
|
name = "pin-utils"
|
||||||
version = "0.5.7"
|
version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce"
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
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]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
|
@ -55,6 +187,17 @@ dependencies = [
|
||||||
"unicode-ident",
|
"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]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.23"
|
version = "1.0.23"
|
||||||
|
@ -65,10 +208,89 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "rand"
|
||||||
version = "1.0.151"
|
version = "0.8.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
|
@ -81,35 +303,6 @@ dependencies = [
|
||||||
"unicode-ident",
|
"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]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
|
@ -121,5 +314,12 @@ name = "uxn"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nofmt",
|
"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"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
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
|
# 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"
|
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 {
|
impl Device for BuffDevice {
|
||||||
fn dei1(&mut self, _vm: &mut Uxn, port: u8) -> Result<u8, DeviceError> {
|
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])
|
Ok(self.buffer[slot])
|
||||||
}
|
}
|
||||||
fn deo1(&mut self, _vm: &mut Uxn, port: u8, val: u8) -> Result<(), DeviceError> {
|
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;
|
self.buffer[slot as usize] = val;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::io::{stderr, stdout, Write};
|
||||||
|
|
||||||
use crate::device::{Device, DeviceError};
|
use crate::device::{Device, DeviceError};
|
||||||
use crate::vm::Uxn;
|
use crate::vm::Uxn;
|
||||||
|
|
||||||
|
@ -59,9 +61,32 @@ impl Device for ConsoleDevice {
|
||||||
/**
|
/**
|
||||||
* Callback used by UXN to do output through a "device".
|
* Callback used by UXN to do output through a "device".
|
||||||
*/
|
*/
|
||||||
fn deo1(&mut self, vm: &mut Uxn, port: u8, val: u8) -> Result<(), DeviceError> {
|
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(())
|
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> {
|
fn deo2(&mut self, vm: &mut Uxn, port: u8, val: u16) -> Result<(), DeviceError> {
|
||||||
Err(DeviceError::PortTypeError(
|
Err(DeviceError::PortTypeError(
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
|
use std::borrow::Borrow;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::device::{Device, DeviceError};
|
use crate::device::{Device, DeviceError};
|
||||||
|
use crate::stack::Stack;
|
||||||
use crate::vm::Uxn;
|
use crate::vm::Uxn;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,8 +40,16 @@ impl Device for SystemDevice {
|
||||||
0x0 => (self.vector >> 8) as u8,
|
0x0 => (self.vector >> 8) as u8,
|
||||||
0x1 => (self.vector & 0xFF) as u8,
|
0x1 => (self.vector & 0xFF) as u8,
|
||||||
// The stack ports (somewhat nonstandard)
|
// The stack ports (somewhat nonstandard)
|
||||||
0x2 => vm.wst.borrow().idx(),
|
0x2 => {
|
||||||
0x3 => vm.rst.borrow().idx(),
|
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
|
// Red
|
||||||
0x8 => (self.red >> 8) as u8,
|
0x8 => (self.red >> 8) as u8,
|
||||||
|
@ -52,7 +65,7 @@ impl Device for SystemDevice {
|
||||||
|
|
||||||
// The state ports
|
// The state ports
|
||||||
0xe => self.debug,
|
0xe => self.debug,
|
||||||
0xf => self.state,
|
0xf => 0,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -108,7 +121,9 @@ impl Device for SystemDevice {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The state ports
|
// The state ports
|
||||||
0xe => self.debug = val,
|
0xe => {
|
||||||
|
vm.debug();
|
||||||
|
}
|
||||||
0xf => self.state = val,
|
0xf => self.state = val,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
51
src/isa.rs
51
src/isa.rs
|
@ -4,7 +4,8 @@ pub struct Icode {}
|
||||||
impl Icode {
|
impl Icode {
|
||||||
// Official names
|
// Official names
|
||||||
pub const BRK: u8 = 0x00u8;
|
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 INC: u8 = 0x01;
|
||||||
pub const POP: u8 = 0x02;
|
pub const POP: u8 = 0x02;
|
||||||
pub const NIP: u8 = 0x03;
|
pub const NIP: u8 = 0x03;
|
||||||
|
@ -38,9 +39,9 @@ impl Icode {
|
||||||
pub const SFT: u8 = 0x1f;
|
pub const SFT: u8 = 0x1f;
|
||||||
|
|
||||||
// Opcode flags
|
// Opcode flags
|
||||||
pub const SHORT: u8 = 0x1 << 5;
|
pub const SHORT: u8 = 0x20;
|
||||||
pub const RETURN: u8 = 0x1 << 6;
|
pub const RETURN: u8 = 0x40;
|
||||||
pub const KEEP: u8 = 0x1 << 7;
|
pub const KEEP: u8 = 0x80;
|
||||||
|
|
||||||
// Hacking around the official names for some things
|
// Hacking around the official names for some things
|
||||||
pub const XOR: u8 = Icode::EOR;
|
pub const XOR: u8 = Icode::EOR;
|
||||||
|
@ -58,4 +59,46 @@ impl Icode {
|
||||||
let icode: u8 = opcode & 0x1F;
|
let icode: u8 = opcode & 0x1F;
|
||||||
(kflag, rflag, sflag, icode)
|
(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 memory;
|
||||||
pub mod stack;
|
pub mod stack;
|
||||||
pub mod vm;
|
pub mod vm;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate quickcheck;
|
||||||
|
|
|
@ -91,6 +91,8 @@ impl Stack for ArrayStack {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod arrs_test {
|
mod arrs_test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use quickcheck::*;
|
||||||
|
use rstest::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_push_pop() {
|
fn test_push_pop() {
|
||||||
|
@ -167,4 +169,41 @@ mod arrs_test {
|
||||||
Err(_) => assert!(false, "poppoing stack of size 0 didn't underflow"),
|
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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
137
src/vm.rs
137
src/vm.rs
|
@ -1,7 +1,10 @@
|
||||||
|
use std::borrow::Borrow;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::*;
|
use std::*;
|
||||||
|
|
||||||
|
use crate::device::console::ConsoleDevice;
|
||||||
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::*;
|
||||||
|
@ -47,17 +50,19 @@ pub struct Uxn {
|
||||||
// Note: Using Rc so we can start with many NullDevs and replace them
|
// Note: Using Rc so we can start with many NullDevs and replace them
|
||||||
pub devices: [Rc<RefCell<dyn Device>>; 16],
|
pub devices: [Rc<RefCell<dyn Device>>; 16],
|
||||||
pub pc: u16, // Program counter
|
pub pc: u16, // Program counter
|
||||||
|
pub clock: u64, // Executed instructions count
|
||||||
pub wst: Rc<RefCell<dyn Stack>>, // Data stack
|
pub wst: Rc<RefCell<dyn Stack>>, // Data stack
|
||||||
pub rst: Rc<RefCell<dyn Stack>>, // Return stack pointer
|
pub rst: Rc<RefCell<dyn Stack>>, // Return stack pointer
|
||||||
|
pub symbols: HashMap<u16, String>, // Symbol table
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Uxn {
|
impl Uxn {
|
||||||
pub fn new() -> Uxn {
|
pub fn new() -> Uxn {
|
||||||
Uxn {
|
let mut uxn = Uxn {
|
||||||
memory: Rc::new(RefCell::new(TrivialMemory::new())),
|
memory: Rc::new(RefCell::new(TrivialMemory::new())),
|
||||||
devices: [
|
devices: [
|
||||||
Rc::new(RefCell::new(SystemDevice::new())), // #00
|
Rc::new(RefCell::new(SystemDevice::new())), // #00
|
||||||
Rc::new(RefCell::new(NullDevice::new())), // #01
|
Rc::new(RefCell::new(ConsoleDevice::new())), // #01
|
||||||
Rc::new(RefCell::new(NullDevice::new())), // #02
|
Rc::new(RefCell::new(NullDevice::new())), // #02
|
||||||
Rc::new(RefCell::new(NullDevice::new())), // #03
|
Rc::new(RefCell::new(NullDevice::new())), // #03
|
||||||
Rc::new(RefCell::new(NullDevice::new())), // #04
|
Rc::new(RefCell::new(NullDevice::new())), // #04
|
||||||
|
@ -74,9 +79,13 @@ impl Uxn {
|
||||||
Rc::new(RefCell::new(NullDevice::new())), // #0f
|
Rc::new(RefCell::new(NullDevice::new())), // #0f
|
||||||
],
|
],
|
||||||
pc: 0x0100,
|
pc: 0x0100,
|
||||||
|
clock: 0,
|
||||||
wst: Rc::new(RefCell::new(ArrayStack::new())),
|
wst: Rc::new(RefCell::new(ArrayStack::new())),
|
||||||
rst: 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 {
|
pub fn of1(program: &[u8]) -> Uxn {
|
||||||
|
@ -93,8 +102,35 @@ impl Uxn {
|
||||||
self.dei1(0x0f).unwrap() != 0
|
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>> {
|
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> {
|
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> {
|
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> {
|
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)
|
// Run one clock cycle (instruction)
|
||||||
|
@ -136,20 +185,33 @@ impl Uxn {
|
||||||
match self.lda1(self.pc) {
|
match self.lda1(self.pc) {
|
||||||
Err(e) => Err(UxnError::MemoryError(e)),
|
Err(e) => Err(UxnError::MemoryError(e)),
|
||||||
Ok(icode) => {
|
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
|
// The value of PC is defined to be the value of the NEXT pc ala Mips
|
||||||
self.pc += 1;
|
self.pc += 1;
|
||||||
|
self.clock += 1;
|
||||||
|
|
||||||
// Short circuit for cheap NOPs (POPk, POPkr)
|
// Short circuit for cheap NOPs (POPk, POPkr)
|
||||||
if icode & Icode::NOP == Icode::NOP {
|
if (icode & !Icode::RETURN) == Icode::NOP {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract flags
|
// Extract flags
|
||||||
let (kflag, rflag, sflag, icode) = Icode::parse(icode);
|
let (kflag, rflag, sflag, icode5) = Icode::parse(icode);
|
||||||
|
|
||||||
println!(
|
eprintln!(
|
||||||
"pc #{:04X}: #{:02x} ( {:05b} s: {:1x} r: {:1x} k: {:1x} )",
|
" cycle #{:04X}; pc #{:04X}, rom pc: #{:04X}: {} ( {:05b} s: {:1x} r: {:1x} k: {:1x} )",
|
||||||
self.pc, icode, icode, sflag, rflag, kflag
|
self.clock,
|
||||||
|
self.pc - 1,
|
||||||
|
self.pc - 0x0101,
|
||||||
|
Icode::nameof(icode),
|
||||||
|
icode5,
|
||||||
|
sflag,
|
||||||
|
rflag,
|
||||||
|
kflag
|
||||||
);
|
);
|
||||||
|
|
||||||
// Swizzle the stacks as needed
|
// 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) => {
|
(0, 0, 0, Icode::BRK) => {
|
||||||
// BRK --
|
// BRK --
|
||||||
return Err(UxnError::Break);
|
return Err(UxnError::Break);
|
||||||
}
|
}
|
||||||
(1, _, _, Icode::BRK) => {
|
(1, _, _, Icode::BRK) => {
|
||||||
// BRKk aka LIT -- a
|
// BRKk aka LIT -- a
|
||||||
push(wst.clone(), load(self.pc)?)?;
|
let val = load(self.pc)?;
|
||||||
self.pc += if sflag == 1 { 2 } else { 1 };
|
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) => {
|
(_, _, _, Icode::INC) => {
|
||||||
// INC a -- a
|
// INC a -- a
|
||||||
push(wst.clone(), pop(wst.clone())? + 1)?;
|
push(wst.clone(), pop(wst.clone())?.wrapping_add(1))?;
|
||||||
}
|
}
|
||||||
(_, _, _, Icode::POP) => {
|
(_, _, _, Icode::POP) => {
|
||||||
// POP a --
|
// POP a --
|
||||||
|
@ -287,19 +355,19 @@ impl Uxn {
|
||||||
(_, _, 0, Icode::JMP) => {
|
(_, _, 0, Icode::JMP) => {
|
||||||
// JMP1 a --
|
// 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.branch(self.pc.wrapping_add(delta as u16));
|
||||||
}
|
}
|
||||||
(_, _, 1, Icode::JMP) => {
|
(_, _, 1, Icode::JMP) => {
|
||||||
// JMP2 a --
|
// JMP2 a --
|
||||||
let delta = wst.borrow_mut().pop2()?;
|
let target = wst.borrow_mut().pop2()?;
|
||||||
self.pc = delta;
|
self.branch(target);
|
||||||
}
|
}
|
||||||
(_, _, 0, Icode::JCN) => {
|
(_, _, 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()?;
|
||||||
if cnd != 0 {
|
if cnd != 0 {
|
||||||
self.pc = self.pc.wrapping_add(delta as u16);
|
self.branch(self.pc.wrapping_add(delta as u16));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(_, _, 1, Icode::JCN) => {
|
(_, _, 1, Icode::JCN) => {
|
||||||
|
@ -307,19 +375,19 @@ impl Uxn {
|
||||||
let addr = wst.borrow_mut().pop2()?;
|
let addr = wst.borrow_mut().pop2()?;
|
||||||
let cnd = wst.borrow_mut().pop1()?;
|
let cnd = wst.borrow_mut().pop1()?;
|
||||||
if cnd != 0 {
|
if cnd != 0 {
|
||||||
self.pc = addr;
|
self.branch(addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(_, _, 0, Icode::JSR) => {
|
(_, _, 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.branch(self.pc.wrapping_add(delta as u16));
|
||||||
}
|
}
|
||||||
(_, _, 1, Icode::JSR) => {
|
(_, _, 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.branch(wst.borrow_mut().pop2()?);
|
||||||
}
|
}
|
||||||
(_, _, _, Icode::STH) => {
|
(_, _, _, Icode::STH) => {
|
||||||
// STH a
|
// STH a
|
||||||
|
@ -345,11 +413,6 @@ impl Uxn {
|
||||||
// STR val addr8 --
|
// STR val addr8 --
|
||||||
let delta = wst.borrow_mut().pop1()?;
|
let delta = wst.borrow_mut().pop1()?;
|
||||||
let addr = self.pc.wrapping_add(delta as u16);
|
let addr = self.pc.wrapping_add(delta as u16);
|
||||||
println!(
|
|
||||||
"STR] Got delta {}, effective store address #{:04x}",
|
|
||||||
delta, addr
|
|
||||||
);
|
|
||||||
|
|
||||||
store(addr, pop(wst)?)?;
|
store(addr, pop(wst)?)?;
|
||||||
}
|
}
|
||||||
(_, _, _, Icode::LDA) => {
|
(_, _, _, Icode::LDA) => {
|
||||||
|
@ -366,12 +429,14 @@ impl Uxn {
|
||||||
// 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()?;
|
||||||
|
eprintln!(" DEI got port {:02X}", port);
|
||||||
wst.push1(self.dei1(port)?)?;
|
wst.push1(self.dei1(port)?)?;
|
||||||
}
|
}
|
||||||
(_, _, 1, Icode::DEI) => {
|
(_, _, 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()?;
|
||||||
|
eprintln!(" DEI2 got port {:02X}", port);
|
||||||
wst.push2(self.dei2(port)?)?;
|
wst.push2(self.dei2(port)?)?;
|
||||||
}
|
}
|
||||||
(_, _, 0, Icode::DEO) => {
|
(_, _, 0, Icode::DEO) => {
|
||||||
|
@ -379,37 +444,39 @@ impl Uxn {
|
||||||
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).unwrap();
|
||||||
}
|
}
|
||||||
(_, _, 1, Icode::DEO) => {
|
(_, _, 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).unwrap();
|
||||||
}
|
}
|
||||||
(_, _, _, Icode::ADD) => {
|
(_, _, _, 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.wrapping_add(b))?;
|
||||||
}
|
}
|
||||||
(_, _, _, Icode::SUB) => {
|
(_, _, _, 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.wrapping_sub(b))?;
|
||||||
}
|
}
|
||||||
(_, _, _, Icode::MUL) => {
|
(_, _, _, 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.wrapping_mul(b))?;
|
||||||
}
|
}
|
||||||
(_, _, _, Icode::DIV) => {
|
(_, _, _, Icode::DIV) => {
|
||||||
// DIV a b -- c
|
// DIV a b -- c
|
||||||
|
self.debug();
|
||||||
let b = pop(wst.clone())?;
|
let b = pop(wst.clone())?;
|
||||||
let a = pop(wst.clone())?;
|
let a = pop(wst.clone())?;
|
||||||
|
eprintln!(" DIV {:04X} {:04X}", a, b);
|
||||||
push(wst.clone(), a / b)?;
|
push(wst.clone(), a / b)?;
|
||||||
}
|
}
|
||||||
(_, _, _, Icode::AND) => {
|
(_, _, _, Icode::AND) => {
|
||||||
|
@ -451,11 +518,6 @@ impl Uxn {
|
||||||
if executed == limit {
|
if executed == limit {
|
||||||
return Err(UxnError::ExecutionLimit(executed));
|
return Err(UxnError::ExecutionLimit(executed));
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.is_halted() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
executed += 1;
|
executed += 1;
|
||||||
|
|
||||||
match self.step() {
|
match self.step() {
|
||||||
|
@ -463,6 +525,5 @@ impl Uxn {
|
||||||
Ok(()) => continue,
|
Ok(()) => continue,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -722,12 +722,13 @@ fn test_sta2() {
|
||||||
fn test_dei() {
|
fn test_dei() {
|
||||||
nofmt::pls! {
|
nofmt::pls! {
|
||||||
let mut vm = Uxn::of1(&[
|
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()));
|
let dev = Rc::new(RefCell::new(BuffDevice::new()));
|
||||||
vm.deo1(0x30, 0xFF).unwrap();
|
|
||||||
vm.deo1(0x31, 0xEE).unwrap();
|
|
||||||
vm.devices[3] = dev.clone();
|
vm.devices[3] = dev.clone();
|
||||||
|
vm.deo1(0x30, 0xFF).unwrap();
|
||||||
}
|
}
|
||||||
assert_eq!(vm.run(64), Err(UxnError::Break));
|
assert_eq!(vm.run(64), Err(UxnError::Break));
|
||||||
assert_eq!(vm.wst.borrow().idx(), 1);
|
assert_eq!(vm.wst.borrow().idx(), 1);
|
||||||
|
@ -738,11 +739,13 @@ fn test_dei() {
|
||||||
fn test_dei2() {
|
fn test_dei2() {
|
||||||
nofmt::pls! {
|
nofmt::pls! {
|
||||||
let mut vm = Uxn::of1(&[
|
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()));
|
let dev = Rc::new(RefCell::new(BuffDevice::new()));
|
||||||
vm.deo2(0x30, 0xFFEE).unwrap();
|
|
||||||
vm.devices[3] = dev.clone();
|
vm.devices[3] = dev.clone();
|
||||||
|
vm.deo2(0x30, 0xFFEE).unwrap();
|
||||||
}
|
}
|
||||||
assert_eq!(vm.run(64), Err(UxnError::Break));
|
assert_eq!(vm.run(64), Err(UxnError::Break));
|
||||||
assert_eq!(vm.wst.borrow().idx(), 2);
|
assert_eq!(vm.wst.borrow().idx(), 2);
|
||||||
|
|
Loading…
Reference in a new issue