Compare commits
No commits in common. "618314a7bb818e26460b50d59231c72fdb16802f" and "34ceb1b392bf46fd470af3f4300c1f5d4676d79f" have entirely different histories.
618314a7bb
...
34ceb1b392
23 changed files with 185 additions and 1426 deletions
257
Cargo.lock
generated
257
Cargo.lock
generated
|
@ -11,48 +11,18 @@ dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "autocfg"
|
|
||||||
version = "0.1.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg 1.1.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "1.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "0.1.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cloudabi"
|
|
||||||
version = "0.0.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "env_logger"
|
name = "env_logger"
|
||||||
version = "0.8.4"
|
version = "0.8.4"
|
||||||
|
@ -63,12 +33,6 @@ dependencies = [
|
||||||
"regex",
|
"regex",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fuchsia-cprng"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures"
|
name = "futures"
|
||||||
version = "0.3.25"
|
version = "0.3.25"
|
||||||
|
@ -170,17 +134,11 @@ version = "0.2.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lazy_static"
|
|
||||||
version = "1.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.139"
|
version = "0.2.139"
|
||||||
|
@ -193,7 +151,7 @@ version = "0.4.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -208,47 +166,6 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b06910a54adb901a01dfd9c475e7959c41acd55a078101ec70fb180f01b7435f"
|
checksum = "b06910a54adb901a01dfd9c475e7959c41acd55a078101ec70fb180f01b7435f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num"
|
|
||||||
version = "0.1.42"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e"
|
|
||||||
dependencies = [
|
|
||||||
"num-integer",
|
|
||||||
"num-iter",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-integer"
|
|
||||||
version = "0.1.45"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg 1.1.0",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-iter"
|
|
||||||
version = "0.1.43"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg 1.1.0",
|
|
||||||
"num-integer",
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-traits"
|
|
||||||
version = "0.2.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg 1.1.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.9"
|
version = "0.2.9"
|
||||||
|
@ -278,7 +195,7 @@ checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"log",
|
"log",
|
||||||
"rand 0.8.5",
|
"rand",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -290,59 +207,15 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand"
|
|
||||||
version = "0.6.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg 0.1.8",
|
|
||||||
"libc",
|
|
||||||
"rand_chacha",
|
|
||||||
"rand_core 0.4.2",
|
|
||||||
"rand_hc",
|
|
||||||
"rand_isaac",
|
|
||||||
"rand_jitter",
|
|
||||||
"rand_os",
|
|
||||||
"rand_pcg",
|
|
||||||
"rand_xorshift",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.8.5"
|
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 = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand_core 0.6.4",
|
"rand_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_chacha"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg 0.1.8",
|
|
||||||
"rand_core 0.3.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_core"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
|
||||||
dependencies = [
|
|
||||||
"rand_core 0.4.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_core"
|
|
||||||
version = "0.4.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_core"
|
name = "rand_core"
|
||||||
version = "0.6.4"
|
version = "0.6.4"
|
||||||
|
@ -352,77 +225,6 @@ dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_hc"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
|
|
||||||
dependencies = [
|
|
||||||
"rand_core 0.3.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_isaac"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
|
|
||||||
dependencies = [
|
|
||||||
"rand_core 0.3.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_jitter"
|
|
||||||
version = "0.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"rand_core 0.4.2",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_os"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
|
|
||||||
dependencies = [
|
|
||||||
"cloudabi",
|
|
||||||
"fuchsia-cprng",
|
|
||||||
"libc",
|
|
||||||
"rand_core 0.4.2",
|
|
||||||
"rdrand",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_pcg"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg 0.1.8",
|
|
||||||
"rand_core 0.4.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_xorshift"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
|
|
||||||
dependencies = [
|
|
||||||
"rand_core 0.3.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rdrand"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
|
||||||
dependencies = [
|
|
||||||
"rand_core 0.3.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.7.0"
|
version = "1.7.0"
|
||||||
|
@ -458,7 +260,7 @@ version = "0.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7229b505ae0706e64f37ffc54a9c163e11022a6636d58fe1f3f52018257ff9f7"
|
checksum = "7229b505ae0706e64f37ffc54a9c163e11022a6636d58fe1f3f52018257ff9f7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
|
@ -475,30 +277,6 @@ dependencies = [
|
||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sdl2"
|
|
||||||
version = "0.32.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d051a07231e303f5f719da78cb6f7394f6d5b54f733aef5b0b447804a83edd7b"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"lazy_static",
|
|
||||||
"libc",
|
|
||||||
"num",
|
|
||||||
"rand 0.6.5",
|
|
||||||
"sdl2-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sdl2-sys"
|
|
||||||
version = "0.32.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "34e71125077d297d57e4c1acfe8981b5bdfbf5a20e7b589abfdcb33bf1127f86"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if 0.1.10",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.16"
|
version = "1.0.16"
|
||||||
|
@ -511,7 +289,7 @@ version = "0.4.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef"
|
checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg 1.1.0",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -538,7 +316,6 @@ dependencies = [
|
||||||
"nofmt",
|
"nofmt",
|
||||||
"quickcheck",
|
"quickcheck",
|
||||||
"rstest",
|
"rstest",
|
||||||
"sdl2",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -546,25 +323,3 @@ name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi"
|
|
||||||
version = "0.3.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-i686-pc-windows-gnu",
|
|
||||||
"winapi-x86_64-pc-windows-gnu",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-i686-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|
||||||
|
|
|
@ -11,16 +11,8 @@ path = "src/bin/uxncli/main.rs"
|
||||||
name = "uxnsym"
|
name = "uxnsym"
|
||||||
path = "src/bin/uxnsym/main.rs"
|
path = "src/bin/uxnsym/main.rs"
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "uxnsdl2"
|
|
||||||
path = "src/bin/uxnsdl2/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.sdl2]
|
|
||||||
version = "0.32.1" # FIXME: Get upgraded
|
|
||||||
default-features = false
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
quickcheck = "1.0.3"
|
quickcheck = "1.0.3"
|
||||||
rstest = "0.16.0"
|
rstest = "0.16.0"
|
||||||
|
|
BIN
assets/bardo.png
BIN
assets/bardo.png
Binary file not shown.
Before Width: | Height: | Size: 17 KiB |
|
@ -103,7 +103,10 @@ Raw labels are inserted directly into bytecode.
|
||||||
Absolute labels are double quantities.
|
Absolute labels are double quantities.
|
||||||
Relative labels are single signed byte quantities with a ±127 range.
|
Relative labels are single signed byte quantities with a ±127 range.
|
||||||
|
|
||||||
The zero page (`#00XX`) is used for program globals and convenient scratch space.
|
The zero page (`#00XX`) is used for system devices, along other things.
|
||||||
|
It's common to see labels such as `.System/vector`, being a reference to the address `#0000` packed into just `#00`
|
||||||
|
However as UXN has a special `LDZ` operation for loading from the zero page, this address can be specified as simply `#96` to save a byte.
|
||||||
|
As the last device is mapped to `#CX`, it is common to see `#DX`, `#EX` and `#FX` used for program-global variables for ease of access.
|
||||||
|
|
||||||
Literal byte relative references ala `,foo` are used for control flow.
|
Literal byte relative references ala `,foo` are used for control flow.
|
||||||
Using only a single byte, these references have a range of ±127 instructions.
|
Using only a single byte, these references have a range of ±127 instructions.
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,596 +0,0 @@
|
||||||
( Opcode Tester )
|
|
||||||
|
|
||||||
( Requirements:
|
|
||||||
EQU/EQU2 should put #00 or #01 on the stack
|
|
||||||
#18 DEO should output ascii character to console )
|
|
||||||
|
|
||||||
%EMIT { #18 DEO }
|
|
||||||
%FAIL { #00 EQU ;fail JCN2 }
|
|
||||||
%TEST-SHORT { EQU2 DUP #30 ADD EMIT FAIL }
|
|
||||||
%TEST-BYTE { EQU DUP #30 ADD EMIT FAIL }
|
|
||||||
%MODE { #20 EMIT }
|
|
||||||
%OPCODE { #0a EMIT }
|
|
||||||
%TYPE { OPCODE OPCODE }
|
|
||||||
%DEBUG { #010e DEO }
|
|
||||||
%HALT { #010f DEO BRK }
|
|
||||||
|
|
||||||
|0000
|
|
||||||
|
|
||||||
@zeropage
|
|
||||||
&byte $1 &short $2
|
|
||||||
|
|
||||||
|0100
|
|
||||||
|
|
||||||
( Logic )
|
|
||||||
|
|
||||||
( EQU )
|
|
||||||
@test_equ
|
|
||||||
&normal
|
|
||||||
#f8 #f8 EQU [ #01 ] TEST-BYTE
|
|
||||||
#01 #01 EQU [ #01 ] TEST-BYTE
|
|
||||||
#f8 #01 EQU [ #00 ] TEST-BYTE
|
|
||||||
#01 #f8 EQU [ #00 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#f801 #f801 EQU2 [ #01 ] TEST-BYTE
|
|
||||||
#01f8 #01f8 EQU2 [ #01 ] TEST-BYTE
|
|
||||||
#f801 #01f8 EQU2 [ #00 ] TEST-BYTE
|
|
||||||
#01f8 #f801 EQU2 [ #00 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&keep
|
|
||||||
#f8 #f8 EQUk ADD ADD [ #f1 ] TEST-BYTE
|
|
||||||
#01 #01 EQUk ADD ADD [ #03 ] TEST-BYTE
|
|
||||||
#f8 #01 EQUk ADD ADD [ #f9 ] TEST-BYTE
|
|
||||||
#01 #f8 EQUk ADD ADD [ #f9 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short_keep
|
|
||||||
#f801 #f801 EQU2k #00 ADD2 ADD2 [ #f102 ] TEST-SHORT
|
|
||||||
#01f8 #01f8 EQU2k #00 ADD2 ADD2 [ #04f0 ] TEST-SHORT
|
|
||||||
#f801 #01f8 EQU2k #00 ADD2 ADD2 [ #f9f9 ] TEST-SHORT
|
|
||||||
#01f8 #f801 EQU2k #00 ADD2 ADD2 [ #f9f9 ] TEST-SHORT
|
|
||||||
OPCODE
|
|
||||||
|
|
||||||
( NEQ )
|
|
||||||
@test_neq
|
|
||||||
&normal
|
|
||||||
#f8 #f8 NEQ [ #00 ] TEST-BYTE
|
|
||||||
#01 #01 NEQ [ #00 ] TEST-BYTE
|
|
||||||
#f8 #01 NEQ [ #01 ] TEST-BYTE
|
|
||||||
#01 #f8 NEQ [ #01 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#f801 #f801 NEQ2 [ #00 ] TEST-BYTE
|
|
||||||
#01f8 #01f8 NEQ2 [ #00 ] TEST-BYTE
|
|
||||||
#f801 #01f8 NEQ2 [ #01 ] TEST-BYTE
|
|
||||||
#01f8 #f801 NEQ2 [ #01 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&keep
|
|
||||||
#f8 #f8 NEQk ADD ADD [ #f0 ] TEST-BYTE
|
|
||||||
#01 #01 NEQk ADD ADD [ #02 ] TEST-BYTE
|
|
||||||
#f8 #01 NEQk ADD ADD [ #fa ] TEST-BYTE
|
|
||||||
#01 #f8 NEQk ADD ADD [ #fa ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short_kep
|
|
||||||
#f801 #f801 NEQ2k #00 ADD2 ADD2 [ #f002 ] TEST-SHORT
|
|
||||||
#01f8 #01f8 NEQ2k #00 ADD2 ADD2 [ #03f0 ] TEST-SHORT
|
|
||||||
#f801 #01f8 NEQ2k #00 ADD2 ADD2 [ #faf9 ] TEST-SHORT
|
|
||||||
#01f8 #f801 NEQ2k #00 ADD2 ADD2 [ #faf9 ] TEST-SHORT
|
|
||||||
OPCODE
|
|
||||||
|
|
||||||
( GTH )
|
|
||||||
@test_gth
|
|
||||||
&normal
|
|
||||||
#f8 #f8 GTH [ #00 ] TEST-BYTE
|
|
||||||
#01 #01 GTH [ #00 ] TEST-BYTE
|
|
||||||
#f8 #01 GTH [ #01 ] TEST-BYTE
|
|
||||||
#01 #f8 GTH [ #00 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#f801 #f801 GTH2 [ #00 ] TEST-BYTE
|
|
||||||
#01f8 #01f8 GTH2 [ #00 ] TEST-BYTE
|
|
||||||
#f801 #01f8 GTH2 [ #01 ] TEST-BYTE
|
|
||||||
#01f8 #f801 GTH2 [ #00 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&keep
|
|
||||||
#f8 #f8 GTHk ADD ADD [ #f0 ] TEST-BYTE
|
|
||||||
#01 #01 GTHk ADD ADD [ #02 ] TEST-BYTE
|
|
||||||
#f8 #01 GTHk ADD ADD [ #fa ] TEST-BYTE
|
|
||||||
#01 #f8 GTHk ADD ADD [ #f9 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short_keep
|
|
||||||
#f801 #f801 GTH2k #00 ADD2 ADD2 [ #f002 ] TEST-SHORT
|
|
||||||
#01f8 #01f8 GTH2k #00 ADD2 ADD2 [ #03f0 ] TEST-SHORT
|
|
||||||
#f801 #01f8 GTH2k #00 ADD2 ADD2 [ #faf9 ] TEST-SHORT
|
|
||||||
#01f8 #f801 GTH2k #00 ADD2 ADD2 [ #f9f9 ] TEST-SHORT
|
|
||||||
OPCODE
|
|
||||||
|
|
||||||
( LTH )
|
|
||||||
@test_lth
|
|
||||||
&normal
|
|
||||||
#f8 #f8 LTH [ #00 ] TEST-BYTE
|
|
||||||
#01 #01 LTH [ #00 ] TEST-BYTE
|
|
||||||
#f8 #01 LTH [ #00 ] TEST-BYTE
|
|
||||||
#01 #f8 LTH [ #01 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#f801 #f801 LTH2 [ #00 ] TEST-BYTE
|
|
||||||
#01f8 #01f8 LTH2 [ #00 ] TEST-BYTE
|
|
||||||
#f801 #01f8 LTH2 [ #00 ] TEST-BYTE
|
|
||||||
#01f8 #f801 LTH2 [ #01 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&keep
|
|
||||||
#f8 #f8 LTHk ADD ADD [ #f0 ] TEST-BYTE
|
|
||||||
#01 #01 LTHk ADD ADD [ #02 ] TEST-BYTE
|
|
||||||
#f8 #01 LTHk ADD ADD [ #f9 ] TEST-BYTE
|
|
||||||
#01 #f8 LTHk ADD ADD [ #fa ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short_keep
|
|
||||||
#f801 #f801 LTH2k #00 ADD2 ADD2 [ #f002 ] TEST-SHORT
|
|
||||||
#01f8 #01f8 LTH2k #00 ADD2 ADD2 [ #03f0 ] TEST-SHORT
|
|
||||||
#f801 #01f8 LTH2k #00 ADD2 ADD2 [ #f9f9 ] TEST-SHORT
|
|
||||||
#01f8 #f801 LTH2k #00 ADD2 ADD2 [ #faf9 ] TEST-SHORT
|
|
||||||
TYPE
|
|
||||||
|
|
||||||
( Arithmetic )
|
|
||||||
|
|
||||||
( ADD )
|
|
||||||
@test_add
|
|
||||||
&normal
|
|
||||||
#ff #00 ADD [ #ff ] TEST-BYTE
|
|
||||||
#01 #ff ADD [ #00 ] TEST-BYTE
|
|
||||||
#ff #ff ADD [ #fe ] TEST-BYTE
|
|
||||||
#fe #ff ADD [ #fd ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#ffff #0000 ADD2 [ #ffff ] TEST-SHORT
|
|
||||||
#0001 #ffff ADD2 [ #0000 ] TEST-SHORT
|
|
||||||
#ffff #ffff ADD2 [ #fffe ] TEST-SHORT
|
|
||||||
#fffe #ffff ADD2 [ #fffd ] TEST-SHORT
|
|
||||||
MODE
|
|
||||||
&keep
|
|
||||||
#ff #00 ADDk ADD ADD [ #fe ] TEST-BYTE
|
|
||||||
#01 #ff ADDk ADD ADD [ #00 ] TEST-BYTE
|
|
||||||
#ff #ff ADDk ADD ADD [ #fc ] TEST-BYTE
|
|
||||||
#fe #ff ADDk ADD ADD [ #fa ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short_keep
|
|
||||||
#ffff #0000 ADD2k ADD2 ADD2 [ #fffe ] TEST-SHORT
|
|
||||||
#0001 #ffff ADD2k ADD2 ADD2 [ #0000 ] TEST-SHORT
|
|
||||||
#ffff #ffff ADD2k ADD2 ADD2 [ #fffc ] TEST-SHORT
|
|
||||||
#fffe #ffff ADD2k ADD2 ADD2 [ #fffa ] TEST-SHORT
|
|
||||||
OPCODE
|
|
||||||
|
|
||||||
( SUB )
|
|
||||||
@test_sub
|
|
||||||
&normal
|
|
||||||
#ff #00 SUB [ #ff ] TEST-BYTE
|
|
||||||
#01 #ff SUB [ #02 ] TEST-BYTE
|
|
||||||
#ff #ff SUB [ #00 ] TEST-BYTE
|
|
||||||
#fe #ff SUB [ #ff ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#ffff #0000 SUB2 [ #ffff ] TEST-SHORT
|
|
||||||
#0001 #ffff SUB2 [ #0002 ] TEST-SHORT
|
|
||||||
#ffff #ffff SUB2 [ #0000 ] TEST-SHORT
|
|
||||||
#fffe #ffff SUB2 [ #ffff ] TEST-SHORT
|
|
||||||
MODE
|
|
||||||
&keep
|
|
||||||
#ff #00 SUBk ADD ADD [ #fe ] TEST-BYTE
|
|
||||||
#01 #ff SUBk ADD ADD [ #02 ] TEST-BYTE
|
|
||||||
#ff #ff SUBk ADD ADD [ #fe ] TEST-BYTE
|
|
||||||
#fe #ff SUBk ADD ADD [ #fc ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short_keep
|
|
||||||
#ffff #0000 SUB2k ADD2 ADD2 [ #fffe ] TEST-SHORT
|
|
||||||
#0001 #ffff SUB2k ADD2 ADD2 [ #0002 ] TEST-SHORT
|
|
||||||
#ffff #ffff SUB2k ADD2 ADD2 [ #fffe ] TEST-SHORT
|
|
||||||
#fffe #ffff SUB2k ADD2 ADD2 [ #fffc ] TEST-SHORT
|
|
||||||
OPCODE
|
|
||||||
|
|
||||||
( MUL )
|
|
||||||
@test_mul
|
|
||||||
&normal
|
|
||||||
#00 #01 MUL [ #00 ] TEST-BYTE
|
|
||||||
#3f #e7 MUL [ #d9 ] TEST-BYTE
|
|
||||||
#37 #3f MUL [ #89 ] TEST-BYTE
|
|
||||||
#10 #02 MUL [ #20 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#1000 #0003 MUL2 [ #3000 ] TEST-SHORT
|
|
||||||
#abcd #1234 MUL2 [ #4fa4 ] TEST-SHORT
|
|
||||||
#8000 #0200 MUL2 [ #0000 ] TEST-SHORT
|
|
||||||
#2222 #0003 MUL2 [ #6666 ] TEST-SHORT
|
|
||||||
MODE
|
|
||||||
&keep
|
|
||||||
#00 #01 MULk ADD ADD [ #01 ] TEST-BYTE
|
|
||||||
#3f #e7 MULk ADD ADD [ #ff ] TEST-BYTE
|
|
||||||
#37 #3f MULk ADD ADD [ #ff ] TEST-BYTE
|
|
||||||
#10 #02 MULk ADD ADD [ #32 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short_keep
|
|
||||||
#1000 #0003 MUL2k ADD2 ADD2 [ #4003 ] TEST-SHORT
|
|
||||||
#abcd #1234 MUL2k ADD2 ADD2 [ #0da5 ] TEST-SHORT
|
|
||||||
#8000 #0200 MUL2k ADD2 ADD2 [ #8200 ] TEST-SHORT
|
|
||||||
#2222 #0003 MUL2k ADD2 ADD2 [ #888b ] TEST-SHORT
|
|
||||||
OPCODE
|
|
||||||
|
|
||||||
( DIV )
|
|
||||||
@test_div
|
|
||||||
&normal
|
|
||||||
#10 #02 DIV [ #08 ] TEST-BYTE
|
|
||||||
#20 #20 DIV [ #01 ] TEST-BYTE
|
|
||||||
#34 #01 DIV [ #34 ] TEST-BYTE
|
|
||||||
#02 #ef DIV [ #00 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#1000 #0040 DIV2 [ #0040 ] TEST-SHORT
|
|
||||||
#abcd #1234 DIV2 [ #0009 ] TEST-SHORT
|
|
||||||
#8000 #0200 DIV2 [ #0040 ] TEST-SHORT
|
|
||||||
#2222 #0003 DIV2 [ #0b60 ] TEST-SHORT
|
|
||||||
MODE
|
|
||||||
&keep
|
|
||||||
#10 #02 DIVk ADD ADD [ #1a ] TEST-BYTE
|
|
||||||
#20 #20 DIVk ADD ADD [ #41 ] TEST-BYTE
|
|
||||||
#34 #01 DIVk ADD ADD [ #69 ] TEST-BYTE
|
|
||||||
#02 #ef DIVk ADD ADD [ #f1 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short_keep
|
|
||||||
#1000 #0040 DIV2k ADD2 ADD2 [ #1080 ] TEST-SHORT
|
|
||||||
#abcd #1234 DIV2k ADD2 ADD2 [ #be0a ] TEST-SHORT
|
|
||||||
#8000 #0200 DIV2k ADD2 ADD2 [ #8240 ] TEST-SHORT
|
|
||||||
#2222 #0003 DIV2k ADD2 ADD2 [ #2d85 ] TEST-SHORT
|
|
||||||
TYPE
|
|
||||||
|
|
||||||
( Stack )
|
|
||||||
|
|
||||||
( INC )
|
|
||||||
@test_inc
|
|
||||||
&normal
|
|
||||||
#01 INC [ #02 ] TEST-BYTE
|
|
||||||
#ff INC [ #00 ] TEST-BYTE
|
|
||||||
#fe INC [ #ff ] TEST-BYTE
|
|
||||||
#00 INC [ #01 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#0001 INC2 [ #0002 ] TEST-SHORT
|
|
||||||
#ffff INC2 [ #0000 ] TEST-SHORT
|
|
||||||
#fffe INC2 [ #ffff ] TEST-SHORT
|
|
||||||
#0000 INC2 [ #0001 ] TEST-SHORT
|
|
||||||
MODE
|
|
||||||
&keep
|
|
||||||
#01 INCk ADD [ #03 ] TEST-BYTE
|
|
||||||
#ff INCk ADD [ #ff ] TEST-BYTE
|
|
||||||
#fe INCk ADD [ #fd ] TEST-BYTE
|
|
||||||
#00 INCk ADD [ #01 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short_keep
|
|
||||||
#0001 INC2k ADD2 [ #0003 ] TEST-SHORT
|
|
||||||
#ffff INC2k ADD2 [ #ffff ] TEST-SHORT
|
|
||||||
#fffe INC2k ADD2 [ #fffd ] TEST-SHORT
|
|
||||||
#0000 INC2k ADD2 [ #0001 ] TEST-SHORT
|
|
||||||
OPCODE
|
|
||||||
|
|
||||||
( POP )
|
|
||||||
@test_pop
|
|
||||||
&normal
|
|
||||||
#0a #0b POP [ #0a ] TEST-BYTE
|
|
||||||
#0a #0b #0c POP POP [ #0a ] TEST-BYTE
|
|
||||||
#0a #0b #0c ADD POP [ #0a ] TEST-BYTE
|
|
||||||
#0a #0b #0c POP ADD [ #15 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#0a0b #0c0d POP2 [ #0a0b ] TEST-SHORT
|
|
||||||
#0a0b #0c0d #0e0f POP2 POP2 [ #0a0b ] TEST-SHORT
|
|
||||||
#0a0b #0c0d #0e0f ADD2 POP2 [ #0a0b ] TEST-SHORT
|
|
||||||
#0a0b #0c0d #0e0f POP2 ADD2 [ #1618 ] TEST-SHORT
|
|
||||||
MODE
|
|
||||||
&keep
|
|
||||||
#0a #0b POPk [ #0b ] TEST-BYTE POP
|
|
||||||
#0a #0b #0c POPk POP [ #0b ] TEST-BYTE POP
|
|
||||||
#0a #0b #0c ADD POPk [ #17 ] TEST-BYTE POP
|
|
||||||
#0a #0b #0c POPk ADD [ #17 ] TEST-BYTE POP
|
|
||||||
MODE
|
|
||||||
&short_keep
|
|
||||||
#0a0b #0c0d POP2k [ #0c0d ] TEST-SHORT POP2
|
|
||||||
#0a0b #0c0d #0e0f POP2k POP2 [ #0c0d ] TEST-SHORT POP2
|
|
||||||
#0a0b #0c0d #0e0f ADD2 POP2k [ #1a1c ] TEST-SHORT POP2
|
|
||||||
#0a0b #0c0d #0e0f POP2k ADD2 [ #1a1c ] TEST-SHORT POP2
|
|
||||||
OPCODE
|
|
||||||
|
|
||||||
( DUP )
|
|
||||||
@test_dup
|
|
||||||
&normal
|
|
||||||
#0a #0b DUP ADD ADD [ #20 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#0a0b DUP2 ADD2 [ #1416 ] TEST-SHORT
|
|
||||||
MODE
|
|
||||||
&keep
|
|
||||||
#0a #0b DUPk ADD ADD ADD [ #2b ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short_keep
|
|
||||||
#0a0b DUP2k ADD2 ADD2 [ #1e21 ] TEST-SHORT
|
|
||||||
OPCODE
|
|
||||||
|
|
||||||
( NIP )
|
|
||||||
@test_nip
|
|
||||||
&normal
|
|
||||||
#12 #34 #56 NIP ADD [ #68 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#1234 #5678 #9abc NIP2 ADD2 [ #acf0 ] TEST-SHORT
|
|
||||||
MODE
|
|
||||||
&keep
|
|
||||||
#12 #34 #56 NIPk ADD ADD [ #e0 ] TEST-BYTE POP
|
|
||||||
MODE
|
|
||||||
&short_keep
|
|
||||||
#1234 #5678 #9abc NIP2k ADD2 ADD2 [ #8bf0 ] TEST-SHORT POP2
|
|
||||||
OPCODE
|
|
||||||
|
|
||||||
( SWP )
|
|
||||||
@test_swp
|
|
||||||
&normal
|
|
||||||
#02 #10 SWP DIV [ #08 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#0a0b #0c0d SWP2 NIP2 [ #0a0b ] TEST-SHORT
|
|
||||||
MODE
|
|
||||||
&keep
|
|
||||||
#02 #10 SWPk DIV ADD ADD [ #1a ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short_keep
|
|
||||||
#0a0b #0c0d SWP2k POP2 POP2 POP2 [ #0a0b ] TEST-SHORT
|
|
||||||
OPCODE
|
|
||||||
|
|
||||||
( OVR )
|
|
||||||
@test_ovr
|
|
||||||
&normal
|
|
||||||
#02 #10 OVR DIV ADD [ #0a ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#0a0b #0c0d OVR2 NIP2 ADD2 [ #1416 ] TEST-SHORT
|
|
||||||
MODE
|
|
||||||
&keep
|
|
||||||
#02 #10 OVRk DIV ADD ADD ADD [ #1c ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short_keep
|
|
||||||
#0a0b #0c0d OVR2k NIP2 ADD2 ADD2 ADD2 [ #2a2e ] TEST-SHORT
|
|
||||||
OPCODE
|
|
||||||
|
|
||||||
( ROT )
|
|
||||||
@test_rot
|
|
||||||
&normal
|
|
||||||
#02 #04 #10 ROT DIV ADD [ #0c ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#0a0b #0c0d #0c0f ROT2 ADD2 NIP2 [ #161a ] TEST-SHORT
|
|
||||||
MODE
|
|
||||||
&keep
|
|
||||||
#02 #04 #10 ROTk DIV ADD ADD ADD ADD [ #22 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short_keep
|
|
||||||
#0a0b #0c0d #0c0f ROT2k ADD2 NIP2 ADD2 ADD2 ADD2 [ #3841 ] TEST-SHORT
|
|
||||||
TYPE
|
|
||||||
|
|
||||||
( Bitwise )
|
|
||||||
|
|
||||||
( AND )
|
|
||||||
@test_and
|
|
||||||
&normal
|
|
||||||
#fc #3f AND [ #3c ] TEST-BYTE
|
|
||||||
#f0 #0f AND [ #00 ] TEST-BYTE
|
|
||||||
#ff #3c AND [ #3c ] TEST-BYTE
|
|
||||||
#02 #03 AND [ #02 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#f0f0 #00f0 AND2 [ #00f0 ] TEST-SHORT
|
|
||||||
#aaaa #5555 AND2 [ #0000 ] TEST-SHORT
|
|
||||||
#ffff #1234 AND2 [ #1234 ] TEST-SHORT
|
|
||||||
#abcd #0a0c AND2 [ #0a0c ] TEST-SHORT
|
|
||||||
MODE
|
|
||||||
&keep
|
|
||||||
#fc #3f ANDk ADD ADD [ #77 ] TEST-BYTE
|
|
||||||
#f0 #0f ANDk ADD ADD [ #ff ] TEST-BYTE
|
|
||||||
#ff #3c ANDk ADD ADD [ #77 ] TEST-BYTE
|
|
||||||
#02 #03 ANDk ADD ADD [ #07 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short_keep
|
|
||||||
#f0f0 #00f0 AND2k ADD2 ADD2 [ #f2d0 ] TEST-SHORT
|
|
||||||
#aaaa #5555 AND2k ADD2 ADD2 [ #ffff ] TEST-SHORT
|
|
||||||
#ffff #1234 AND2k ADD2 ADD2 [ #2467 ] TEST-SHORT
|
|
||||||
#abcd #0a0c AND2k ADD2 ADD2 [ #bfe5 ] TEST-SHORT
|
|
||||||
OPCODE
|
|
||||||
|
|
||||||
( ORA )
|
|
||||||
@test_ora
|
|
||||||
&normal
|
|
||||||
#0f #f0 ORA [ #ff ] TEST-BYTE
|
|
||||||
#ab #cd ORA [ #ef ] TEST-BYTE
|
|
||||||
#12 #34 ORA [ #36 ] TEST-BYTE
|
|
||||||
#88 #10 ORA [ #98 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#0f0f #f0f0 ORA2 [ #ffff ] TEST-SHORT
|
|
||||||
#abab #cdcd ORA2 [ #efef ] TEST-SHORT
|
|
||||||
#1122 #1234 ORA2 [ #1336 ] TEST-SHORT
|
|
||||||
#8888 #1000 ORA2 [ #9888 ] TEST-SHORT
|
|
||||||
MODE
|
|
||||||
&keep
|
|
||||||
#0f #f0 ORAk ADD ADD [ #fe ] TEST-BYTE
|
|
||||||
#ab #cd ORAk ADD ADD [ #67 ] TEST-BYTE
|
|
||||||
#12 #34 ORAk ADD ADD [ #7c ] TEST-BYTE
|
|
||||||
#88 #10 ORAk ADD ADD [ #30 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short_keep
|
|
||||||
#0f0f #f0f0 ORA2k ADD2 ADD2 [ #fffe ] TEST-SHORT
|
|
||||||
#abab #cdcd ORA2k ADD2 ADD2 [ #6967 ] TEST-SHORT
|
|
||||||
#1122 #1234 ORA2k ADD2 ADD2 [ #368c ] TEST-SHORT
|
|
||||||
#8888 #1000 ORA2k ADD2 ADD2 [ #3110 ] TEST-SHORT
|
|
||||||
OPCODE
|
|
||||||
|
|
||||||
( EOR )
|
|
||||||
@test_eor
|
|
||||||
&normal
|
|
||||||
#00 #00 EOR [ #00 ] TEST-BYTE
|
|
||||||
#ff #00 EOR [ #ff ] TEST-BYTE
|
|
||||||
#aa #55 EOR [ #ff ] TEST-BYTE
|
|
||||||
#ff #ff EOR [ #00 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#ffff #ff00 EOR2 [ #00ff ] TEST-SHORT
|
|
||||||
#aaaa #5555 EOR2 [ #ffff ] TEST-SHORT
|
|
||||||
#1122 #1234 EOR2 [ #0316 ] TEST-SHORT
|
|
||||||
#8888 #1000 EOR2 [ #9888 ] TEST-SHORT
|
|
||||||
MODE
|
|
||||||
&keep
|
|
||||||
#00 #00 EORk ADD ADD [ #00 ] TEST-BYTE
|
|
||||||
#ff #00 EORk ADD ADD [ #fe ] TEST-BYTE
|
|
||||||
#aa #55 EORk ADD ADD [ #fe ] TEST-BYTE
|
|
||||||
#ff #ff EORk ADD ADD [ #fe ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short_keep
|
|
||||||
#ffff #ff00 EOR2k ADD2 ADD2 [ #fffe ] TEST-SHORT
|
|
||||||
#aaaa #5555 EOR2k ADD2 ADD2 [ #fffe ] TEST-SHORT
|
|
||||||
#1122 #1234 EOR2k ADD2 ADD2 [ #266c ] TEST-SHORT
|
|
||||||
#8888 #1000 EOR2k ADD2 ADD2 [ #3110 ] TEST-SHORT
|
|
||||||
OPCODE
|
|
||||||
|
|
||||||
( SFT )
|
|
||||||
@test_sft
|
|
||||||
&normal
|
|
||||||
#ff #08 SFT [ #00 ] TEST-BYTE
|
|
||||||
#ff #e0 SFT [ #00 ] TEST-BYTE
|
|
||||||
#ff #11 SFT [ #fe ] TEST-BYTE
|
|
||||||
#ff #12 SFT [ #7e ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#ffff #01 SFT2 [ #7fff ] TEST-SHORT
|
|
||||||
#ffff #70 SFT2 [ #ff80 ] TEST-SHORT
|
|
||||||
#ffff #7e SFT2 [ #0180 ] TEST-SHORT
|
|
||||||
#ffff #e3 SFT2 [ #c000 ] TEST-SHORT
|
|
||||||
MODE
|
|
||||||
&keep
|
|
||||||
#ff #08 SFTk ADD ADD [ #07 ] TEST-BYTE
|
|
||||||
#ff #e0 SFTk ADD ADD [ #df ] TEST-BYTE
|
|
||||||
#ff #11 SFTk ADD ADD [ #0e ] TEST-BYTE
|
|
||||||
#ff #12 SFTk ADD ADD [ #8f ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short_keep
|
|
||||||
#ffff #01 SFT2k ROT POP ADD2 [ #7ffe ] TEST-SHORT
|
|
||||||
#ffff #70 SFT2k ROT POP ADD2 [ #ff7f ] TEST-SHORT
|
|
||||||
#ffff #7e SFT2k ROT POP ADD2 [ #017f ] TEST-SHORT
|
|
||||||
#ffff #e3 SFT2k ROT POP ADD2 [ #bfff ] TEST-SHORT
|
|
||||||
TYPE
|
|
||||||
|
|
||||||
( Memory )
|
|
||||||
|
|
||||||
( STA/LDA )
|
|
||||||
@test_sta_lda
|
|
||||||
&normal
|
|
||||||
#34 ;absolute/byte STA ;absolute/byte LDA [ #34 ] TEST-BYTE
|
|
||||||
#56 ;absolute/byte STA ;absolute/byte LDA [ #56 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#1234 ;absolute/short STA2 ;absolute/short LDA2 [ #1234 ] TEST-SHORT
|
|
||||||
#5678 ;absolute/short STA2 ;absolute/short LDA2 [ #5678 ] TEST-SHORT
|
|
||||||
OPCODE
|
|
||||||
|
|
||||||
( STZ/LDZ )
|
|
||||||
@test_stz_ldz
|
|
||||||
&normal
|
|
||||||
#ab .zeropage/byte STZ .zeropage/byte LDZ [ #ab ] TEST-BYTE
|
|
||||||
#cd .zeropage/byte STZ .zeropage/byte LDZ [ #cd ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#1234 .zeropage/short STZ2 .zeropage/short LDZ2 [ #1234 ] TEST-SHORT
|
|
||||||
#5678 .zeropage/short STZ2 .zeropage/short LDZ2 [ #5678 ] TEST-SHORT
|
|
||||||
OPCODE
|
|
||||||
|
|
||||||
( STR/LDR )
|
|
||||||
@test_str_ldr
|
|
||||||
&normal
|
|
||||||
[ LIT &before1 fe ] POP
|
|
||||||
;&before1 LDA [ #fe ] TEST-BYTE ( ensure we even have the right ROM loc. )
|
|
||||||
,&before1 LDR [ #fe ] TEST-BYTE ( test loading the seed value )
|
|
||||||
#22 ,&before1 STR ,&before1 LDR [ #22 ] TEST-BYTE
|
|
||||||
#ef ,&after1 STR ,&after1 LDR [ #ef ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
|
|
||||||
&short
|
|
||||||
[ LIT2 &before2 fefe ] POP2
|
|
||||||
;&before2 LDA2 [ #fefe ] TEST-BYTE ( ensure we even have the right ROM loc. )
|
|
||||||
,&before2 LDR2 [ #fefe ] TEST-SHORT ( test loading the seed value )
|
|
||||||
#1234 ,&before2 STR2 ,&before2 LDR2 [ #1234 ] TEST-SHORT
|
|
||||||
#5678 ,&after2 STR2 ,&after2 LDR2 [ #5678 ] TEST-SHORT
|
|
||||||
[ LIT &after1 $1 ] POP
|
|
||||||
[ LIT2 &after2 $2 ] POP2
|
|
||||||
OPCODE
|
|
||||||
|
|
||||||
@test_dei_deo
|
|
||||||
( DEI/DEO )
|
|
||||||
LIT "1 EMIT
|
|
||||||
LIT "1 EMIT
|
|
||||||
TYPE
|
|
||||||
|
|
||||||
( Branching )
|
|
||||||
|
|
||||||
( JMP )
|
|
||||||
@test_jmp
|
|
||||||
&normal
|
|
||||||
#12 #34 ,&reljmp JMP SWP &reljmp POP [ #12 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#56 #78 ;&absjmp JMP2 SWP &absjmp POP [ #56 ] TEST-BYTE
|
|
||||||
OPCODE
|
|
||||||
|
|
||||||
( JCN )
|
|
||||||
@test_jnc
|
|
||||||
&normal
|
|
||||||
#23 #01 ,&reljcn-y JCN INC &reljcn-y [ #23 ] TEST-BYTE
|
|
||||||
#23 #00 ,&reljcn-n JCN INC &reljcn-n [ #24 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#23 #01 ;&absjcn-y JCN2 INC &absjcn-y [ #23 ] TEST-BYTE
|
|
||||||
#23 #00 ;&absjcn-n JCN2 INC &absjcn-n [ #24 ] TEST-BYTE
|
|
||||||
OPCODE
|
|
||||||
|
|
||||||
( JSR - Requires return mode )
|
|
||||||
@test_jsr
|
|
||||||
&short
|
|
||||||
#12 #34 ;routine JSR2 [ #46 ] TEST-BYTE
|
|
||||||
OPCODE
|
|
||||||
|
|
||||||
( STH )
|
|
||||||
@test_sth
|
|
||||||
&normal
|
|
||||||
LITr ff STHr [ #ff ] TEST-BYTE
|
|
||||||
LITr 0a LITr 0b ADDr STHr [ #15 ] TEST-BYTE
|
|
||||||
#0a STH #0b STH ADDr STHr [ #15 ] TEST-BYTE
|
|
||||||
MODE
|
|
||||||
&short
|
|
||||||
#000a STH2 #000b STH2 ADD2r STH2r [ #0015 ] TEST-SHORT
|
|
||||||
TYPE
|
|
||||||
|
|
||||||
( Keep )
|
|
||||||
@test_keep
|
|
||||||
&normal
|
|
||||||
#12 #34 ADDk ADD ADD [ #8c ] TEST-BYTE
|
|
||||||
OPCODE
|
|
||||||
|
|
||||||
@halt
|
|
||||||
DEBUG
|
|
||||||
HALT
|
|
||||||
|
|
||||||
@fail
|
|
||||||
#ffff #0000 DEO2
|
|
||||||
DEBUG
|
|
||||||
HALT
|
|
||||||
|
|
||||||
@routine ( a b -- c )
|
|
||||||
|
|
||||||
ADD
|
|
||||||
|
|
||||||
JMP2r
|
|
||||||
|
|
||||||
@absolute
|
|
||||||
&byte $1 &short $2
|
|
|
@ -1,5 +1,9 @@
|
||||||
use std::env::args;
|
use std::env::args;
|
||||||
|
use std::ffi::CStr;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
use std::io::BufRead;
|
||||||
|
use std::io::BufReader;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
use uxn::vm::{Uxn, UxnError};
|
use uxn::vm::{Uxn, UxnError};
|
||||||
|
|
||||||
|
@ -9,19 +13,44 @@ fn main() -> Result<(), std::io::Error> {
|
||||||
let argv: Vec<String> = args().collect();
|
let argv: Vec<String> = args().collect();
|
||||||
|
|
||||||
// Load a bytecode file
|
// Load a bytecode file
|
||||||
let program: File = File::open(&argv[1])?;
|
let f: File = File::open(&argv[1])?;
|
||||||
vm.load_rom(program).unwrap();
|
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
|
// Load a symbol table
|
||||||
if argv.len() > 2 {
|
if argv.len() > 2 {
|
||||||
let symbols: File = File::open(&argv[2])?;
|
let f: File = File::open(&argv[2])?;
|
||||||
vm.load_symbols(symbols)?;
|
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
|
// Execute the VM
|
||||||
loop {
|
loop {
|
||||||
if vm.is_halted() {
|
if vm.is_halted() {
|
||||||
eprintln!("Interpreter is halted");
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +58,7 @@ fn main() -> Result<(), std::io::Error> {
|
||||||
Ok(()) => return Ok(()),
|
Ok(()) => return Ok(()),
|
||||||
|
|
||||||
Err(UxnError::Break) => {
|
Err(UxnError::Break) => {
|
||||||
eprintln!("Interpreter broke");
|
eprintln!("Interpreter broke; continuing...");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Err(UxnError::ExecutionLimit(_)) => continue,
|
Err(UxnError::ExecutionLimit(_)) => continue,
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
use sdl2::event::Event;
|
|
||||||
use sdl2::keyboard::Keycode;
|
|
||||||
use sdl2::pixels::Color;
|
|
||||||
use sdl2::rect::{Point, Rect};
|
|
||||||
use sdl2::render::WindowCanvas;
|
|
||||||
// "self" imports the "image" module itself as well as everything else we listed
|
|
||||||
use std::thread::sleep;
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
fn render(canvas: &mut WindowCanvas, color: Color) -> Result<(), String> {
|
|
||||||
canvas.set_draw_color(color);
|
|
||||||
canvas.clear();
|
|
||||||
|
|
||||||
canvas.set_draw_color(color);
|
|
||||||
// fills the canvas with the color we set in `set_draw_color`.
|
|
||||||
canvas.clear();
|
|
||||||
|
|
||||||
// change the color of our drawing with a gold-color ...
|
|
||||||
canvas.set_draw_color(Color::RGB(255, 210, 0));
|
|
||||||
|
|
||||||
// A draw a rectangle which almost fills our window with it!
|
|
||||||
canvas.fill_rect(Rect::new(10, 10, 780, 580))?;
|
|
||||||
|
|
||||||
canvas.draw_point(Point::new(5, 5))?;
|
|
||||||
|
|
||||||
canvas.present();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> Result<(), String> {
|
|
||||||
let sdl_context = sdl2::init()?;
|
|
||||||
let video_subsystem = sdl_context.video()?;
|
|
||||||
let window = video_subsystem
|
|
||||||
.window("rusty varvara [sdl2]", 800, 600)
|
|
||||||
.position_centered()
|
|
||||||
.build()
|
|
||||||
.expect("could not initialize video subsystem");
|
|
||||||
|
|
||||||
let mut canvas = window
|
|
||||||
.into_canvas()
|
|
||||||
.build()
|
|
||||||
.expect("could not make a canvas");
|
|
||||||
|
|
||||||
let mut event_pump = sdl_context.event_pump()?;
|
|
||||||
let mut i = 0;
|
|
||||||
'running: loop {
|
|
||||||
// Handle events
|
|
||||||
for event in event_pump.poll_iter() {
|
|
||||||
match event {
|
|
||||||
Event::Quit { .. }
|
|
||||||
| Event::KeyDown {
|
|
||||||
keycode: Some(Keycode::Escape),
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
break 'running;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update
|
|
||||||
i = (i + 1) % 255;
|
|
||||||
|
|
||||||
// Render
|
|
||||||
render(&mut canvas, Color::RGB(i, 64, 255 - i))?;
|
|
||||||
|
|
||||||
// Time management!
|
|
||||||
sleep(Duration::new(0, 1_000_000_000u32 / 60));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -1,5 +1,8 @@
|
||||||
use std::env::args;
|
use std::env::args;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
use std::io::BufRead;
|
||||||
|
use std::io::BufReader;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
use uxn::vm::Uxn;
|
use uxn::vm::Uxn;
|
||||||
|
|
||||||
|
@ -7,8 +10,28 @@ fn main() -> Result<(), std::io::Error> {
|
||||||
let mut vm = Uxn::new();
|
let mut vm = Uxn::new();
|
||||||
|
|
||||||
let argv: Vec<String> = args().collect();
|
let argv: Vec<String> = args().collect();
|
||||||
let symbols: File = File::open(&argv[1])?;
|
let f: File = File::open(&argv[1])?;
|
||||||
vm.load_symbols(symbols)?;
|
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();
|
vm.debug_symbols();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -2,7 +2,6 @@ pub mod buff;
|
||||||
pub mod console;
|
pub mod console;
|
||||||
pub mod null;
|
pub mod null;
|
||||||
pub mod system;
|
pub mod system;
|
||||||
pub mod video_sdl2;
|
|
||||||
|
|
||||||
use crate::vm::Uxn;
|
use crate::vm::Uxn;
|
||||||
|
|
||||||
|
@ -19,7 +18,7 @@ pub trait Device: std::fmt::Debug {
|
||||||
fn dei1(&mut self, vm: &mut Uxn, port: u8) -> Result<u8, DeviceError>;
|
fn dei1(&mut self, vm: &mut Uxn, port: u8) -> Result<u8, DeviceError>;
|
||||||
|
|
||||||
fn dei2(&mut self, vm: &mut Uxn, port: u8) -> Result<u16, DeviceError> {
|
fn dei2(&mut self, vm: &mut Uxn, port: u8) -> Result<u16, DeviceError> {
|
||||||
Ok(((self.dei1(vm, port)? as u16) << 8) + self.dei1(vm, port + 1)? as u16)
|
return Ok(((self.dei1(vm, port)? as u16) << 8) + self.dei1(vm, port + 1)? as u16);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -30,7 +30,7 @@ impl Device for BuffDevice {
|
||||||
"Got write to device {:02X} slot {:02X} val {:02X}",
|
"Got write to device {:02X} slot {:02X} val {:02X}",
|
||||||
port, slot, val
|
port, slot, val
|
||||||
);
|
);
|
||||||
self.buffer[slot] = val;
|
self.buffer[slot as usize] = val;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#[allow(unused_imports)]
|
use std::io::{stderr, stdout, Write};
|
||||||
use std::io::{stderr, stdin, stdout, Write};
|
|
||||||
|
|
||||||
use crate::device::{Device, DeviceError};
|
use crate::device::{Device, DeviceError};
|
||||||
use crate::vm::Uxn;
|
use crate::vm::Uxn;
|
||||||
|
@ -17,17 +16,18 @@ use crate::vm::Uxn;
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[allow(dead_code)]
|
|
||||||
pub struct ConsoleDevice {
|
pub struct ConsoleDevice {
|
||||||
vector: u16,
|
vector: u16,
|
||||||
inbuffer: Vec<u8>,
|
inbuffer: [u8; 256],
|
||||||
|
inidx: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConsoleDevice {
|
impl ConsoleDevice {
|
||||||
pub fn new() -> ConsoleDevice {
|
pub fn new() -> ConsoleDevice {
|
||||||
ConsoleDevice {
|
ConsoleDevice {
|
||||||
vector: 0,
|
vector: 0,
|
||||||
inbuffer: Vec::new(),
|
inidx: 255,
|
||||||
|
inbuffer: [0; 256],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ impl Device for ConsoleDevice {
|
||||||
* If inidx < inbuffer.size, we want to return the next character out of the
|
* If inidx < inbuffer.size, we want to return the next character out of the
|
||||||
* inbuffer.
|
* inbuffer.
|
||||||
*/
|
*/
|
||||||
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;
|
let slot = port & 0xF;
|
||||||
match slot {
|
match slot {
|
||||||
0x2 => Ok(0),
|
0x2 => Ok(0),
|
||||||
|
@ -51,7 +51,7 @@ impl Device for ConsoleDevice {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEI2 is not supported on the terminal device
|
// DEI2 is not supported on the terminal device
|
||||||
fn dei2(&mut self, _vm: &mut Uxn, port: u8) -> Result<u16, DeviceError> {
|
fn dei2(&mut self, vm: &mut Uxn, port: u8) -> Result<u16, DeviceError> {
|
||||||
Err(DeviceError::PortTypeError(
|
Err(DeviceError::PortTypeError(
|
||||||
port,
|
port,
|
||||||
"double reads from the console are not supported".into(),
|
"double reads from the console are not supported".into(),
|
||||||
|
@ -88,7 +88,7 @@ impl Device for ConsoleDevice {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
||||||
port,
|
port,
|
||||||
"double writes to the console are not supported".into(),
|
"double writes to the console are not supported".into(),
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::borrow::Borrow;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
@ -64,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!(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,258 +0,0 @@
|
||||||
use std::{cell::RefCell, rc::Rc};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
device::{Device, DeviceError},
|
|
||||||
vm::Uxn,
|
|
||||||
};
|
|
||||||
|
|
||||||
static BLENDING: [[u8; 16]; 5] = [
|
|
||||||
[0, 0, 0, 0, 1, 0, 1, 1, 2, 2, 0, 2, 3, 3, 3, 0],
|
|
||||||
[0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3],
|
|
||||||
[1, 2, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1],
|
|
||||||
[2, 3, 1, 2, 2, 3, 1, 2, 2, 3, 1, 2, 2, 3, 1, 2],
|
|
||||||
[1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0],
|
|
||||||
];
|
|
||||||
|
|
||||||
static PALETTE_MONO: [u32; 2] = [0x0f000000u32, 0x0fffffffu32];
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Layer {
|
|
||||||
pixels: Vec<u8>,
|
|
||||||
changed: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Sdl2VideoDevice {
|
|
||||||
vector: u16,
|
|
||||||
palette: [u32; 4],
|
|
||||||
pixels: Vec<u32>,
|
|
||||||
width: u16,
|
|
||||||
height: u16,
|
|
||||||
fg: Rc<RefCell<Layer>>,
|
|
||||||
bg: Rc<RefCell<Layer>>,
|
|
||||||
mono: bool,
|
|
||||||
|
|
||||||
x_cur: u16, // x8, x9
|
|
||||||
y_cur: u16, // xa, xb
|
|
||||||
auto_x: bool, // x6
|
|
||||||
auto_y: bool, // x6
|
|
||||||
sprite_addr: u16, // xc, xd
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sdl2VideoDevice {
|
|
||||||
fn new() -> Sdl2VideoDevice {
|
|
||||||
unimplemented!();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear(&mut self) {
|
|
||||||
{
|
|
||||||
let mut fg = self.fg.borrow_mut();
|
|
||||||
for i in 0..(self.width * self.height) as usize {
|
|
||||||
fg.pixels[i] = 0x00;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let mut bg = self.bg.borrow_mut();
|
|
||||||
for i in 0..(self.width * self.height) as usize {
|
|
||||||
bg.pixels[i] = 0x00;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update an entry in either the foreground or background buffers, marking the buffer as dirty.
|
|
||||||
*/
|
|
||||||
fn write_pixel(&mut self, layer: bool, x: u16, y: u16, color: u8) {
|
|
||||||
let mut layer = if layer {
|
|
||||||
self.fg.borrow_mut()
|
|
||||||
} else {
|
|
||||||
self.bg.borrow_mut()
|
|
||||||
};
|
|
||||||
if x < self.width && y < self.height {
|
|
||||||
let idx = (x + (y * self.height)) as usize;
|
|
||||||
if color != layer.pixels[idx] {
|
|
||||||
layer.pixels[idx] = color;
|
|
||||||
layer.changed |= true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Roll through the pixels associated with a sprite, calling write_pixel for each one.
|
|
||||||
*
|
|
||||||
* Known as `screen_blit` in the C implementation.
|
|
||||||
*/
|
|
||||||
fn write_sprite(
|
|
||||||
&mut self,
|
|
||||||
layer: bool,
|
|
||||||
x: u16,
|
|
||||||
y: u16,
|
|
||||||
sprite: &[u8],
|
|
||||||
color: u8,
|
|
||||||
flipx: bool,
|
|
||||||
flipy: bool,
|
|
||||||
twobpp: bool,
|
|
||||||
) {
|
|
||||||
let v = BLENDING[4][color as usize];
|
|
||||||
let _h = v;
|
|
||||||
let opaque = v;
|
|
||||||
for v in 0..8 {
|
|
||||||
let mut c: u8 = sprite[v] | (if twobpp { sprite[v + 8] } else { 0 }) << 8;
|
|
||||||
|
|
||||||
for h in 7..0 {
|
|
||||||
c >>= 1;
|
|
||||||
let ch = ((c & 1) | ((c >> 7) & 2)) as usize;
|
|
||||||
if opaque != 0 || ch != 0 {
|
|
||||||
self.write_pixel(
|
|
||||||
layer,
|
|
||||||
x + (if flipx { 7 - h } else { h }) as u16,
|
|
||||||
y + (if flipy { 7 - v } else { v }) as u16,
|
|
||||||
BLENDING[ch][color as usize],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compute a partial form of the palette.
|
|
||||||
* Note that redraw() does its own final palette computation.
|
|
||||||
* Not clear what parts of that live where why.
|
|
||||||
*/
|
|
||||||
fn set_palette(&mut self, colors: [u8; 6]) {
|
|
||||||
// TODO: What in the everliving fuck is this doing.
|
|
||||||
// Works in C's *u8 land, not clear it works in Rust.
|
|
||||||
let mut shift = 4;
|
|
||||||
for i in 0..4 {
|
|
||||||
let r = (colors[i / 2] >> shift) & 0x0f;
|
|
||||||
let g = (colors[2 + i / 2] >> shift) & 0x0f;
|
|
||||||
let b = (colors[4 + i / 2] >> shift) & 0x0f;
|
|
||||||
|
|
||||||
self.palette[i] = 0x0f000000u32 | (r as u32) << 16 | (g as u32) << 8 | b as u32;
|
|
||||||
self.palette[i] |= self.palette[i] << 4;
|
|
||||||
|
|
||||||
shift ^= 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Both layers are now dirty
|
|
||||||
self.fg.borrow_mut().changed |= true;
|
|
||||||
self.bg.borrow_mut().changed |= true;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn redraw(&mut self) {
|
|
||||||
let size = self.width * self.height;
|
|
||||||
let mut palette = [0u32; 16];
|
|
||||||
for i in 0..16 {
|
|
||||||
let idx = if (i >> 2) != 0 { i >> 2 } else { i & 3 };
|
|
||||||
palette[i] = self.palette[idx];
|
|
||||||
}
|
|
||||||
if self.mono {
|
|
||||||
for i in 0..size as usize {
|
|
||||||
let idx = (if self.fg.borrow().pixels[i] != 0 {
|
|
||||||
self.fg.borrow().pixels[i]
|
|
||||||
} else {
|
|
||||||
self.bg.borrow().pixels[i]
|
|
||||||
}) & 0x1;
|
|
||||||
self.pixels[i] = PALETTE_MONO[idx as usize];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for i in 0..size as usize {
|
|
||||||
self.pixels[i] = palette
|
|
||||||
[(self.fg.borrow().pixels[i] << 2 | self.bg.borrow().pixels[i]) as usize];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.fg.borrow_mut().changed = false;
|
|
||||||
self.bg.borrow_mut().changed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resize(&mut self) {
|
|
||||||
()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn auto_increment(&mut self, d: u8) {
|
|
||||||
if self.auto_x {
|
|
||||||
self.x_cur += d as u16;
|
|
||||||
}
|
|
||||||
if self.auto_y {
|
|
||||||
self.y_cur += d as u16;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Device for Sdl2VideoDevice {
|
|
||||||
fn dei1(&mut self, _vm: &mut Uxn, port: u8) -> Result<u8, DeviceError> {
|
|
||||||
let slot = port & 0xF;
|
|
||||||
// FIXME: this is sorta copypasta, but LOTS of source byte order assumptions here.
|
|
||||||
match slot {
|
|
||||||
0x0 => Ok((self.vector >> 8) as u8),
|
|
||||||
0x1 => Ok((self.vector & 0xFF) as u8),
|
|
||||||
|
|
||||||
0x2 => Ok((self.width >> 8) as u8),
|
|
||||||
0x3 => Ok((self.width & 0xFF) as u8),
|
|
||||||
|
|
||||||
0x4 => Ok((self.height >> 8) as u8),
|
|
||||||
0x5 => Ok((self.height & 0xFF) as u8),
|
|
||||||
|
|
||||||
0x6 => Ok((if self.auto_y { 1 } else { 0 }) << 1 | (if self.auto_x { 1 } else { 0 })),
|
|
||||||
|
|
||||||
0x8 => Ok((self.x_cur >> 8) as u8),
|
|
||||||
0x9 => Ok((self.x_cur & 0xFF) as u8),
|
|
||||||
|
|
||||||
0xa => Ok((self.y_cur >> 8) as u8),
|
|
||||||
0xb => Ok((self.y_cur & 0xFF) as u8),
|
|
||||||
|
|
||||||
_ => Ok(0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback used by UXN to do output through a "device".
|
|
||||||
*/
|
|
||||||
fn deo1(&mut self, _vm: &mut Uxn, port: u8, val: u8) -> Result<(), DeviceError> {
|
|
||||||
let slot = port & 0xF;
|
|
||||||
match slot {
|
|
||||||
// Writing to the device vector
|
|
||||||
0x0 => self.vector = self.vector & 0x00FF | ((val as u16) << 8),
|
|
||||||
0x1 => self.vector = self.vector & 0xFF00 | (val as u16),
|
|
||||||
// Writing to the device width port.
|
|
||||||
// Note that the reference implementation triggers resizing on the lower byte
|
|
||||||
0x2 => self.width = self.width & 0x00FF | ((val as u16) << 8),
|
|
||||||
0x3 => {
|
|
||||||
self.width = self.width & 0xFF00 | (val as u16);
|
|
||||||
self.resize();
|
|
||||||
}
|
|
||||||
// Writing to the device height port
|
|
||||||
// Note that the reference implementation triggers resizing on the lower byte
|
|
||||||
0x4 => self.height = self.height & 0x00FF | ((val as u16) << 8),
|
|
||||||
0x5 => {
|
|
||||||
self.height = self.height & 0xFF00 | (val as u16);
|
|
||||||
self.resize();
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Writing to all the settings words (auto, x, y, addr)
|
|
||||||
|
|
||||||
// Write the auto word
|
|
||||||
0x6 => {
|
|
||||||
self.auto_x = val & 0x1 != 0;
|
|
||||||
self.auto_y = val & 0x2 != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write a pixel word
|
|
||||||
0xe => {
|
|
||||||
let layer = val & 0x40 != 0;
|
|
||||||
self.write_pixel(layer, self.x_cur, self.y_cur, val & 0x3);
|
|
||||||
self.auto_increment(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write a sprite word
|
|
||||||
0xf => {
|
|
||||||
let layer = val & 0x40 != 0;
|
|
||||||
let n = val & 0xF >> 4;
|
|
||||||
self.auto_increment(8); // sprites are always 8x8, although we may do many at once.
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
84
src/isa.rs
84
src/isa.rs
|
@ -4,16 +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 = 0b10000000; // AKA keep Yes really. Per spec;
|
||||||
// LIT is BRK + flags
|
pub const LIT2: u8 = 0b10100000; // AKA keep Yes really. Per spec;
|
||||||
pub const LIT: u8 = 0x80; // AKA keep Yes really. Per spec;
|
|
||||||
pub const LIT2: u8 = 0xa0; // AKA keep Yes really. Per spec;
|
|
||||||
|
|
||||||
// Jump-immediate extensions (again BRK + flags)
|
|
||||||
pub const JMI: u8 = 0x20; // Jump [to] immediate
|
|
||||||
pub const JCI: u8 = 0x40; // Jump Conditional Immediate
|
|
||||||
pub const JSI: u8 = 0x60; // Jump Storing Immediate (call)
|
|
||||||
|
|
||||||
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;
|
||||||
|
@ -71,45 +63,41 @@ impl Icode {
|
||||||
pub const fn nameof(opcode: u8) -> &'static str {
|
pub const fn nameof(opcode: u8) -> &'static str {
|
||||||
match opcode {
|
match opcode {
|
||||||
// Nonstandard icodes + extensions
|
// Nonstandard icodes + extensions
|
||||||
Icode::LIT | Icode::LIT2 => "LIT", // AKA keep. Yes really. Per spec,
|
Icode::LIT | Icode::LIT2 => &"LIT", // AKA keep Yes really. Per spec,
|
||||||
Icode::NOP => "NOP",
|
Icode::NOP => &"NOP",
|
||||||
// Standard icodes
|
// Standard icodes
|
||||||
Icode::BRK => "BRK",
|
Icode::BRK => &"BRK",
|
||||||
Icode::INC => "INC",
|
Icode::INC => &"INC",
|
||||||
Icode::POP => "POP",
|
Icode::POP => &"POP",
|
||||||
Icode::NIP => "NIP",
|
Icode::NIP => &"NIP",
|
||||||
Icode::SWP => "SWP",
|
Icode::SWP => &"SWP",
|
||||||
Icode::ROT => "ROT",
|
Icode::ROT => &"ROT",
|
||||||
Icode::DUP => "DUP",
|
Icode::DUP => &"DUP",
|
||||||
Icode::OVR => "OVR",
|
Icode::OVR => &"OVR",
|
||||||
Icode::EQL => "EQL",
|
Icode::EQL => &"EQL",
|
||||||
Icode::NEQ => "NEQ",
|
Icode::NEQ => &"NEQ",
|
||||||
Icode::GTH => "GTH",
|
Icode::GTH => &"GTH",
|
||||||
Icode::LTH => "LTH",
|
Icode::LTH => &"LTH",
|
||||||
Icode::JMP => "JMP",
|
Icode::JMP => &"JMP",
|
||||||
Icode::JCN => "JNC",
|
Icode::JCN => &"JNC",
|
||||||
Icode::JSR => "JSR",
|
Icode::JSR => &"JSR",
|
||||||
Icode::STH => "STH",
|
Icode::STH => &"STH",
|
||||||
Icode::LDZ => "LDZ",
|
Icode::LDZ => &"LDZ",
|
||||||
Icode::STZ => "STZ",
|
Icode::STZ => &"STZ",
|
||||||
Icode::LDR => "LDR",
|
Icode::LDR => &"LDR",
|
||||||
Icode::STR => "STR",
|
Icode::STR => &"STR",
|
||||||
Icode::LDA => "LDA",
|
Icode::LDA => &"LDA",
|
||||||
Icode::STA => "STA",
|
Icode::STA => &"STA",
|
||||||
Icode::DEI => "DEI",
|
Icode::DEI => &"DEI",
|
||||||
Icode::DEO => "DEO",
|
Icode::DEO => &"DEO",
|
||||||
Icode::ADD => "ADD",
|
Icode::ADD => &"ADD",
|
||||||
Icode::SUB => "SUB",
|
Icode::SUB => &"SUB",
|
||||||
Icode::MUL => "MUL",
|
Icode::MUL => &"MUL",
|
||||||
Icode::DIV => "DIV",
|
Icode::DIV => &"DIV",
|
||||||
Icode::AND => "AND",
|
Icode::AND => &"AND",
|
||||||
Icode::ORA => "ORA",
|
Icode::ORA => &"ORA",
|
||||||
Icode::EOR => "EOR",
|
Icode::EOR => &"EOR",
|
||||||
Icode::SFT => "SFT",
|
Icode::SFT => &"SFT",
|
||||||
// Jump immediate extension
|
|
||||||
Icode::JMI => "JMI",
|
|
||||||
Icode::JCI => "JCI",
|
|
||||||
Icode::JSI => "JSI",
|
|
||||||
_ => Icode::nameof(opcode & 0x1F),
|
_ => 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;
|
||||||
|
|
|
@ -34,15 +34,15 @@ impl TrivialMemory {
|
||||||
|
|
||||||
impl Memory for TrivialMemory {
|
impl Memory for TrivialMemory {
|
||||||
fn get1(&self, address: u16) -> Result<u8, MemoryError> {
|
fn get1(&self, address: u16) -> Result<u8, MemoryError> {
|
||||||
Ok(self.buffer[address as usize])
|
return Ok(self.buffer[address as usize]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get2(&self, address: u16) -> Result<u16, MemoryError> {
|
fn get2(&self, address: u16) -> Result<u16, MemoryError> {
|
||||||
if address == 0xFFFFu16 {
|
if address == 0xFFFFu16 {
|
||||||
Err(MemoryError::AddressOverflow)
|
Err(MemoryError::AddressOverflow)
|
||||||
} else {
|
} else {
|
||||||
Ok(((self.buffer[address as usize] as u16) << 8)
|
return Ok(((self.buffer[address as usize] as u16) << 8)
|
||||||
+ self.buffer[address as usize + 1] as u16)
|
+ self.buffer[address as usize + 1] as u16);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ impl ArrayStack {
|
||||||
|
|
||||||
impl Stack for ArrayStack {
|
impl Stack for ArrayStack {
|
||||||
fn idx(&self) -> u8 {
|
fn idx(&self) -> u8 {
|
||||||
self._idx
|
return self._idx;
|
||||||
}
|
}
|
||||||
fn push1(&mut self, val: u8) -> Result<(), StackError> {
|
fn push1(&mut self, val: u8) -> Result<(), StackError> {
|
||||||
if self._idx == 255 {
|
if self._idx == 255 {
|
||||||
|
@ -182,7 +182,7 @@ mod arrs_test {
|
||||||
for i in val.clone().into_iter() {
|
for i in val.clone().into_iter() {
|
||||||
s.push1(i).unwrap();
|
s.push1(i).unwrap();
|
||||||
};
|
};
|
||||||
for i in val.into_iter().rev() {
|
for i in val.clone().into_iter().rev() {
|
||||||
match s.pop1() {
|
match s.pop1() {
|
||||||
Ok(j) => if i != j { return false }
|
Ok(j) => if i != j { return false }
|
||||||
Err(e) => panic!("{:?}", e)
|
Err(e) => panic!("{:?}", e)
|
||||||
|
@ -214,7 +214,7 @@ mod arrs_test {
|
||||||
for i in val.clone().into_iter() {
|
for i in val.clone().into_iter() {
|
||||||
s.push2(i).unwrap();
|
s.push2(i).unwrap();
|
||||||
};
|
};
|
||||||
for i in val.into_iter().rev() {
|
for i in val.clone().into_iter().rev() {
|
||||||
match s.pop2() {
|
match s.pop2() {
|
||||||
Ok(j) => if i != j { return false }
|
Ok(j) => if i != j { return false }
|
||||||
Err(e) => panic!("{:?}", e)
|
Err(e) => panic!("{:?}", e)
|
||||||
|
|
|
@ -28,7 +28,7 @@ impl PopStack {
|
||||||
|
|
||||||
impl Stack for PopStack {
|
impl Stack for PopStack {
|
||||||
fn idx(&self) -> u8 {
|
fn idx(&self) -> u8 {
|
||||||
self._idx
|
return self._idx;
|
||||||
}
|
}
|
||||||
fn push1(&mut self, val: u8) -> Result<(), StackError> {
|
fn push1(&mut self, val: u8) -> Result<(), StackError> {
|
||||||
self.wrapped.borrow_mut().push1(val)
|
self.wrapped.borrow_mut().push1(val)
|
||||||
|
|
192
src/vm.rs
192
src/vm.rs
|
@ -1,11 +1,6 @@
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ffi::CStr;
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io::BufRead;
|
|
||||||
use std::io::BufReader;
|
|
||||||
use std::io::Read;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::*;
|
use std::*;
|
||||||
|
|
||||||
|
@ -103,82 +98,32 @@ impl Uxn {
|
||||||
vm
|
vm
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_rom(&mut self, file: File) -> Result<(), UxnError> {
|
|
||||||
let reader = BufReader::new(file);
|
|
||||||
|
|
||||||
let mut i = 0x0100u16;
|
|
||||||
for b in reader.bytes() {
|
|
||||||
self.sta1(i, b.unwrap())?;
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_symbols(&mut self, file: File) -> Result<(), io::Error> {
|
|
||||||
let mut reader: BufReader<File> = BufReader::new(file);
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
self.symbols.insert(addr, label);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_halted(&mut self) -> bool {
|
pub fn is_halted(&mut self) -> bool {
|
||||||
self.dei1(0x0f).unwrap() != 0
|
self.dei1(0x0f).unwrap() != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_tracing(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn debug(&mut self) {
|
pub fn debug(&mut self) {
|
||||||
let wst = self.wst.clone();
|
let wst = self.wst.clone();
|
||||||
let rst = self.rst.clone();
|
let rst = self.rst.clone();
|
||||||
|
|
||||||
print!(
|
eprint!(
|
||||||
"<symbols> #{:04X}\n<clock> #{:04X}\n<pc> #{:04X}\n<data stack>",
|
"<clock> #{:04X}\n<pc> #{:04X}\n<data stack>",
|
||||||
self.symbols.len(),
|
self.clock, self.pc
|
||||||
self.clock,
|
|
||||||
self.pc
|
|
||||||
);
|
);
|
||||||
let wst_idx = wst.borrow_mut().idx();
|
let wst_idx = wst.borrow_mut().idx();
|
||||||
if wst_idx != 0 {
|
for i in 0..wst_idx {
|
||||||
for i in 0..wst_idx {
|
eprint!(" #{:02X}", self.wst.borrow_mut().get1(i).unwrap());
|
||||||
print!(" #{:02X}", self.wst.borrow_mut().get1(i).unwrap());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
print!(" empty")
|
|
||||||
}
|
}
|
||||||
print!("\n<return stack>");
|
eprint!("\n<return stack>");
|
||||||
let rst_idx = rst.borrow_mut().idx();
|
let rst_idx = rst.borrow_mut().idx();
|
||||||
if rst_idx != 0 {
|
for i in 0..rst_idx {
|
||||||
for i in 0..rst_idx {
|
eprint!(" #{:02X}", self.rst.borrow_mut().get1(i).unwrap());
|
||||||
print!(" #{:02X}", self.rst.borrow_mut().get1(i).unwrap());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
print!(" empty")
|
|
||||||
}
|
}
|
||||||
println!();
|
eprint!("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debug_symbols(&self) {
|
pub fn debug_symbols(&self) {
|
||||||
for (k, v) in self.symbols.borrow().iter() {
|
for (k, v) in self.symbols.borrow().into_iter() {
|
||||||
println!(" #{:02X} {}", k, v);
|
println!(" #{:02X} {}", k, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,65 +150,31 @@ impl Uxn {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sta1(&mut self, address: u16, val: u8) -> Result<(), MemoryError> {
|
pub fn sta1(&mut self, address: u16, val: u8) -> Result<(), MemoryError> {
|
||||||
if self.is_tracing() {
|
|
||||||
eprintln!(
|
|
||||||
" STA #{:04X} ({}) <- #{:02X}",
|
|
||||||
address,
|
|
||||||
self.symbols.get(&address).unwrap_or(&"".to_string()),
|
|
||||||
val
|
|
||||||
)
|
|
||||||
}
|
|
||||||
self.memory.clone().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> {
|
||||||
if self.is_tracing() {
|
|
||||||
eprintln!(
|
|
||||||
" STA #{:04X} ({}) <- #{:04X}",
|
|
||||||
address,
|
|
||||||
self.symbols.get(&address).unwrap_or(&"".to_string()),
|
|
||||||
val
|
|
||||||
)
|
|
||||||
}
|
|
||||||
self.memory.clone().borrow_mut().set2(address, val)?;
|
self.memory.clone().borrow_mut().set2(address, val)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lda1(&self, address: u16) -> Result<u8, MemoryError> {
|
pub fn lda1(&mut self, address: u16) -> Result<u8, MemoryError> {
|
||||||
if address != self.pc && self.is_tracing() {
|
|
||||||
eprintln!(
|
|
||||||
" LDA #{:04X} ({})",
|
|
||||||
address,
|
|
||||||
self.symbols.get(&address).unwrap_or(&"".to_string()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
self.memory.clone().borrow_mut().get1(address)
|
self.memory.clone().borrow_mut().get1(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lda2(&self, address: u16) -> Result<u16, MemoryError> {
|
pub fn lda2(&mut self, address: u16) -> Result<u16, MemoryError> {
|
||||||
if address != self.pc && self.is_tracing() {
|
|
||||||
eprintln!(
|
|
||||||
" LDA #{:04X} ({})",
|
|
||||||
address,
|
|
||||||
self.symbols.get(&address).unwrap_or(&"".to_string()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
self.memory.clone().borrow_mut().get2(address)
|
self.memory.clone().borrow_mut().get2(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn branch(&mut self, address: u16) {
|
pub fn branch(&mut self, address: u16) {
|
||||||
match self.symbols.get(&address) {
|
match self.symbols.get(&address) {
|
||||||
Some(label) => {
|
Some(label) => eprintln!(
|
||||||
if self.is_tracing() {
|
"Branch #{:04X} to {} (#{:04X})",
|
||||||
eprintln!(
|
self.pc - 1,
|
||||||
"Branch #{:04X} to {} (#{:04X})",
|
label,
|
||||||
self.pc - 1,
|
address
|
||||||
label,
|
),
|
||||||
address
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => (),
|
None => (),
|
||||||
}
|
}
|
||||||
self.pc = address;
|
self.pc = address;
|
||||||
|
@ -275,11 +186,7 @@ impl Uxn {
|
||||||
Err(e) => Err(UxnError::MemoryError(e)),
|
Err(e) => Err(UxnError::MemoryError(e)),
|
||||||
Ok(icode) => {
|
Ok(icode) => {
|
||||||
match self.symbols.get(&self.pc) {
|
match self.symbols.get(&self.pc) {
|
||||||
Some(sym) => {
|
Some(sym) => eprintln!("{}:", sym),
|
||||||
if self.is_tracing() {
|
|
||||||
eprintln!("{}:", sym)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => (),
|
None => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,19 +202,17 @@ impl Uxn {
|
||||||
// Extract flags
|
// Extract flags
|
||||||
let (kflag, rflag, sflag, icode5) = Icode::parse(icode);
|
let (kflag, rflag, sflag, icode5) = Icode::parse(icode);
|
||||||
|
|
||||||
if self.is_tracing() {
|
eprintln!(
|
||||||
eprintln!(
|
" cycle #{:04X}; pc #{:04X}, rom pc: #{:04X}: {} ( {:05b} s: {:1x} r: {:1x} k: {:1x} )",
|
||||||
" cycle #{:04X}; pc #{:04X}, rom pc: #{:04X}: {} ( {:05b} s: {:1x} r: {:1x} k: {:1x} )",
|
self.clock,
|
||||||
self.clock,
|
self.pc - 1,
|
||||||
self.pc - 1,
|
self.pc - 0x0101,
|
||||||
self.pc - 0x0101,
|
Icode::nameof(icode),
|
||||||
Icode::nameof(icode),
|
icode5,
|
||||||
icode5,
|
sflag,
|
||||||
sflag,
|
rflag,
|
||||||
rflag,
|
kflag
|
||||||
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] = {
|
||||||
|
@ -349,18 +254,17 @@ impl Uxn {
|
||||||
|
|
||||||
let load = |addr: u16| -> Result<u16, MemoryError> {
|
let load = |addr: u16| -> Result<u16, MemoryError> {
|
||||||
if sflag == 1 {
|
if sflag == 1 {
|
||||||
self.lda2(addr)
|
self.memory.borrow_mut().get2(addr)
|
||||||
} else {
|
} else {
|
||||||
Ok(self.lda1(addr)? as u16)
|
Ok(self.memory.borrow_mut().get1(addr)? as u16)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: Can't use self.sta1/sta2 due to *self reference uniqueness
|
let store = |addr: u16, value: u16| {
|
||||||
let store = |this: &mut Uxn, addr: u16, val: u16| {
|
|
||||||
if sflag == 1 {
|
if sflag == 1 {
|
||||||
this.sta2(addr, val)
|
self.memory.borrow_mut().set2(addr, value)
|
||||||
} else {
|
} else {
|
||||||
this.sta1(addr, val as u8)
|
self.memory.borrow_mut().set1(addr, value as u8)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -372,6 +276,11 @@ impl Uxn {
|
||||||
(1, _, _, Icode::BRK) => {
|
(1, _, _, Icode::BRK) => {
|
||||||
// BRKk aka LIT -- a
|
// BRKk aka LIT -- a
|
||||||
let val = load(self.pc)?;
|
let val = load(self.pc)?;
|
||||||
|
if sflag == 0 {
|
||||||
|
eprintln!(" LIT #{:02X}", val);
|
||||||
|
} else {
|
||||||
|
eprintln!(" LIT #{:04X}", val);
|
||||||
|
}
|
||||||
push(wst.clone(), val)?;
|
push(wst.clone(), val)?;
|
||||||
self.branch(self.pc + if sflag == 1 { 2 } else { 1 });
|
self.branch(self.pc + if sflag == 1 { 2 } else { 1 });
|
||||||
}
|
}
|
||||||
|
@ -492,7 +401,7 @@ impl Uxn {
|
||||||
(_, _, _, Icode::STZ) => {
|
(_, _, _, 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(self, addr, pop(wst.clone())?)?;
|
store(addr, pop(wst.clone())?)?;
|
||||||
}
|
}
|
||||||
(_, _, _, Icode::LDR) => {
|
(_, _, _, Icode::LDR) => {
|
||||||
// LDR addr8 -- a8
|
// LDR addr8 -- a8
|
||||||
|
@ -502,9 +411,9 @@ impl Uxn {
|
||||||
}
|
}
|
||||||
(_, _, _, Icode::STR) => {
|
(_, _, _, Icode::STR) => {
|
||||||
// STR val addr8 --
|
// STR val addr8 --
|
||||||
let delta = wst.borrow_mut().pop1()? as i8;
|
let delta = wst.borrow_mut().pop1()?;
|
||||||
let addr = self.pc.wrapping_add(delta as u16);
|
let addr = self.pc.wrapping_add(delta as u16);
|
||||||
store(self, addr, pop(wst)?)?;
|
store(addr, pop(wst)?)?;
|
||||||
}
|
}
|
||||||
(_, _, _, Icode::LDA) => {
|
(_, _, _, Icode::LDA) => {
|
||||||
// LDA a16
|
// LDA a16
|
||||||
|
@ -514,24 +423,27 @@ impl Uxn {
|
||||||
(_, _, _, Icode::STA) => {
|
(_, _, _, Icode::STA) => {
|
||||||
// STA val a16 --
|
// STA val a16 --
|
||||||
let addr = wst.borrow_mut().pop2()?;
|
let addr = wst.borrow_mut().pop2()?;
|
||||||
store(self, addr, pop(wst.clone())?)?;
|
store(addr, pop(wst.clone())?)?;
|
||||||
}
|
}
|
||||||
(_, _, 0, Icode::DEI) => {
|
(_, _, 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()?;
|
||||||
|
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) => {
|
||||||
// DEO1 a8 port8 --
|
// DEO1 a8 port8 --
|
||||||
let port = wst.borrow_mut().pop1()?;
|
let mut wst = wst.borrow_mut();
|
||||||
let val = wst.borrow_mut().pop1()?;
|
let port = wst.pop1()?;
|
||||||
|
let val = wst.pop1()?;
|
||||||
self.deo1(port, val).unwrap();
|
self.deo1(port, val).unwrap();
|
||||||
}
|
}
|
||||||
(_, _, 1, Icode::DEO) => {
|
(_, _, 1, Icode::DEO) => {
|
||||||
|
@ -561,8 +473,10 @@ impl Uxn {
|
||||||
}
|
}
|
||||||
(_, _, _, 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) => {
|
||||||
|
@ -590,9 +504,7 @@ impl Uxn {
|
||||||
let a = pop(wst.clone())?;
|
let a = pop(wst.clone())?;
|
||||||
push(wst.clone(), (a >> right) << left)?;
|
push(wst.clone(), (a >> right) << left)?;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => unreachable!(),
|
||||||
panic!("Unsupported opcode {}", Icode::nameof(icode))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
use std::fs::File;
|
|
||||||
|
|
||||||
use uxn::vm::*;
|
|
||||||
|
|
||||||
macro_rules! test_case {
|
|
||||||
($fname:expr) => {
|
|
||||||
concat!(env!("CARGO_MANIFEST_DIR"), "/resources/test/", $fname) // assumes Linux ('/')!
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn reference_tests() {
|
|
||||||
let mut vm = Uxn::new();
|
|
||||||
let progf = File::open(test_case!("tests.rom")).unwrap();
|
|
||||||
vm.load_rom(progf).unwrap();
|
|
||||||
let symf = File::open(test_case!("tests.rom.sym")).unwrap();
|
|
||||||
vm.load_symbols(symf).unwrap();
|
|
||||||
assert_eq!(vm.run(0xFFFF), Err(UxnError::Break));
|
|
||||||
assert_ne!(vm.dei2(0x0000).unwrap(), 0xFFFF);
|
|
||||||
}
|
|
|
@ -727,7 +727,7 @@ fn test_dei() {
|
||||||
Icode::BRK,
|
Icode::BRK,
|
||||||
]);
|
]);
|
||||||
let dev = Rc::new(RefCell::new(BuffDevice::new()));
|
let dev = Rc::new(RefCell::new(BuffDevice::new()));
|
||||||
vm.devices[3] = dev;
|
vm.devices[3] = dev.clone();
|
||||||
vm.deo1(0x30, 0xFF).unwrap();
|
vm.deo1(0x30, 0xFF).unwrap();
|
||||||
}
|
}
|
||||||
assert_eq!(vm.run(64), Err(UxnError::Break));
|
assert_eq!(vm.run(64), Err(UxnError::Break));
|
||||||
|
@ -744,7 +744,7 @@ fn test_dei2() {
|
||||||
Icode::BRK,
|
Icode::BRK,
|
||||||
]);
|
]);
|
||||||
let dev = Rc::new(RefCell::new(BuffDevice::new()));
|
let dev = Rc::new(RefCell::new(BuffDevice::new()));
|
||||||
vm.devices[3] = dev;
|
vm.devices[3] = dev.clone();
|
||||||
vm.deo2(0x30, 0xFFEE).unwrap();
|
vm.deo2(0x30, 0xFFEE).unwrap();
|
||||||
}
|
}
|
||||||
assert_eq!(vm.run(64), Err(UxnError::Break));
|
assert_eq!(vm.run(64), Err(UxnError::Break));
|
||||||
|
@ -759,7 +759,7 @@ fn test_deo() {
|
||||||
Icode::LIT | Icode::SHORT, 0xFF, 0x30, Icode::DEO, Icode::BRK,
|
Icode::LIT | Icode::SHORT, 0xFF, 0x30, Icode::DEO, Icode::BRK,
|
||||||
]);
|
]);
|
||||||
let dev = Rc::new(RefCell::new(BuffDevice::new()));
|
let dev = Rc::new(RefCell::new(BuffDevice::new()));
|
||||||
vm.devices[3] = dev;
|
vm.devices[3] = dev.clone();
|
||||||
}
|
}
|
||||||
assert_eq!(vm.run(64), Err(UxnError::Break));
|
assert_eq!(vm.run(64), Err(UxnError::Break));
|
||||||
assert_eq!(vm.wst.borrow().idx(), 0);
|
assert_eq!(vm.wst.borrow().idx(), 0);
|
||||||
|
@ -776,7 +776,7 @@ fn test_deo2() {
|
||||||
Icode::BRK,
|
Icode::BRK,
|
||||||
]);
|
]);
|
||||||
let dev = Rc::new(RefCell::new(BuffDevice::new()));
|
let dev = Rc::new(RefCell::new(BuffDevice::new()));
|
||||||
vm.devices[3] = dev;
|
vm.devices[3] = dev.clone();
|
||||||
}
|
}
|
||||||
assert_eq!(vm.run(64), Err(UxnError::Break));
|
assert_eq!(vm.run(64), Err(UxnError::Break));
|
||||||
assert_eq!(vm.wst.borrow().idx(), 0);
|
assert_eq!(vm.wst.borrow().idx(), 0);
|
||||||
|
|
Loading…
Reference in a new issue