From 9b21b663f4936f86b806a88c16d464ea6a41a503 Mon Sep 17 00:00:00 2001 From: ry755 Date: Wed, 26 Jan 2022 22:21:21 -0800 Subject: [PATCH] Initial commit I should've made a git repo for this much sooner, oops :p --- Cargo.lock | 1881 ++++++++++++++++++++++++++++++++ Cargo.toml | 14 + encoding.md | 46 + src/cpu.rs | 2953 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 421 +++++++ src/mouse.rs | 14 + 6 files changed, 5329 insertions(+) create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 encoding.md create mode 100644 src/cpu.rs create mode 100644 src/main.rs create mode 100644 src/mouse.rs diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..461eeca --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1881 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" + +[[package]] +name = "alsa" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75c4da790adcb2ce5e758c064b4f3ec17a30349f9961d3e5e6c9688b052a9e18" +dependencies = [ + "alsa-sys", + "bitflags", + "libc", + "nix 0.20.0", +] + +[[package]] +name = "alsa-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "arrayvec" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4dc07131ffa69b8072d35f5007352af944213cde02545e2103680baed38fcd" + +[[package]] +name = "ash" +version = "0.34.0+1.2.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0f780da53d0063880d45554306489f09dd8d1bda47688b4a57bc579119356df" +dependencies = [ + "libloading", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bindgen" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2da379dbebc0b76ef63ca68d8fc6e71c0f13e59432e0987e508c1820e6ab5239" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", +] + +[[package]] +name = "bit-set" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "bumpalo" +version = "3.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" + +[[package]] +name = "bytemuck" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "calloop" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf2eec61efe56aa1e813f5126959296933cf0700030e4314786c48779a66ab82" +dependencies = [ + "log", + "nix 0.22.0", +] + +[[package]] +name = "cc" +version = "1.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cexpr" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" +dependencies = [ + "nom 5.1.2", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "clang-sys" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa66045b9cb23c2e9c1520732030608b02ee07e5cfaa5a521ec15ded7fa24c90" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "claxon" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bfbf56724aa9eca8afa4fcfadeb479e722935bb2a0900c2d37e0cc477af0688" + +[[package]] +name = "cocoa" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63902e9223530efb4e26ccd0cf55ec30d592d3b42e21a28defc42a9586e832" +dependencies = [ + "bitflags", + "block", + "cocoa-foundation", + "core-foundation 0.9.2", + "core-graphics 0.22.2", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" +dependencies = [ + "bitflags", + "block", + "core-foundation 0.9.2", + "core-graphics-types", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "combine" +version = "4.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b2f5d0ee456f3928812dfc8c6d9a1d592b98678f6d56db9b0cd2b7bc6c8db5" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "copyless" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2df960f5d869b2dd8532793fde43eb5427cceb126c929747a26823ab0eeb536" + +[[package]] +name = "core-foundation" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" +dependencies = [ + "core-foundation-sys 0.7.0", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" +dependencies = [ + "core-foundation-sys 0.8.3", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "core-graphics" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923" +dependencies = [ + "bitflags", + "core-foundation 0.7.0", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "269f35f69b542b80e736a20a89a05215c0ce80c2c03c514abb2e318b78379d86" +dependencies = [ + "bitflags", + "core-foundation 0.9.2", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +dependencies = [ + "bitflags", + "core-foundation 0.9.2", + "foreign-types", + "libc", +] + +[[package]] +name = "core-video-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ecad23610ad9757664d644e369246edde1803fcb43ed72876565098a5d3828" +dependencies = [ + "cfg-if 0.1.10", + "core-foundation-sys 0.7.0", + "core-graphics 0.19.2", + "libc", + "objc", +] + +[[package]] +name = "coreaudio-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11894b20ebfe1ff903cbdc52259693389eea03b94918a2def2c30c3bf227ad88" +dependencies = [ + "bitflags", + "coreaudio-sys", +] + +[[package]] +name = "coreaudio-sys" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b7e3347be6a09b46aba228d6608386739fb70beff4f61e07422da87b0bb31fa" +dependencies = [ + "bindgen", +] + +[[package]] +name = "cpal" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98f45f0a21f617cd2c788889ef710b63f075c949259593ea09c826f1e47a2418" +dependencies = [ + "alsa", + "core-foundation-sys 0.8.3", + "coreaudio-rs", + "jni", + "js-sys", + "lazy_static", + "libc", + "mach", + "ndk 0.3.0", + "ndk-glue 0.3.0", + "nix 0.20.0", + "oboe", + "parking_lot", + "stdweb", + "thiserror", + "web-sys", + "winapi", +] + +[[package]] +name = "cty" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" + +[[package]] +name = "d3d12" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2daefd788d1e96e0a9d66dee4b828b883509bc3ea9ce30665f04c3246372690c" +dependencies = [ + "bitflags", + "libloading", + "winapi", +] + +[[package]] +name = "darling" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +dependencies = [ + "darling_core 0.10.2", + "darling_macro 0.10.2", +] + +[[package]] +name = "darling" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d720b8683f8dd83c65155f0530560cba68cd2bf395f6513a483caee57ff7f4" +dependencies = [ + "darling_core 0.13.1", + "darling_macro 0.13.1", +] + +[[package]] +name = "darling_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.9.3", + "syn", +] + +[[package]] +name = "darling_core" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a340f241d2ceed1deb47ae36c4144b2707ec7dd0b649f894cb39bb595986324" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +dependencies = [ + "darling_core 0.10.2", + "quote", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c41b3b7352feb3211a0d743dc5700a4e3b60f51bd2b368892d1e0f9a95f44b" +dependencies = [ + "darling_core 0.13.1", + "quote", + "syn", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dlib" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794" +dependencies = [ + "libloading", +] + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "fox32" +version = "0.1.0" +dependencies = [ + "log", + "pixels", + "rodio", + "winit", + "winit_input_helper", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + +[[package]] +name = "glow" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8bd5877156a19b8ac83a29b2306fe20537429d318f3ff0a1a2119f8d9c61919" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gpu-alloc" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e64cbb8d36508d3e19da95e56e196a84f674fc190881f2cc010000798838aa6" +dependencies = [ + "bitflags", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54804d0d6bc9d7f26db4eaec1ad10def69b599315f487d32c334a80d1efe67a5" +dependencies = [ + "bitflags", +] + +[[package]] +name = "gpu-descriptor" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a237f0419ab10d17006d55c62ac4f689a6bf52c75d3f38b8361d249e8d4b0b" +dependencies = [ + "bitflags", + "gpu-descriptor-types", + "hashbrown 0.9.1", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "363e3677e55ad168fef68cf9de3a4a310b53124c5e784c53a1d70e92d23f2126" +dependencies = [ + "bitflags", +] + +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + +[[package]] +name = "hound" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a164bb2ceaeff4f42542bdb847c41517c78a60f5649671b2a07312b6e117549" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +dependencies = [ + "autocfg", + "hashbrown 0.11.2", +] + +[[package]] +name = "inplace_it" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90953f308a79fe6d62a4643e51f848fbfddcd05975a38e69fdf4ab86a7baf7ca" + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "khronos-egl" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3" +dependencies = [ + "libc", + "libloading", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "lewton" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777b48df9aaab155475a83a7df3070395ea1ac6902f5cd062b8f2b028075c030" +dependencies = [ + "byteorder", + "ogg", + "tinyvec", +] + +[[package]] +name = "libc" +version = "0.2.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013" + +[[package]] +name = "libloading" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0cf036d15402bea3c5d4de17b3fce76b3e4a56ebc1f577be0e7a72f7c607cf0" +dependencies = [ + "cfg-if 1.0.0", + "winapi", +] + +[[package]] +name = "lock_api" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "memmap2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b6c2ebff6180198788f5db08d7ce3bc1d0b617176678831a7510825973e357" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg", +] + +[[package]] +name = "metal" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0514f491f4cc03632ab399ee01e2c1c1b12d3e1cf2d667c1ff5f87d6dcd2084" +dependencies = [ + "bitflags", + "block", + "core-graphics-types", + "foreign-types", + "log", + "objc", +] + +[[package]] +name = "minimal-lexical" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c64630dcdd71f1a64c435f54885086a0de5d6a12d104d69b165fb7d5286d677" + +[[package]] +name = "minimp3" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985438f75febf74c392071a975a29641b420dd84431135a6e6db721de4b74372" +dependencies = [ + "minimp3-sys", + "slice-deque", + "thiserror", +] + +[[package]] +name = "minimp3-sys" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e21c73734c69dc95696c9ed8926a2b393171d98b3f5f5935686a26a487ab9b90" +dependencies = [ + "cc", +] + +[[package]] +name = "mio" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "naga" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4419062f8aa39fb25938169486341945758679e260ddbc1f94bfd1f33924dc2" +dependencies = [ + "bit-set", + "bitflags", + "codespan-reporting", + "hexf-parse", + "indexmap", + "log", + "num-traits", + "rustc-hash", + "spirv", + "thiserror", +] + +[[package]] +name = "ndk" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8794322172319b972f528bf90c6b467be0079f1fa82780ffb431088e741a73ab" +dependencies = [ + "jni-sys", + "ndk-sys", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d64d6af06fde0e527b1ba5c7b79a6cc89cfc46325b0b2887dffe8f70197e0c3c" +dependencies = [ + "bitflags", + "jni-sys", + "ndk-sys", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d868f654c72e75f8687572699cdabe755f03effbb62542768e995d5b8d699d" +dependencies = [ + "bitflags", + "jni-sys", + "ndk-sys", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk-glue" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5caf0c24d51ac1c905c27d4eda4fa0635bbe0de596b8f79235e0b17a4d29385" +dependencies = [ + "lazy_static", + "libc", + "log", + "ndk 0.3.0", + "ndk-macro 0.2.0", + "ndk-sys", +] + +[[package]] +name = "ndk-glue" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e9e94628f24e7a3cb5b96a2dc5683acd9230bf11991c2a1677b87695138420" +dependencies = [ + "lazy_static", + "libc", + "log", + "ndk 0.4.0", + "ndk-macro 0.2.0", + "ndk-sys", +] + +[[package]] +name = "ndk-glue" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc291b8de2095cba8dab7cf381bf582ff4c17a09acf854c32e46545b08085d28" +dependencies = [ + "lazy_static", + "libc", + "log", + "ndk 0.5.0", + "ndk-macro 0.3.0", + "ndk-sys", +] + +[[package]] +name = "ndk-macro" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" +dependencies = [ + "darling 0.10.2", + "proc-macro-crate 0.1.5", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ndk-macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c" +dependencies = [ + "darling 0.13.1", + "proc-macro-crate 1.1.0", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ndk-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" + +[[package]] +name = "nix" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a" +dependencies = [ + "bitflags", + "cc", + "cfg-if 1.0.0", + "libc", +] + +[[package]] +name = "nix" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1e25ee6b412c2a1e3fcb6a4499a5c1bfe7f43e014bdce9a6b6666e5aa2d187" +dependencies = [ + "bitflags", + "cc", + "cfg-if 1.0.0", + "libc", + "memoffset", +] + +[[package]] +name = "nom" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +dependencies = [ + "memchr", + "version_check", +] + +[[package]] +name = "nom" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffd9d26838a953b4af82cbeb9f1592c6798916983959be223a7124e992742c1" +dependencies = [ + "memchr", + "minimal-lexical", + "version_check", +] + +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9bd055fb730c4f8f4f57d45d35cd6b3f0980535b056dc7ff119cee6a66ed6f" +dependencies = [ + "derivative", + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "486ea01961c4a818096de679a8b740b26d9033146ac5291b1c98557658f8cdd9" +dependencies = [ + "proc-macro-crate 1.1.0", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", + "objc_exception", +] + +[[package]] +name = "objc_exception" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" +dependencies = [ + "cc", +] + +[[package]] +name = "oboe" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e15e22bc67e047fe342a32ecba55f555e3be6166b04dd157cd0f803dfa9f48e1" +dependencies = [ + "jni", + "ndk 0.4.0", + "ndk-glue 0.4.0", + "num-derive", + "num-traits", + "oboe-sys", +] + +[[package]] +name = "oboe-sys" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "338142ae5ab0aaedc8275aa8f67f460e43ae0fca76a695a742d56da0a269eadc" +dependencies = [ + "cc", +] + +[[package]] +name = "ogg" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6951b4e8bf21c8193da321bcce9c9dd2e13c858fe078bf9054a288b419ae5d6e" +dependencies = [ + "byteorder", +] + +[[package]] +name = "once_cell" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pixels" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3be4951b24b374c72b0aaaeb59e51e1acb38b8e680b11f43c1d0049b8550891" +dependencies = [ + "bytemuck", + "pollster", + "raw-window-handle", + "thiserror", + "ultraviolet", + "wgpu", +] + +[[package]] +name = "pkg-config" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10e2fcbb64ecbe64c8e040a386c3104d384583af58b956d870aaaf229df6e66d" + +[[package]] +name = "pollster" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb20dcc30536a1508e75d47dd0e399bb2fe7354dcf35cda9127f2bf1ed92e30e" + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + +[[package]] +name = "proc-macro-crate" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebace6889caf889b4d3f76becee12e90353f2b8c7d875534a71e5742f8f6f83" +dependencies = [ + "thiserror", + "toml", +] + +[[package]] +name = "proc-macro2" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "profiling" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87dfd5592a8eed7e74f56ad7b125f8234763b805c30f0c7c95c486920026a6ec" + +[[package]] +name = "quote" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "range-alloc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e935c45e09cc6dcf00d2f0b2d630a58f4095320223d47fc68918722f0538b6" + +[[package]] +name = "raw-window-handle" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba75eee94a9d5273a68c9e1e105d9cffe1ef700532325788389e5a83e2522b7" +dependencies = [ + "cty", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "renderdoc-sys" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1382d1f0a252c4bf97dc20d979a2fdd05b024acd7c2ed0f7595d7817666a157" + +[[package]] +name = "rodio" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d98f5e557b61525057e2bc142c8cd7f0e70d75dc32852309bec440e6e046bf9" +dependencies = [ + "claxon", + "cpal", + "hound", + "lewton", + "minimp3", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "safe_arch" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ff3d6d9696af502cc3110dacce942840fb06ff4514cad92236ecc455f2ce05" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scoped-tls" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" + +[[package]] +name = "shlex" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" + +[[package]] +name = "slice-deque" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31ef6ee280cdefba6d2d0b4b78a84a1c1a3f3a4cec98c2d4231c8bc225de0f25" +dependencies = [ + "libc", + "mach", + "winapi", +] + +[[package]] +name = "slotmap" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" + +[[package]] +name = "smithay-client-toolkit" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1325f292209cee78d5035530932422a30aa4c8fda1a16593ac083c1de211e68a" +dependencies = [ + "bitflags", + "calloop", + "dlib", + "lazy_static", + "log", + "memmap2", + "nix 0.22.0", + "pkg-config", + "wayland-client", + "wayland-cursor", + "wayland-protocols", +] + +[[package]] +name = "spirv" +version = "0.2.0+1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246bfa38fe3db3f1dfc8ca5a2cdeb7348c78be2112740cc0ec8ef18b6d94f830" +dependencies = [ + "bitflags", + "num-traits", +] + +[[package]] +name = "stdweb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" + +[[package]] +name = "strsim" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinyvec" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + +[[package]] +name = "ultraviolet" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b9e3507eba17043af05c8a72fce3ec2c24b58945f45732e71dbc6646d904a7" +dependencies = [ + "wide", +] + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" + +[[package]] +name = "wayland-client" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91223460e73257f697d9e23d401279123d36039a3f7a449e983f123292d4458f" +dependencies = [ + "bitflags", + "downcast-rs", + "libc", + "nix 0.22.0", + "scoped-tls", + "wayland-commons", + "wayland-scanner", + "wayland-sys", +] + +[[package]] +name = "wayland-commons" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f6e5e340d7c13490eca867898c4cec5af56c27a5ffe5c80c6fc4708e22d33e" +dependencies = [ + "nix 0.22.0", + "once_cell", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-cursor" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c52758f13d5e7861fc83d942d3d99bf270c83269575e52ac29e5b73cb956a6bd" +dependencies = [ + "nix 0.22.0", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60147ae23303402e41fe034f74fb2c35ad0780ee88a1c40ac09a3be1e7465741" +dependencies = [ + "bitflags", + "wayland-client", + "wayland-commons", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39a1ed3143f7a143187156a2ab52742e89dac33245ba505c17224df48939f9e0" +dependencies = [ + "proc-macro2", + "quote", + "xml-rs", +] + +[[package]] +name = "wayland-sys" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9341df79a8975679188e37dab3889bfa57c44ac2cb6da166f519a81cbe452d4" +dependencies = [ + "dlib", + "lazy_static", + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wgpu" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97cd781ff044d6d697b632a2e212032c2e957d1afaa21dbf58069cbb8f78567" +dependencies = [ + "arrayvec", + "js-sys", + "log", + "naga", + "parking_lot", + "raw-window-handle", + "smallvec", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe9cb9c9d728c0f7ea0c309f1b3d5e9d5c7d379890d0a4e3df3103323ff7a84" +dependencies = [ + "arrayvec", + "bitflags", + "cfg_aliases", + "codespan-reporting", + "copyless", + "fxhash", + "log", + "naga", + "parking_lot", + "profiling", + "raw-window-handle", + "smallvec", + "thiserror", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-hal" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "742ec904d0577e1a88b82dba6cf0347c12197cd664b859b05f868bceb8cfff4d" +dependencies = [ + "arrayvec", + "ash", + "bit-set", + "bitflags", + "block", + "core-graphics-types", + "d3d12", + "foreign-types", + "fxhash", + "glow", + "gpu-alloc", + "gpu-descriptor", + "inplace_it", + "js-sys", + "khronos-egl", + "libloading", + "log", + "metal", + "naga", + "objc", + "parking_lot", + "profiling", + "range-alloc", + "raw-window-handle", + "renderdoc-sys", + "thiserror", + "wasm-bindgen", + "web-sys", + "wgpu-types", + "winapi", +] + +[[package]] +name = "wgpu-types" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "549533d9e1cdd4b4cda7718d33ff500fc4c34b5467b71d76b547ae0324f3b2a2" +dependencies = [ + "bitflags", +] + +[[package]] +name = "wide" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46bbe7c604a27ca0b05c5503221e76da628225b568e6f1280b42dbad3b72d89b" +dependencies = [ + "bytemuck", + "safe_arch", +] + +[[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-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "winit" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b43cc931d58b99461188607efd7acb2a093e65fc621f54cad78517a6063e73a" +dependencies = [ + "bitflags", + "cocoa", + "core-foundation 0.9.2", + "core-graphics 0.22.2", + "core-video-sys", + "dispatch", + "instant", + "lazy_static", + "libc", + "log", + "mio", + "ndk 0.5.0", + "ndk-glue 0.5.0", + "ndk-sys", + "objc", + "parking_lot", + "percent-encoding", + "raw-window-handle", + "smithay-client-toolkit", + "wasm-bindgen", + "wayland-client", + "wayland-protocols", + "web-sys", + "winapi", + "x11-dl", +] + +[[package]] +name = "winit_input_helper" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c8618b5c5e3f44a9d0a2ace15ad580cb7402d585507f4f9c74d07af7603909" +dependencies = [ + "winit", +] + +[[package]] +name = "x11-dl" +version = "2.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea26926b4ce81a6f5d9d0f3a0bc401e5a37c6ae14a1bfaa8ff6099ca80038c59" +dependencies = [ + "lazy_static", + "libc", + "pkg-config", +] + +[[package]] +name = "xcursor" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" +dependencies = [ + "nom 7.0.0", +] + +[[package]] +name = "xml-rs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..63befaa --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "fox32" +version = "0.1.0" +authors = ["ry"] +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +log = "0.4" +pixels = "0.9.0" +rodio = "0.14.0" +winit = "0.26" +winit_input_helper = "0.11" diff --git a/encoding.md b/encoding.md new file mode 100644 index 0000000..f16c4eb --- /dev/null +++ b/encoding.md @@ -0,0 +1,46 @@ +# Encoding +``` +size instr . cond dest src +xx xxxxxx 0 xxx xx xx <8,16,32 bits> <8,16,32 bits> +``` + + +# Size table +If instruction doesn't allow variable sizes or size was not specified, set size bits to 0b11 +| | | +| :--: | -------------- | +| 0b00 | byte (8 bits) | +| 0b01 | half (16 bits) | +| 0b10 | word (32 bits) | + +# Instruction table +| 0x | -0 | -1 | -2 | -3 | -4 | -5 | -6 | -7 | -8 | -9 | -A | -B | -C | -D | -E | -F | +| :-: | ---- | ------------- | ------------- | ------------- | ------------- | ------------- | ------------- | -------------- | ---- | ----- | -------------- | --- | --- | --- | --- | --- | +| 0- | NOP | ADD[.8,16,32] | MUL[.8,16,32] | AND[.8,16,32] | SLA[.8,16,32] | SRA[.8,16,32] | BSE[.8,16,32] | CMP[.8,16,32] | JMP | RJMP | PUSH[.8,16,32] | IN | ISE | | | | +| 1- | HALT | INC[.8,16,32] | POW[.8,16,32] | OR[.8,16,32] | | SRL[.8,16,32] | BCL[.8,16,32] | MOV[.8,16,32] | CALL | RCALL | POP[.8,16,32] | OUT | ICL | | | | +| 2- | BRK | SUB[.8,16,32] | DIV[.8,16,32] | XOR[.8,16,32] | ROL[.8,16,32] | ROR[.8,16,32] | BTS[.8,16,32] | MOVZ[.8,16,32] | LOOP | RLOOP | RET | | | | | | +| 3- | | DEC[.8,16,32] | REM[.8,16,32] | NOT[.8,16,32] | | | | | | RTA | RETI | | | | | | + +# Condition table +| | | +| :---: | -------- | +| 0b000 | (always) | +| 0b001 | IFZ | +| 0b010 | IFNZ | +| 0b011 | IFC | +| 0b100 | IFNC | + +# Destination table +| | | +| :--: | ------------------- | +| 0b00 | register | +| 0b01 | register (pointer) | +| 0b10 | immediate (pointer) | + +# Source table +| | | +| :--: | ------------------- | +| 0b00 | register | +| 0b01 | register (pointer) | +| 0b10 | immediate | +| 0b11 | immediate (pointer) | \ No newline at end of file diff --git a/src/cpu.rs b/src/cpu.rs new file mode 100644 index 0000000..0667ef7 --- /dev/null +++ b/src/cpu.rs @@ -0,0 +1,2953 @@ +// cpu.rs + +// TODO: in the instruction match statement, all of the register ones have `let result` inside the if statement +// move this up to match all of the other ones (or move all of the other ones down, which would probably be better anyways) + +use crate::{Mouse, Overlay}; +use std::sync::{Arc, Mutex}; + +const DEBUG: bool = false; + +pub struct Memory { + ram: Vec, + rom: Vec, + pub shared_memory: Arc>>, + pub overlays: Arc>>, +} + +impl Memory { // TODO: make this a trait, so the application can implement read_memory and write_memory itself + pub fn new(size: u32, shared_memory: Arc>>, overlays: Arc>>, read_only_memory: Vec) -> Self { + Memory { + ram: vec![0; size as usize], + rom: read_only_memory, + shared_memory, + overlays, + } + } + pub fn read_8(&self, address: u32) -> u8 { + let address = address as usize; + if address < 0x02000000 { + self.ram[address] + } else if address >= 0xF0000000 { + let address = address - 0xF0000000; + self.rom[address] + } else { + let address = address - 0x02000000; + let shared_memory_lock = self.shared_memory.lock().unwrap(); + shared_memory_lock[address] + } + } + pub fn read_16(&self, address: u32) -> u16 { + (self.read_8(address + 1) as u16) << 8 | + (self.read_8(address) as u16) + } + pub fn read_32(&self, address: u32) -> u32 { + let address = address as usize; + if address < 0x02000000 { + (self.ram[address + 3] as u32) << 24 | + (self.ram[address + 2] as u32) << 16 | + (self.ram[address + 1] as u32) << 8 | + (self.ram[address] as u32) + } else if address >= 0xF0000000 { + let address = address - 0xF0000000; + (self.rom[address + 3] as u32) << 24 | + (self.rom[address + 2] as u32) << 16 | + (self.rom[address + 1] as u32) << 8 | + (self.rom[address] as u32) + } else { + let address = address - 0x02000000; + let shared_memory_lock = self.shared_memory.lock().unwrap(); + (shared_memory_lock[address + 3] as u32) << 24 | + (shared_memory_lock[address + 2] as u32) << 16 | + (shared_memory_lock[address + 1] as u32) << 8 | + (shared_memory_lock[address] as u32) + } + } + pub fn write_8(&mut self, address: u32, byte: u8) { + let address = address as usize; + if address < 0x02000000 { + self.ram[address] = byte; + } else { + let address = address - 0x02000000; + let mut shared_memory_lock = self.shared_memory.lock().unwrap(); + shared_memory_lock[address] = byte; + } + } + pub fn write_16(&mut self, address: u32, half: u16) { + self.write_8(address, (half & 0x00FF) as u8); + self.write_8(address + 1, (half >> 8) as u8); + } + pub fn write_32(&mut self, address: u32, word: u32) { + let address = address as usize; + if address < 0x02000000 { + self.ram[address] = (word & 0x000000FF) as u8; + self.ram[address + 1] = ((word & 0x0000FF00) >> 8) as u8; + self.ram[address + 2] = ((word & 0x00FF0000) >> 16) as u8; + self.ram[address + 3] = ((word & 0xFF000000) >> 24) as u8; + } else { + let address = address - 0x02000000; + let mut shared_memory_lock = self.shared_memory.lock().unwrap(); + shared_memory_lock[address] = (word & 0x000000FF) as u8; + shared_memory_lock[address + 1] = ((word & 0x0000FF00) >> 8) as u8; + shared_memory_lock[address + 2] = ((word & 0x00FF0000) >> 16) as u8; + shared_memory_lock[address + 3] = ((word & 0xFF000000) >> 24) as u8; + } + } +} + +pub trait IO { + // called during the `in` instruction + // default implementation returns 0 + fn read_io(&mut self, port: u32) -> u32 { + if DEBUG { println!("read_io(): port: {:#010X}", port); } + 0 + } + // called during the `out` instruction + fn write_io(&mut self, port: u32, word: u32) { + if DEBUG { println!("write_io(): port: {:#010X}, word: {:#010X}", port, word); } + } +} + +pub struct Bus { + pub memory: Memory, + pub mouse: Arc>, +} + +#[derive(Copy, Clone)] +pub struct Flag { + pub carry: bool, + pub zero: bool, +} + +impl std::convert::From for u8 { + fn from(flag: Flag) -> u8 { + (if flag.carry { 1 } else { 0 }) << 1 | + (if flag.zero { 1 } else { 0 }) << 0 + } +} + +impl std::convert::From for Flag { + fn from(byte: u8) -> Self { + let carry = ((byte >> 1) & 1) != 0; + let zero = ((byte >> 0) & 1) != 0; + Flag { + carry, + zero, + } + } +} + +#[derive(Debug)] +pub enum Exception { + DivideByZero, + InvalidOpcode(u32), +} + +#[derive(Debug)] +pub enum Interrupt { + Exception(Exception), + Request(u8), // u8 contains the interrupt vector value +} + +pub struct CPU { + pub instruction_pointer: u32, + + // 0-31: r0-r31 + // 32: rsp + pub register: [u32; 33], + pub flag: Flag, + pub halted: bool, + pub interrupts_enabled: bool, + pub interrupts_paused: bool, // stores the previous state of interrupts_enabled while servicing an interrupt + + pub bus: Bus, +} + +impl CPU { + pub fn new(bus: Bus) -> Self { + CPU { + instruction_pointer: 0xF0000000, + register: [0; 33], + flag: Flag { zero: false, carry: false }, + halted: false, + interrupts_enabled: false, + interrupts_paused: false, + bus, + } + } + fn check_condition(&self, condition: Condition) -> bool { + match condition { + Condition::Always => true, + Condition::Zero => self.flag.zero, + Condition::NotZero => !self.flag.zero, + Condition::Carry => self.flag.carry, + Condition::NotCarry => !self.flag.carry, + } + } + fn relative_to_absolute(&self, relative_address: u32) -> u32 { + self.instruction_pointer.wrapping_add(relative_address) + } + fn read_source(&self, source: Operand) -> (u32, u32) { + let mut instruction_pointer_offset = 2; // increment past opcode half + let source_value = match source { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let value = self.register[register]; + instruction_pointer_offset += 1; // increment past 8 bit register number + value + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + let value = self.bus.memory.read_32(pointer); + instruction_pointer_offset += 1; // increment past 8 bit register number + value + } + Operand::Immediate8 => { + let value = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset); + instruction_pointer_offset += 1; // increment past 8 bit immediate + value as u32 + } + Operand::Immediate16 => { + let value = self.bus.memory.read_16(self.instruction_pointer + instruction_pointer_offset); + instruction_pointer_offset += 2; // increment past 16 bit immediate + value as u32 + } + Operand::Immediate32 => { + let value = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + instruction_pointer_offset += 4; // increment past 32 bit immediate + value + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + let value = self.bus.memory.read_32(pointer); + instruction_pointer_offset += 4; // increment past 32 bit pointer + value + } + }; + (source_value, instruction_pointer_offset) + } + pub fn read_register(self, register: u8) -> u32 { + self.register[register as usize] + } + pub fn write_register(&mut self, register: u8, word: u32) { + self.register[register as usize] = word; + } + pub fn print_registers(&mut self) { + for index in 0..2 { + println!("r{}: {:#010X} | r{}: {:#010X} | r{}: {:#010X} | r{}: {:#010X}", + index, self.register[index], + index + 8, self.register[index + 8], + index + 16, self.register[index + 16], + index + 24, self.register[index + 24] + ); + } + for index in 2..8 { + println!("r{}: {:#010X} | r{}: {:#010X} | r{}: {:#010X} | r{}: {:#010X}", + index, self.register[index], + index + 8, self.register[index + 8], + index + 16, self.register[index + 16], + index + 24, self.register[index + 24] + ); + } + println!("rsp: {:#010X}", self.register[32]); + } + pub fn push_stack_8(&mut self, byte: u8) { + let decremented_stack_pointer = self.register[32].overflowing_sub(1); + self.register[32] = decremented_stack_pointer.0; + if decremented_stack_pointer.1 { + // TODO: stack overflow exception + } + self.bus.memory.write_8(self.register[32], byte); + } + pub fn pop_stack_8(&mut self) -> u8 { + let byte = self.bus.memory.read_8(self.register[32]); + let incremented_stack_pointer = self.register[32].overflowing_add(1); + self.register[32] = incremented_stack_pointer.0; + if incremented_stack_pointer.1 { + // TODO: stack overflow exception + } + byte + } + pub fn push_stack_16(&mut self, half: u16) { + let decremented_stack_pointer = self.register[32].overflowing_sub(2); + self.register[32] = decremented_stack_pointer.0; + if decremented_stack_pointer.1 { + // TODO: stack overflow exception + } + self.bus.memory.write_16(self.register[32], half); + } + pub fn pop_stack_16(&mut self) -> u16 { + let half = self.bus.memory.read_16(self.register[32]); + let incremented_stack_pointer = self.register[32].overflowing_add(2); + self.register[32] = incremented_stack_pointer.0; + if incremented_stack_pointer.1 { + // TODO: stack overflow exception + } + half + } + pub fn push_stack_32(&mut self, word: u32) { + let decremented_stack_pointer = self.register[32].overflowing_sub(4); + self.register[32] = decremented_stack_pointer.0; + if decremented_stack_pointer.1 { + // TODO: stack overflow exception + } + self.bus.memory.write_32(self.register[32], word); + } + pub fn pop_stack_32(&mut self) -> u32 { + let word = self.bus.memory.read_32(self.register[32]); + let incremented_stack_pointer = self.register[32].overflowing_add(4); + self.register[32] = incremented_stack_pointer.0; + if incremented_stack_pointer.1 { + // TODO: stack overflow exception + } + word + } + pub fn interrupt(&mut self, interrupt: Interrupt) { + if DEBUG { println!("interrupt(): enabled: {}, paused: {}", self.interrupts_enabled, self.interrupts_paused); } + if self.interrupts_enabled && !self.interrupts_paused { + self.interrupts_paused = true; // prevent interrupts while already servicing an interrupt + match interrupt { + Interrupt::Request(vector) => { + self.handle_interrupt(vector as u16); + } + Interrupt::Exception(exception) => { + match exception { + Exception::DivideByZero => { + let vector: u16 = 0; + self.handle_exception(vector, None); + } + Exception::InvalidOpcode(opcode) => { + let vector: u16 = 1; + self.handle_exception(vector, Some(opcode)); + } + } + } + } + } + } + fn handle_interrupt(&mut self, vector: u16) { + if DEBUG { println!("interrupt!!! vector: {:#04X}", vector); } + let address_of_pointer = vector as u32 * 4; + let address = self.bus.memory.read_32(address_of_pointer); + self.push_stack_32(self.instruction_pointer); + self.push_stack_8(u8::from(self.flag)); + self.instruction_pointer = address; + } + fn handle_exception(&mut self, vector: u16, operand: Option) { + if DEBUG { println!("exception!!! vector: {:#04X}, operand: {:?}", vector, operand); } + let address_of_pointer = (256 + vector) as u32 * 4; + let address = self.bus.memory.read_32(address_of_pointer); + self.push_stack_32(self.instruction_pointer); + self.push_stack_8(u8::from(self.flag)); + if let Some(operand) = operand { + self.push_stack_32(operand); + } + self.instruction_pointer = address; + } + // execute instruction from memory at the current instruction pointer + pub fn execute_memory_instruction(&mut self) { + let opcode = self.bus.memory.read_16(self.instruction_pointer); + + if let Some(instruction) = Instruction::from_half(opcode) { + if DEBUG { println!("{:#010X}: {:?}", self.instruction_pointer, instruction); } + self.instruction_pointer = self.execute_instruction(instruction); + } else { + let size = ((opcode & 0b1100000000000000) >> 14) as u8; + let instruction = ((opcode & 0b0011111100000000) >> 8) as u8; + let empty = ((opcode & 0b0000000010000000) >> 7) as u8; + let condition = ((opcode & 0b0000000001110000) >> 4) as u8; + let destination = ((opcode & 0b0000000000001100) >> 2) as u8; + let source = (opcode & 0b0000000000000011) as u8; + + println!("{:#010X}: bad opcode {:#06X}", self.instruction_pointer, opcode); + println!("size instr . cond dest src"); + println!("{:02b} {:06b} {:01b} {:03b} {:02b} {:02b}", size, instruction, empty, condition, destination, source); + panic!("bad opcode"); + } + } + // execute one instruction and return the next instruction pointer value + fn execute_instruction(&mut self, instruction: Instruction) -> u32 { + match instruction { + Instruction::Nop() => { + self.instruction_pointer + 2 // increment past opcode half + } + Instruction::Halt(condition) => { + let instruction_pointer_offset = 2; // increment past opcode half + let should_run = self.check_condition(condition); + if should_run { + self.halted = true; + //if DEBUG { self.print_registers(); } + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Brk(condition) => { + let instruction_pointer_offset = 2; // increment past opcode half + let should_run = self.check_condition(condition); + if should_run { + //self.breakpoint = true; + println!("Breakpoint reached"); + self.print_registers(); + } + self.instruction_pointer + instruction_pointer_offset + } + + Instruction::Add(size, condition, destination, source) => { + let (source_value, mut instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match destination { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + if should_run { + let result = (self.register[register] as u8).overflowing_add(source_value as u8); + self.register[register] = (self.register[register] & 0xFFFFFF00) | (result.0 as u32); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Half => { + if should_run { + let result = (self.register[register] as u16).overflowing_add(source_value as u16); + self.register[register] = (self.register[register] & 0xFFFF0000) | (result.0 as u32); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Word => { + if should_run { + let result = (self.register[register]).overflowing_add(source_value); + self.register[register] = result.0; + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer).overflowing_add(source_value as u8); + if should_run { + self.bus.memory.write_8(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer).overflowing_add(source_value as u16); + if should_run { + self.bus.memory.write_16(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer).overflowing_add(source_value); + if should_run { + self.bus.memory.write_32(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer).overflowing_add(source_value as u8); + if should_run { + self.bus.memory.write_8(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer).overflowing_add(source_value as u16); + if should_run { + self.bus.memory.write_16(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer).overflowing_add(source_value); + if should_run { + self.bus.memory.write_32(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Inc(size, condition, source) => { + let mut instruction_pointer_offset = 2; // increment past opcode half + let should_run = self.check_condition(condition); + match source { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + if should_run { + let result = (self.register[register] as u8).overflowing_add(1); + self.register[register] = (self.register[register] & 0xFFFFFF00) | (result.0 as u32); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Half => { + if should_run { + let result = (self.register[register] as u16).overflowing_add(1); + self.register[register] = (self.register[register] & 0xFFFF0000) | (result.0 as u32); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Word => { + if should_run { + let result = (self.register[register]).overflowing_add(1); + self.register[register] = result.0; + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + match size { + Size::Byte => { + if should_run { + let result = self.bus.memory.read_8(pointer).overflowing_add(1); + self.bus.memory.write_8(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Half => { + if should_run { + let result = self.bus.memory.read_16(pointer).overflowing_add(1); + self.bus.memory.write_16(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Word => { + if should_run { + let result = self.bus.memory.read_32(pointer).overflowing_add(1); + self.bus.memory.write_32(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + match size { + Size::Byte => { + if should_run { + let result = self.bus.memory.read_8(pointer).overflowing_add(1); + self.bus.memory.write_8(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Half => { + if should_run { + let result = self.bus.memory.read_16(pointer).overflowing_add(1); + self.bus.memory.write_16(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Word => { + if should_run { + let result = self.bus.memory.read_32(pointer).overflowing_add(1); + self.bus.memory.write_32(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Sub(size, condition, destination, source) => { + let (source_value, mut instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match destination { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + if should_run { + let result = (self.register[register] as u8).overflowing_sub(source_value as u8); + self.register[register] = (self.register[register] & 0xFFFFFF00) | (result.0 as u32); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Half => { + if should_run { + let result = (self.register[register] as u16).overflowing_sub(source_value as u16); + self.register[register] = (self.register[register] & 0xFFFF0000) | (result.0 as u32); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Word => { + if should_run { + let result = (self.register[register]).overflowing_sub(source_value); + self.register[register] = result.0; + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer).overflowing_sub(source_value as u8); + if should_run { + self.bus.memory.write_8(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer).overflowing_sub(source_value as u16); + if should_run { + self.bus.memory.write_16(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer).overflowing_sub(source_value); + if should_run { + self.bus.memory.write_32(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer).overflowing_sub(source_value as u8); + if should_run { + self.bus.memory.write_8(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer).overflowing_sub(source_value as u16); + if should_run { + self.bus.memory.write_16(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer).overflowing_sub(source_value); + if should_run { + self.bus.memory.write_32(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Dec(size, condition, source) => { + let mut instruction_pointer_offset = 2; // increment past opcode half + let should_run = self.check_condition(condition); + match source { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + if should_run { + let result = (self.register[register] as u8).overflowing_sub(1); + self.register[register] = (self.register[register] & 0xFFFFFF00) | (result.0 as u32); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Half => { + if should_run { + let result = (self.register[register] as u16).overflowing_sub(1); + self.register[register] = (self.register[register] & 0xFFFF0000) | (result.0 as u32); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Word => { + if should_run { + let result = (self.register[register]).overflowing_sub(1); + self.register[register] = result.0; + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + match size { + Size::Byte => { + if should_run { + let result = self.bus.memory.read_8(pointer).overflowing_sub(1); + self.bus.memory.write_8(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Half => { + if should_run { + let result = self.bus.memory.read_16(pointer).overflowing_sub(1); + self.bus.memory.write_16(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Word => { + if should_run { + let result = self.bus.memory.read_32(pointer).overflowing_sub(1); + self.bus.memory.write_32(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + match size { + Size::Byte => { + if should_run { + let result = self.bus.memory.read_8(pointer).overflowing_sub(1); + self.bus.memory.write_8(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Half => { + if should_run { + let result = self.bus.memory.read_16(pointer).overflowing_sub(1); + self.bus.memory.write_16(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Word => { + if should_run { + let result = self.bus.memory.read_32(pointer).overflowing_sub(1); + self.bus.memory.write_32(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Mul(size, condition, destination, source) => { + let (source_value, mut instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match destination { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + if should_run { + let result = (self.register[register] as u8).overflowing_mul(source_value as u8); + self.register[register] = (self.register[register] & 0xFFFFFF00) | (result.0 as u32); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Half => { + if should_run { + let result = (self.register[register] as u16).overflowing_mul(source_value as u16); + self.register[register] = (self.register[register] & 0xFFFF0000) | (result.0 as u32); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Word => { + if should_run { + let result = (self.register[register]).overflowing_mul(source_value); + self.register[register] = result.0; + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer).overflowing_mul(source_value as u8); + if should_run { + self.bus.memory.write_8(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer).overflowing_mul(source_value as u16); + if should_run { + self.bus.memory.write_16(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer).overflowing_mul(source_value); + if should_run { + self.bus.memory.write_32(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer).overflowing_mul(source_value as u8); + if should_run { + self.bus.memory.write_8(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer).overflowing_mul(source_value as u16); + if should_run { + self.bus.memory.write_16(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer).overflowing_mul(source_value); + if should_run { + self.bus.memory.write_32(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Pow(size, condition, destination, source) => { + let (source_value, mut instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match destination { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + if should_run { + let result = (self.register[register] as u8).pow(source_value); + self.register[register] = (self.register[register] & 0xFFFFFF00) | (result as u32); + self.flag.zero = result == 0; + } + } + Size::Half => { + if should_run { + let result = (self.register[register] as u16).pow(source_value); + self.register[register] = (self.register[register] & 0xFFFF0000) | (result as u32); + self.flag.zero = result == 0; + } + } + Size::Word => { + if should_run { + let result = (self.register[register]).pow(source_value); + self.register[register] = result; + self.flag.zero = result == 0; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer).pow(source_value); + if should_run { + self.bus.memory.write_8(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer).pow(source_value); + if should_run { + self.bus.memory.write_16(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer).pow(source_value); + if should_run { + self.bus.memory.write_32(pointer, result); + self.flag.zero = result == 0; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer).pow(source_value); + if should_run { + self.bus.memory.write_8(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer).pow(source_value); + if should_run { + self.bus.memory.write_16(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer).pow(source_value); + if should_run { + self.bus.memory.write_32(pointer, result); + self.flag.zero = result == 0; + } + } + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Div(size, condition, destination, source) => { + let (source_value, mut instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match destination { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + if should_run { + let result = (self.register[register] as u8).overflowing_div(source_value as u8); + self.register[register] = (self.register[register] & 0xFFFFFF00) | (result.0 as u32); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Half => { + if should_run { + let result = (self.register[register] as u16).overflowing_div(source_value as u16); + self.register[register] = (self.register[register] & 0xFFFF0000) | (result.0 as u32); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Word => { + if should_run { + let result = (self.register[register]).overflowing_div(source_value); + self.register[register] = result.0; + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer).overflowing_div(source_value as u8); + if should_run { + self.bus.memory.write_8(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer).overflowing_div(source_value as u16); + if should_run { + self.bus.memory.write_16(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer).overflowing_div(source_value); + if should_run { + self.bus.memory.write_32(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer).overflowing_div(source_value as u8); + if should_run { + self.bus.memory.write_8(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer).overflowing_div(source_value as u16); + if should_run { + self.bus.memory.write_16(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer).overflowing_div(source_value); + if should_run { + self.bus.memory.write_32(pointer, result.0); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Rem(size, condition, destination, source) => { + let (source_value, mut instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match destination { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + if should_run { + let result = (self.register[register] as u8) % source_value as u8; + self.register[register] = (self.register[register] & 0xFFFFFF00) | (result as u32); + self.flag.zero = result == 0; + } + } + Size::Half => { + if should_run { + let result = (self.register[register] as u16) % source_value as u16; + self.register[register] = (self.register[register] & 0xFFFF0000) | (result as u32); + self.flag.zero = result == 0; + } + } + Size::Word => { + if should_run { + let result = (self.register[register]) % source_value; + self.register[register] = result; + self.flag.zero = result == 0; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer) % source_value as u8; + if should_run { + self.bus.memory.write_8(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer) % source_value as u16; + if should_run { + self.bus.memory.write_16(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer) % source_value; + if should_run { + self.bus.memory.write_32(pointer, result); + self.flag.zero = result == 0; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer) % source_value as u8; + if should_run { + self.bus.memory.write_8(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer) % source_value as u16; + if should_run { + self.bus.memory.write_16(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer) % source_value; + if should_run { + self.bus.memory.write_32(pointer, result); + self.flag.zero = result == 0; + } + } + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + + Instruction::And(size, condition, destination, source) => { + let (source_value, mut instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match destination { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + if should_run { + let result = (self.register[register] as u8) & source_value as u8; + self.register[register] = (self.register[register] & 0xFFFFFF00) | (result as u32); + self.flag.zero = result == 0; + } + } + Size::Half => { + if should_run { + let result = (self.register[register] as u16) & source_value as u16; + self.register[register] = (self.register[register] & 0xFFFF0000) | (result as u32); + self.flag.zero = result == 0; + } + } + Size::Word => { + if should_run { + let result = (self.register[register]) & source_value; + self.register[register] = result; + self.flag.zero = result == 0; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer) & source_value as u8; + if should_run { + self.bus.memory.write_8(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer) & source_value as u16; + if should_run { + self.bus.memory.write_16(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer) & source_value; + if should_run { + self.bus.memory.write_32(pointer, result); + self.flag.zero = result == 0; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer) & source_value as u8; + if should_run { + self.bus.memory.write_8(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer) & source_value as u16; + if should_run { + self.bus.memory.write_16(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer) & source_value; + if should_run { + self.bus.memory.write_32(pointer, result); + self.flag.zero = result == 0; + } + } + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Or(size, condition, destination, source) => { + let (source_value, mut instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match destination { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + if should_run { + let result = (self.register[register] as u8) | source_value as u8; + self.register[register] = (self.register[register] & 0xFFFFFF00) | (result as u32); + self.flag.zero = result == 0; + } + } + Size::Half => { + if should_run { + let result = (self.register[register] as u16) | source_value as u16; + self.register[register] = (self.register[register] & 0xFFFF0000) | (result as u32); + self.flag.zero = result == 0; + } + } + Size::Word => { + if should_run { + let result = (self.register[register]) | source_value; + self.register[register] = result; + self.flag.zero = result == 0; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer) | source_value as u8; + if should_run { + self.bus.memory.write_8(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer) | source_value as u16; + if should_run { + self.bus.memory.write_16(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer) | source_value; + if should_run { + self.bus.memory.write_32(pointer, result); + self.flag.zero = result == 0; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer) | source_value as u8; + if should_run { + self.bus.memory.write_8(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer) | source_value as u16; + if should_run { + self.bus.memory.write_16(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer) | source_value; + if should_run { + self.bus.memory.write_32(pointer, result); + self.flag.zero = result == 0; + } + } + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Xor(size, condition, destination, source) => { + let (source_value, mut instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match destination { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + if should_run { + let result = (self.register[register] as u8) ^ source_value as u8; + self.register[register] = (self.register[register] & 0xFFFFFF00) | (result as u32); + self.flag.zero = result == 0; + } + } + Size::Half => { + if should_run { + let result = (self.register[register] as u16) ^ source_value as u16; + self.register[register] = (self.register[register] & 0xFFFF0000) | (result as u32); + self.flag.zero = result == 0; + } + } + Size::Word => { + if should_run { + let result = (self.register[register]) ^ source_value; + self.register[register] = result; + self.flag.zero = result == 0; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer) ^ source_value as u8; + if should_run { + self.bus.memory.write_8(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer) ^ source_value as u16; + if should_run { + self.bus.memory.write_16(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer) ^ source_value; + if should_run { + self.bus.memory.write_32(pointer, result); + self.flag.zero = result == 0; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer) ^ source_value as u8; + if should_run { + self.bus.memory.write_8(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer) ^ source_value as u16; + if should_run { + self.bus.memory.write_16(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer) ^ source_value; + if should_run { + self.bus.memory.write_32(pointer, result); + self.flag.zero = result == 0; + } + } + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Not(size, condition, source) => { + let mut instruction_pointer_offset = 2; // increment past opcode half + let should_run = self.check_condition(condition); + match source { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + if should_run { + let result = !self.register[register] as u8; + self.register[register] = (self.register[register] & 0xFFFFFF00) | (result as u32); + self.flag.zero = result == 0; + } + } + Size::Half => { + if should_run { + let result = !self.register[register] as u16; + self.register[register] = (self.register[register] & 0xFFFF0000) | (result as u32); + self.flag.zero = result == 0; + } + } + Size::Word => { + if should_run { + let result = !self.register[register]; + self.register[register] = result; + self.flag.zero = result == 0; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + match size { + Size::Byte => { + let result =!self.bus.memory.read_8(pointer); + if should_run { + self.bus.memory.write_8(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Half => { + let result = !self.bus.memory.read_16(pointer); + if should_run { + self.bus.memory.write_16(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Word => { + let result = !self.bus.memory.read_32(pointer); + if should_run { + self.bus.memory.write_32(pointer, result); + self.flag.zero = result == 0; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + match size { + Size::Byte => { + let result = !self.bus.memory.read_8(pointer); + if should_run { + self.bus.memory.write_8(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Half => { + let result = !self.bus.memory.read_16(pointer); + if should_run { + self.bus.memory.write_16(pointer, result); + self.flag.zero = result == 0; + } + } + Size::Word => { + let result = !self.bus.memory.read_32(pointer); + if should_run { + self.bus.memory.write_32(pointer, result); + self.flag.zero = result == 0; + } + } + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Sla(size, condition, destination, source) => { + let (source_value, mut instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match destination { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + if should_run { + let result = (self.register[register] as u8) << source_value; + self.register[register] = (self.register[register] & 0xFFFFFF00) | (result as u32); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 7) != 0; + } + } + Size::Half => { + if should_run { + let result = (self.register[register] as u16) << source_value; + self.register[register] = (self.register[register] & 0xFFFF0000) | (result as u32); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 15) != 0; + } + } + Size::Word => { + if should_run { + let result = self.register[register] << source_value; + self.register[register] = result; + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 31) != 0; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer) << source_value; + if should_run { + self.bus.memory.write_8(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 7) != 0; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer) << source_value; + if should_run { + self.bus.memory.write_16(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 15) != 0; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer) << source_value; + if should_run { + self.bus.memory.write_32(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 31) != 0; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer) << source_value; + if should_run { + self.bus.memory.write_8(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 7) != 0; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer) << source_value; + if should_run { + self.bus.memory.write_16(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 15) != 0; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer) << source_value; + if should_run { + self.bus.memory.write_32(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 31) != 0; + } + } + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Sra(size, condition, destination, source) => { + let (source_value, mut instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match destination { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + if should_run { + let result = (self.register[register] as u8) >> source_value as i32; + self.register[register] = (self.register[register] & 0xFFFFFF00) | (result as u32); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + Size::Half => { + if should_run { + let result = (self.register[register] as u16) >> source_value as i32; + self.register[register] = (self.register[register] & 0xFFFF0000) | (result as u32); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + Size::Word => { + if should_run { + let result = self.register[register] >> source_value as i32; + self.register[register] = result; + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer) >> source_value as i32; + if should_run { + self.bus.memory.write_8(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer) >> source_value as i32; + if should_run { + self.bus.memory.write_16(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer) >> source_value as i32; + if should_run { + self.bus.memory.write_32(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer) >> source_value as i32; + if should_run { + self.bus.memory.write_8(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer) >> source_value as i32; + if should_run { + self.bus.memory.write_16(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer) >> source_value as i32; + if should_run { + self.bus.memory.write_32(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Srl(size, condition, destination, source) => { + let (source_value, mut instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match destination { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + if should_run { + let result = (self.register[register] as u8) >> source_value; + self.register[register] = (self.register[register] & 0xFFFFFF00) | (result as u32); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + Size::Half => { + if should_run { + let result = (self.register[register] as u16) >> source_value; + self.register[register] = (self.register[register] & 0xFFFF0000) | (result as u32); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + Size::Word => { + if should_run { + let result = self.register[register] >> source_value; + self.register[register] = result; + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer) >> source_value; + if should_run { + self.bus.memory.write_8(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer) >> source_value; + if should_run { + self.bus.memory.write_16(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer) >> source_value; + if should_run { + self.bus.memory.write_32(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer) >> source_value; + if should_run { + self.bus.memory.write_8(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer) >> source_value; + if should_run { + self.bus.memory.write_16(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer) >> source_value; + if should_run { + self.bus.memory.write_32(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Rol(size, condition, destination, source) => { + let (source_value, mut instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match destination { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + if should_run { + let result = (self.register[register] as u8).rotate_left(source_value); + self.register[register] = (self.register[register] & 0xFFFFFF00) | (result as u32); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 7) != 0; + } + } + Size::Half => { + if should_run { + let result = (self.register[register] as u16).rotate_left(source_value); + self.register[register] = (self.register[register] & 0xFFFF0000) | (result as u32); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 15) != 0; + } + } + Size::Word => { + if should_run { + let result = self.register[register].rotate_left(source_value); + self.register[register] = result; + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 31) != 0; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer).rotate_left(source_value); + if should_run { + self.bus.memory.write_8(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 7) != 0; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer).rotate_left(source_value); + if should_run { + self.bus.memory.write_16(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 15) != 0; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer).rotate_left(source_value); + if should_run { + self.bus.memory.write_32(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 31) != 0; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer).rotate_left(source_value); + if should_run { + self.bus.memory.write_8(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 7) != 0; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer).rotate_left(source_value); + if should_run { + self.bus.memory.write_16(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 15) != 0; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer).rotate_left(source_value); + if should_run { + self.bus.memory.write_32(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 31) != 0; + } + } + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Ror(size, condition, destination, source) => { + let (source_value, mut instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match destination { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + if should_run { + let result = (self.register[register] as u8).rotate_right(source_value); + self.register[register] = (self.register[register] & 0xFFFFFF00) | (result as u32); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + Size::Half => { + if should_run { + let result = (self.register[register] as u16).rotate_right(source_value); + self.register[register] = (self.register[register] & 0xFFFF0000) | (result as u32); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + Size::Word => { + if should_run { + let result = self.register[register].rotate_right(source_value); + self.register[register] = result; + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer).rotate_right(source_value); + if should_run { + self.bus.memory.write_8(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer).rotate_right(source_value); + if should_run { + self.bus.memory.write_16(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer).rotate_right(source_value); + if should_run { + self.bus.memory.write_32(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer).rotate_right(source_value); + if should_run { + self.bus.memory.write_8(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer).rotate_right(source_value); + if should_run { + self.bus.memory.write_16(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer).rotate_right(source_value); + if should_run { + self.bus.memory.write_32(pointer, result); + self.flag.zero = result == 0; + self.flag.carry = source_value & (1 << 0) != 0; + } + } + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + + Instruction::Bse(size, condition, destination, source) => { + let (source_value, mut instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match destination { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + let result = self.register[register] as u8 | (1 << source_value); + if should_run { + self.register[register] = (self.register[register] & 0xFFFFFF00) | (result as u32); + } + } + Size::Half => { + let result = self.register[register] as u16 | (1 << source_value); + if should_run { + self.register[register] = (self.register[register] & 0xFFFF0000) | (result as u32); + } + } + Size::Word => { + let result = self.register[register] | (1 << source_value); + if should_run { + self.register[register] = result; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer) | (1 << source_value); + if should_run { + self.bus.memory.write_8(pointer, result); + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer) | (1 << source_value); + if should_run { + self.bus.memory.write_16(pointer, result); + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer) | (1 << source_value); + if should_run { + self.bus.memory.write_32(pointer, result); + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer) | (1 << source_value); + if should_run { + self.bus.memory.write_8(pointer, result); + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer) | (1 << source_value); + if should_run { + self.bus.memory.write_16(pointer, result); + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer) | (1 << source_value); + if should_run { + self.bus.memory.write_32(pointer, result); + } + } + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Bcl(size, condition, destination, source) => { + let (source_value, mut instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match destination { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + let result = self.register[register] as u8 & !(1 << source_value); + if should_run { + self.register[register] = (self.register[register] & 0xFFFFFF00) | (result as u32); + } + } + Size::Half => { + let result = self.register[register] as u16 & !(1 << source_value); + if should_run { + self.register[register] = (self.register[register] & 0xFFFF0000) | (result as u32); + } + } + Size::Word => { + let result = self.register[register] & !(1 << source_value); + if should_run { + self.register[register] = result; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer) & !(1 << source_value); + if should_run { + self.bus.memory.write_8(pointer, result); + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer) & !(1 << source_value); + if should_run { + self.bus.memory.write_16(pointer, result); + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer) & !(1 << source_value); + if should_run { + self.bus.memory.write_32(pointer, result); + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer) & !(1 << source_value); + if should_run { + self.bus.memory.write_8(pointer, result); + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer) & !(1 << source_value); + if should_run { + self.bus.memory.write_16(pointer, result); + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer) & !(1 << source_value); + if should_run { + self.bus.memory.write_32(pointer, result); + } + } + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Bts(size, condition, destination, source) => { + let (source_value, mut instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match destination { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + let result = self.register[register] as u8 & (1 << source_value) == 0; + if should_run { + self.flag.zero = result; + } + } + Size::Half => { + let result = self.register[register] as u16 & (1 << source_value) == 0; + if should_run { + self.flag.zero = result; + } + } + Size::Word => { + let result = self.register[register] & (1 << source_value) == 0; + if should_run { + self.flag.zero = result; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer) & (1 << source_value) == 0; + if should_run { + self.flag.zero = result; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer) & (1 << source_value) == 0; + if should_run { + self.flag.zero = result; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer) & (1 << source_value) == 0; + if should_run { + self.flag.zero = result; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer) & (1 << source_value) == 0; + if should_run { + self.flag.zero = result; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer) & (1 << source_value) == 0; + if should_run { + self.flag.zero = result; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer) & (1 << source_value) == 0; + if should_run { + self.flag.zero = result; + } + } + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + + Instruction::Cmp(size, condition, destination, source) => { + let (source_value, mut instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match destination { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + if should_run { + let result = (self.register[register] as u8).overflowing_sub(source_value as u8); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Half => { + if should_run { + let result = (self.register[register] as u16).overflowing_sub(source_value as u16); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Word => { + if should_run { + let result = (self.register[register]).overflowing_sub(source_value); + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer).overflowing_sub(source_value as u8); + if should_run { + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer).overflowing_sub(source_value as u16); + if should_run { + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer).overflowing_sub(source_value); + if should_run { + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + match size { + Size::Byte => { + let result = self.bus.memory.read_8(pointer).overflowing_sub(source_value as u8); + if should_run { + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Half => { + let result = self.bus.memory.read_16(pointer).overflowing_sub(source_value as u16); + if should_run { + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + Size::Word => { + let result = self.bus.memory.read_32(pointer).overflowing_sub(source_value); + if should_run { + self.flag.zero = result.0 == 0; + self.flag.carry = result.1; + } + } + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Mov(size, condition, destination, source) => { + let (source_value, mut instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match destination { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + if should_run { + self.register[register] = (self.register[register] & 0xFFFFFF00) | (source_value & 0x000000FF); + } + } + Size::Half => { + if should_run { + self.register[register] = (self.register[register] & 0xFFFF0000) | (source_value & 0x0000FFFF); + } + } + Size::Word => { + if should_run { + self.register[register] = source_value; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + match size { + Size::Byte => { + if should_run { + self.bus.memory.write_8(pointer, source_value as u8); + } + } + Size::Half => { + if should_run { + self.bus.memory.write_16(pointer, source_value as u16); + } + } + Size::Word => { + if should_run { + self.bus.memory.write_32(pointer, source_value); + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + match size { + Size::Byte => { + if should_run { + self.bus.memory.write_8(pointer, source_value as u8); + } + } + Size::Half => { + if should_run { + self.bus.memory.write_16(pointer, source_value as u16); + } + } + Size::Word => { + if should_run { + self.bus.memory.write_32(pointer, source_value); + } + } + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Movz(size, condition, destination, source) => { + let (source_value, mut instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match destination { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + if should_run { + self.register[register] = source_value & 0x000000FF; + } + } + Size::Half => { + if should_run { + self.register[register] = source_value & 0x0000FFFF; + } + } + Size::Word => { + if should_run { + self.register[register] = source_value; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + _ => panic!("MOVZ only operates on registers"), + } + self.instruction_pointer + instruction_pointer_offset + } + + Instruction::Jmp(condition, source) => { + let (source_value, instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + if should_run { + source_value + } else { + self.instruction_pointer + instruction_pointer_offset + } + } + Instruction::Call(condition, source) => { + let (source_value, instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + if should_run { + self.push_stack_32(self.instruction_pointer + instruction_pointer_offset); + source_value + } else { + self.instruction_pointer + instruction_pointer_offset + } + } + Instruction::Loop(condition, source) => { + let (source_value, instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + let result = self.register[31].overflowing_sub(1); + self.register[31] = result.0; + if should_run { + if result.0 != 0 { + source_value + } else { + self.instruction_pointer + instruction_pointer_offset + } + } else { + self.instruction_pointer + instruction_pointer_offset + } + } + Instruction::Rjmp(condition, source) => { + let (source_value, instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + if should_run { + self.relative_to_absolute(source_value) + } else { + self.instruction_pointer + instruction_pointer_offset + } + } + Instruction::Rcall(condition, source) => { + let (source_value, instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + if should_run { + self.push_stack_32(self.instruction_pointer + instruction_pointer_offset); + self.relative_to_absolute(source_value) + } else { + self.instruction_pointer + instruction_pointer_offset + } + } + Instruction::Rloop(condition, source) => { + let (source_value, instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + let result = self.register[31].overflowing_sub(1); + self.register[31] = result.0; + if should_run { + if result.0 != 0 { + self.relative_to_absolute(source_value) + } else { + self.instruction_pointer + instruction_pointer_offset + } + } else { + self.instruction_pointer + instruction_pointer_offset + } + } + + Instruction::Rta(condition, destination, source) => { + let (source_value, mut instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match destination { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + if should_run { + self.register[register] = self.relative_to_absolute(source_value); + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.relative_to_absolute(self.register[register]); + if should_run { + // INFO: register contains a relative address instead of an absolute address + self.bus.memory.write_32(pointer, self.relative_to_absolute(source_value)); + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.relative_to_absolute(self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset)); + if should_run { + self.bus.memory.write_32(pointer, self.relative_to_absolute(source_value)); + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + + Instruction::Push(size, condition, source) => { + let (source_value, instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match size { + Size::Byte => { + if should_run { + self.push_stack_8(source_value as u8); + } + } + Size::Half => { + if should_run { + self.push_stack_16(source_value as u16); + } + } + Size::Word => { + if should_run { + self.push_stack_32(source_value); + } + } + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Pop(size, condition, source) => { + let mut instruction_pointer_offset = 2; // increment past opcode half + let should_run = self.check_condition(condition); + match source { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + match size { + Size::Byte => { + if should_run { + let value = self.pop_stack_8() as u32; + self.register[register] = (self.register[register] & 0xFFFFFF00) | value; + } + } + Size::Half => { + if should_run { + let value = self.pop_stack_16() as u32; + self.register[register] = (self.register[register] & 0xFFFF0000) | value; + } + } + Size::Word => { + if should_run { + let value = self.pop_stack_32(); + self.register[register] = value; + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + match size { + Size::Byte => { + if should_run { + let value = self.pop_stack_8(); + self.bus.memory.write_8(pointer, value); + } + } + Size::Half => { + if should_run { + let value = self.pop_stack_16(); + self.bus.memory.write_16(pointer, value); + } + } + Size::Word => { + if should_run { + let value = self.pop_stack_32(); + self.bus.memory.write_32(pointer, value); + } + } + } + instruction_pointer_offset += 1; // increment past 8 bit register number + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + match size { + Size::Byte => { + if should_run { + let value = self.pop_stack_8(); + self.bus.memory.write_8(pointer, value); + } + } + Size::Half => { + if should_run { + let value = self.pop_stack_16(); + self.bus.memory.write_16(pointer, value); + } + } + Size::Word => { + if should_run { + let value = self.pop_stack_32(); + self.bus.memory.write_32(pointer, value); + } + } + } + instruction_pointer_offset += 4; // increment past 32 bit pointer + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Ret(condition) => { + let instruction_pointer_offset = 2; // increment past opcode half + let should_run = self.check_condition(condition); + if should_run { + self.pop_stack_32() + } else { + self.instruction_pointer + instruction_pointer_offset + } + } + Instruction::Reti(condition) => { + let instruction_pointer_offset = 2; // increment past opcode half + let should_run = self.check_condition(condition); + if should_run { + self.interrupts_enabled = self.interrupts_paused; + self.interrupts_paused = false; + self.flag = Flag::from(self.pop_stack_8()); + self.pop_stack_32() + } else { + self.instruction_pointer + instruction_pointer_offset + } + } + + Instruction::In(condition, destination, source) => { + let (source_value, mut instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match destination { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let value = self.bus.read_io(source_value); + instruction_pointer_offset += 1; // increment past 8 bit register number + if should_run { + self.register[register] = value; + } + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + let value = self.bus.read_io(source_value); + instruction_pointer_offset += 1; // increment past 8 bit register number + if should_run { + self.bus.memory.write_32(pointer, value); + } + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + let value = self.bus.read_io(source_value); + instruction_pointer_offset += 4; // increment past 32 bit pointer + if should_run { + self.bus.memory.write_32(pointer, value); + } + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Out(condition, destination, source) => { + let (source_value, mut instruction_pointer_offset) = self.read_source(source); + let should_run = self.check_condition(condition); + match destination { + Operand::Register => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + instruction_pointer_offset += 1; // increment past 8 bit register number + if should_run { + self.bus.write_io(self.register[register], source_value); + } + } + Operand::RegisterPtr => { + let register = self.bus.memory.read_8(self.instruction_pointer + instruction_pointer_offset) as usize; + let pointer = self.register[register]; + instruction_pointer_offset += 1; // increment past 8 bit register number + if should_run { + self.bus.write_io(self.bus.memory.read_32(pointer), source_value); + } + } + Operand::ImmediatePtr => { + let pointer = self.bus.memory.read_32(self.instruction_pointer + instruction_pointer_offset); + instruction_pointer_offset += 4; // increment past 32 bit pointer + if should_run { + self.bus.write_io(self.bus.memory.read_32(pointer), source_value); + } + } + _ => panic!("Attempting to use an immediate value as a destination"), + } + self.instruction_pointer + instruction_pointer_offset + } + + Instruction::Ise(condition) => { + let instruction_pointer_offset = 2; // increment past opcode half + let should_run = self.check_condition(condition); + if should_run { + self.interrupts_enabled = true; + self.interrupts_paused = false; + } + self.instruction_pointer + instruction_pointer_offset + } + Instruction::Icl(condition) => { + let instruction_pointer_offset = 2; // increment past opcode half + let should_run = self.check_condition(condition); + if should_run { + self.interrupts_enabled = false; + self.interrupts_paused = false; + } + self.instruction_pointer + instruction_pointer_offset + } + } + } +} + +// TODO: separate Immediate into Immediate8, Immediate16, and Immediate32 +#[derive(Debug)] +enum Operand { + Register, + RegisterPtr, + Immediate8, + Immediate16, + Immediate32, + ImmediatePtr, +} + +#[derive(Debug)] +enum Size { + Byte, + Half, + Word, +} + +#[derive(Debug)] +enum Condition { + Always, + Zero, + NotZero, + Carry, + NotCarry, +} + +#[derive(Debug)] +enum Instruction { + Nop(), + Halt(Condition), + Brk(Condition), + + Add(Size, Condition, Operand, Operand), + Inc(Size, Condition, Operand), + Sub(Size, Condition, Operand, Operand), + Dec(Size, Condition, Operand), + + Mul(Size, Condition, Operand, Operand), + Pow(Size, Condition, Operand, Operand), + Div(Size, Condition, Operand, Operand), + Rem(Size, Condition, Operand, Operand), + + And(Size, Condition, Operand, Operand), + Or(Size, Condition, Operand, Operand), + Xor(Size, Condition, Operand, Operand), + Not(Size, Condition, Operand), + + Sla(Size, Condition, Operand, Operand), + Rol(Size, Condition, Operand, Operand), + + Sra(Size, Condition, Operand, Operand), + Srl(Size, Condition, Operand, Operand), + Ror(Size, Condition, Operand, Operand), + + Bse(Size, Condition, Operand, Operand), + Bcl(Size, Condition, Operand, Operand), + Bts(Size, Condition, Operand, Operand), + + Cmp(Size, Condition, Operand, Operand), + Mov(Size, Condition, Operand, Operand), + Movz(Size, Condition, Operand, Operand), + + Jmp(Condition, Operand), + Call(Condition, Operand), + Loop(Condition, Operand), + + Rjmp(Condition, Operand), + Rcall(Condition, Operand), + Rloop(Condition, Operand), + + Rta(Condition, Operand, Operand), + + Push(Size, Condition, Operand), + Pop(Size, Condition, Operand), + Ret(Condition), + Reti(Condition), + + In(Condition, Operand, Operand), + Out(Condition, Operand, Operand), + + Ise(Condition), + Icl(Condition), +} + +impl Instruction { + fn from_half(half: u16) -> Option { + // see encoding.md for more info + let size = match ((half >> 14) as u8) & 0b00000011 { + 0x00 => Size::Byte, + 0x01 => Size::Half, + 0x02 => Size::Word, + _ => return None, + }; + let opcode = ((half >> 8) as u8) & 0b00111111; + let source = match ((half & 0x000F) as u8) & 0b00000011 { + 0x00 => Operand::Register, + 0x01 => Operand::RegisterPtr, + 0x02 => match size { + Size::Byte => Operand::Immediate8, + Size::Half => Operand::Immediate16, + Size::Word => Operand::Immediate32, + }, + 0x03 => Operand::ImmediatePtr, + _ => return None, + }; + let destination = match (((half & 0x000F) >> 2) as u8) & 0b00000011 { + 0x00 => Operand::Register, + 0x01 => Operand::RegisterPtr, + 0x02 => Operand::ImmediatePtr, + _ => return None, + }; + let condition = match (half & 0x00F0) as u8 { + 0x00 => Condition::Always, + 0x10 => Condition::Zero, + 0x20 => Condition::NotZero, + 0x30 => Condition::Carry, + 0x40 => Condition::NotCarry, + _ => return None, + }; + match opcode { + 0x00 => Some(Instruction::Nop()), + 0x10 => Some(Instruction::Halt(condition)), + 0x20 => Some(Instruction::Brk(condition)), + + 0x01 => Some(Instruction::Add(size, condition, destination, source)), + 0x11 => Some(Instruction::Inc(size, condition, source)), + 0x21 => Some(Instruction::Sub(size, condition, destination, source)), + 0x31 => Some(Instruction::Dec(size, condition, source)), + + 0x02 => Some(Instruction::Mul(size, condition, destination, source)), + 0x12 => Some(Instruction::Pow(size, condition, destination, source)), + 0x22 => Some(Instruction::Div(size, condition, destination, source)), + 0x32 => Some(Instruction::Rem(size, condition, destination, source)), + + 0x03 => Some(Instruction::And(size, condition, destination, source)), + 0x13 => Some(Instruction::Or(size, condition, destination, source)), + 0x23 => Some(Instruction::Xor(size, condition, destination, source)), + 0x33 => Some(Instruction::Not(size, condition, source)), + + 0x04 => Some(Instruction::Sla(size, condition, destination, source)), + 0x24 => Some(Instruction::Rol(size, condition, destination, source)), + + 0x05 => Some(Instruction::Sra(size, condition, destination, source)), + 0x15 => Some(Instruction::Srl(size, condition, destination, source)), + 0x25 => Some(Instruction::Ror(size, condition, destination, source)), + + 0x06 => Some(Instruction::Bse(size, condition, destination, source)), + 0x16 => Some(Instruction::Bcl(size, condition, destination, source)), + 0x26 => Some(Instruction::Bts(size, condition, destination, source)), + + 0x07 => Some(Instruction::Cmp(size, condition, destination, source)), + 0x17 => Some(Instruction::Mov(size, condition, destination, source)), + 0x27 => Some(Instruction::Movz(size, condition, destination, source)), + + 0x08 => Some(Instruction::Jmp(condition, source)), + 0x18 => Some(Instruction::Call(condition, source)), + 0x28 => Some(Instruction::Loop(condition, source)), + + 0x09 => Some(Instruction::Rjmp(condition, source)), + 0x19 => Some(Instruction::Rcall(condition, source)), + 0x29 => Some(Instruction::Rloop(condition, source)), + + 0x39 => Some(Instruction::Rta(condition, destination, source)), + + 0x0A => Some(Instruction::Push(size, condition, source)), + 0x1A => Some(Instruction::Pop(size, condition, source)), + 0x2A => Some(Instruction::Ret(condition)), + 0x3A => Some(Instruction::Reti(condition)), + + 0x0B => Some(Instruction::In(condition, destination, source)), + 0x1B => Some(Instruction::Out(condition, destination, source)), + + 0x0C => Some(Instruction::Ise(condition)), + 0x1C => Some(Instruction::Icl(condition)), + + _ => None, + } + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..53724d9 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,421 @@ +// main.rs + +pub mod cpu; +pub mod mouse; +use cpu::{Bus, CPU, Memory, Interrupt, IO}; +use mouse::Mouse; + +use std::convert::TryInto; +use std::env; +use std::fs::read; +//use std::process::exit; +use std::sync::{Arc, mpsc, Mutex}; +use std::io::{stdout, Write}; +use std::thread; + +use log::error; +use pixels::{Pixels, SurfaceTexture}; +use winit::dpi::LogicalSize; +use winit::event::{Event, VirtualKeyCode}; +use winit::event_loop::{ControlFlow, EventLoop}; +use winit::window::WindowBuilder; +use winit_input_helper::WinitInputHelper; + +use rodio::{OutputStream, buffer::SamplesBuffer, Sink}; + +const WIDTH: usize = 640; +const HEIGHT: usize = 480; + +pub struct Display { + background: Vec, + overlays: Arc>>, +} + +#[derive(Copy, Clone, Debug, Default)] +pub struct Overlay { + enabled: bool, + width: usize, + height: usize, + x: usize, + y: usize, + framebuffer_pointer: u32, +} + +impl IO for Bus { + fn read_io(&mut self, port: u32) -> u32 { + match port { + 0x02000000..=0x0200031F => { // overlay port + let overlay_lock = self.memory.overlays.lock().unwrap(); + let overlay_number = (port & 0x000000FF) as usize; + let setting = (port & 0x0000FF00) >> 8; + + match setting { + 0x00 => { + // we're reading the position of this overlay + let x = overlay_lock[overlay_number].x as u32; + let y = overlay_lock[overlay_number].y as u32; + (y << 16) | x + } + 0x01 => { + // we're reading the size of this overlay + let width = overlay_lock[overlay_number].width as u32; + let height = overlay_lock[overlay_number].height as u32; + (height << 16) | width + } + 0x02 => { + // we're reading the framebuffer pointer of this overlay + overlay_lock[overlay_number].framebuffer_pointer + 0x02000000 + } + 0x03 => { + // we're reading the enable status of this overlay + overlay_lock[overlay_number].enabled as u32 + } + _ => panic!("invalid overlay control port"), + } + } + 0x02000400..=0x02000401 => { // mouse port + let setting = (port & 0x000000FF) as u8; + match setting { + 0x00 => { + // we're reading the button states + let mut byte: u8 = 0x00; + let mut mouse_lock = self.mouse.lock().expect("failed to lock the mouse mutex"); + if mouse_lock.click { + byte |= 0b01; + mouse_lock.click = false; + } + if mouse_lock.held { + byte |= 0b10; + } else { + byte &= !0b10; + } + byte as u32 + } + 0x01 => { + // we're reading the position + let mouse_lock = self.mouse.lock().expect("failed to lock the mouse mutex"); + let x = mouse_lock.x as u32; + let y = mouse_lock.y as u32; + (y << 16) | x + } + _ => panic!("invalid mouse control port"), + } + } + _ => 0, + } + } + fn write_io(&mut self, port: u32, word: u32) { + match port { + 0x00000000 => { // terminal output port + print!("{}", word as u8 as char); + stdout().flush().expect("could not flush stdout"); + } + 0x02000000..=0x0200031F => { // overlay port + let mut overlay_lock = self.memory.overlays.lock().unwrap(); + let overlay_number = (port & 0x000000FF) as usize; + let setting = (port & 0x0000FF00) >> 8; + + match setting { + 0x00 => { + // we're setting the position of this overlay + let x = (word & 0x0000FFFF) as usize; + let y = ((word & 0xFFFF0000) >> 16) as usize; + overlay_lock[overlay_number].x = x; + overlay_lock[overlay_number].y = y; + } + 0x01 => { + // we're setting the size of this overlay + let width = (word & 0x0000FFFF) as usize; + let height = ((word & 0xFFFF0000) >> 16) as usize; + overlay_lock[overlay_number].width = width; + overlay_lock[overlay_number].height = height; + } + 0x02 => { + // we're setting the framebuffer pointer of this overlay + if word < 0x02000000 { + panic!("overlay framebuffer must be within shared memory"); + } + overlay_lock[overlay_number].framebuffer_pointer = word - 0x02000000; + } + 0x03 => { + // we're setting the enable status of this overlay + overlay_lock[overlay_number].enabled = word != 0; + } + _ => panic!("invalid overlay control port"), + } + } + 0x02000320 => { // audio port + if word < 0x02000000 { + panic!("audio buffer must be within shared memory"); + } + let address = word as usize - 0x02000000; + let shared_memory_lock = self.memory.shared_memory.lock().unwrap(); + + let length = u32::from_le_bytes(shared_memory_lock[address..address+4].try_into().unwrap()) as usize; + let start_address = address + 4; + let end_address = start_address + length; + + let audio_data: Vec = shared_memory_lock[start_address..end_address].to_vec().chunks_exact(2).map(|x| ((x[1] as i16) << 8) | x[0] as i16).collect(); + let builder = thread::Builder::new().name("audio".to_string()); + builder.spawn({ + move || { + let buffer = SamplesBuffer::new(1, 44100, audio_data); + let (_stream, stream_handle) = OutputStream::try_default().unwrap(); + let sink = Sink::try_new(&stream_handle).unwrap(); + sink.append(buffer); + sink.sleep_until_end(); + } + }).unwrap(); + } + 0x02000400..=0x02000401 => { // mouse port + let setting = (port & 0x000000FF) as u8; + match setting { + 0x00 => { + // we're setting the button states + let mut mouse_lock = self.mouse.lock().expect("failed to lock the mouse mutex"); + mouse_lock.click = word & (1 << 0) != 0; + mouse_lock.held = word & (1 << 1) != 0; + } + 0x01 => { + // we're setting the position + let mut mouse_lock = self.mouse.lock().expect("failed to lock the mouse mutex"); + let x = (word & 0x0000FFFF) as u16; + let y = ((word & 0xFFFF0000) >> 16) as u16; + mouse_lock.x = x; + mouse_lock.y = y; + } + _ => panic!("invalid mouse control port"), + } + } + _ => return, + } + } +} + +fn main() { + let args: Vec = env::args().collect(); + /*if args.len() != 2 { + println!("fox32\nUsage: {} ", &args[0]); + exit(1); + }*/ + + let mut display = Display::new(); + let mouse = Arc::new(Mutex::new(Mouse::new())); + + // 32 MiB of shared memory + // add some "bonus bytes" at the end of memory to prevent dumb errors - (lua was here) + // see the ImmediatePtr match arm in read_source() in cpu.rs for more info + // basically all immediate pointers read 32 bits, even if the opcode size is smaller + // so attempting to read something like the last byte of shared memory (0x03FFFFFF) would previously panic + let shared_memory = Arc::new(Mutex::new(vec![0u8; 0x0200000F])); + + let mut cpu = { + let cpu_shared_memory = Arc::clone(&shared_memory); + let cpu_overlays = Arc::clone(&display.overlays); + //let cpu_read_only_memory = include_bytes!("../rom.bin").to_vec(); + let cpu_read_only_memory = read("rom.bin").unwrap(); + // 32 MiB of CPU-only memory + let memory = Memory::new(0x02000000, cpu_shared_memory, cpu_overlays, cpu_read_only_memory); + + let cpu_mouse = Arc::clone(&mouse); + + let bus = Bus { memory, mouse: cpu_mouse }; + CPU::new(bus) + }; + + if args.len() >= 2 { + let input_file_name = &args[1]; + let opcodes = read(input_file_name).unwrap(); + //println!("{:02X?}", opcodes); + let mut address = 0u32; + for byte in opcodes.iter() { + cpu.bus.memory.write_8(address, *byte); + address += 1; + } + } + + let event_loop = EventLoop::new(); + let mut input = WinitInputHelper::new(); + let window = { + let size = LogicalSize::new(WIDTH as f64, HEIGHT as f64); + WindowBuilder::new() + .with_title("fox32") + .with_inner_size(size) + .with_min_inner_size(size) + .build(&event_loop) + .unwrap() + }; + + window.set_cursor_visible(false); + + let mut pixels = { + let window_size = window.inner_size(); + let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, &window); + Pixels::new(WIDTH as u32, HEIGHT as u32, surface_texture).unwrap() + }; + + let (interrupt_sender, interrupt_receiver) = mpsc::channel::(); + + let builder = thread::Builder::new().name("cpu".to_string()); + builder.spawn({ + move || { + loop { + while !cpu.halted { + if let Ok(interrupt) = interrupt_receiver.try_recv() { + cpu.interrupt(interrupt); + } + cpu.execute_memory_instruction(); + } + if !cpu.interrupts_enabled { + // the cpu was halted and interrupts are disabled + // at this point, the cpu is dead and cannot resume, break out of the loop + break; + } + if let Ok(interrupt) = interrupt_receiver.recv() { + cpu.halted = false; + cpu.interrupt(interrupt); + } else { + // sender is closed, break + break; + } + } + println!("CPU halted"); + } + }).unwrap(); + + event_loop.run(move |event, _, control_flow| { + *control_flow = ControlFlow::Poll; + + // draw the current frame + if let Event::MainEventsCleared = event { + // update internal state and request a redraw + + let mut shared_memory_lock = shared_memory.lock().expect("failed to lock the shared memory mutex"); + //shared_memory_lock[0x01FFFFFF] = shared_memory_lock[0x01FFFFFF].overflowing_add(1).0; // increment vsync counter + let _ = interrupt_sender.send(Interrupt::Request(0xFF)); // vsync interrupt + display.update(&mut *shared_memory_lock); + drop(shared_memory_lock); + window.request_redraw(); + + display.draw(pixels.get_frame()); + if pixels + .render() + .map_err(|e| error!("pixels.render() failed: {}", e)) + .is_err() + { + *control_flow = ControlFlow::Exit; + return; + } + } + + // handle input events + if input.update(&event) { + // close events + if input.key_pressed(VirtualKeyCode::Escape) || input.quit() { + *control_flow = ControlFlow::Exit; + return; + } + + // resize the window + if let Some(size) = input.window_resized() { + pixels.resize_surface(size.width, size.height); + } + + let mouse_pixel = input.mouse().map(|(mx, my)| { + let (x, y) = pixels.window_pos_to_pixel((mx, my)).unwrap_or_else(|pos| pixels.clamp_pixel_pos(pos)); + (x as u16, y as u16) + }).unwrap_or_default(); + + // TODO: allow right click + let mut mouse_lock = mouse.lock().expect("failed to lock the mouse mutex"); + mouse_lock.x = mouse_pixel.0; + mouse_lock.y = mouse_pixel.1; + mouse_lock.held = input.mouse_held(0); + if input.mouse_pressed(0) { + println!("Mouse click at {:?}", mouse_pixel); + mouse_lock.click = true; + } + } + }); +} + +impl Display { + fn new() -> Self { + Self { + background: vec![0; (HEIGHT*WIDTH*4) as usize], + overlays: Arc::new(Mutex::new(vec![Overlay { enabled: false, width: 16, height: 16, x: 0, y: 0, framebuffer_pointer: 0 }; 32])), + } + } + + fn update(&mut self, shared_memory: &mut [u8]) { + let overlay_lock = self.overlays.lock().unwrap(); + + for i in 0..(HEIGHT*WIDTH*4) as usize { + self.background[i] = shared_memory[i]; + } + + for index in 0..=31 { + if overlay_lock[index].enabled { + blit_overlay(&mut self.background, &overlay_lock[index], shared_memory); + } + } + } + + fn draw(&self, frame: &mut [u8]) { + for (i, pixel) in frame.chunks_exact_mut(4).enumerate() { + //let x = (i % WIDTH as usize) as i16; + //let y = (i / WIDTH as usize) as i16; + + let i = i * 4; + + let slice = &self.background[i..i+4]; + pixel.copy_from_slice(slice); + } + } +} + +// modified from https://github.com/parasyte/pixels/blob/main/examples/invaders/simple-invaders/src/sprites.rs +fn blit_overlay(framebuffer: &mut [u8], overlay: &Overlay, shared_memory: &mut [u8]) { + //assert!(overlay.x + overlay.width <= WIDTH); + //assert!(overlay.y + overlay.height <= HEIGHT); + + let mut width = overlay.width * 4; + let mut height = overlay.height; + + // FIXME: this is a hack, and it only allows overlays to go off-screen on the bottom and right sides + // it also completely fucks up the image on the right side :p + if overlay.x + overlay.width > WIDTH { + let difference = (overlay.x + overlay.width) - WIDTH; + width = width - (difference * 4); + //println!("width: {}, difference: {}", width, difference); + } + if overlay.y + overlay.height > HEIGHT { + let difference = (overlay.y + overlay.height) - HEIGHT; + height = height - difference; + //println!("height: {}, difference: {}", height, difference); + } + + let overlay_framebuffer = &shared_memory[overlay.framebuffer_pointer as usize..(overlay.framebuffer_pointer+((width as u32)*(height as u32))) as usize]; + + let mut overlay_framebuffer_index = 0; + for y in 0..height { + let index = overlay.x * 4 + overlay.y * WIDTH * 4 + y * WIDTH * 4; + // merge overlay onto screen + // this is such a dumb hack + let mut zipped = framebuffer[index..index + width].iter_mut().zip(&overlay_framebuffer[overlay_framebuffer_index..overlay_framebuffer_index + width]); + while let Some((left, &right)) = zipped.next() { + let (left_0, &right_0) = (left, &right); + let (left_1, &right_1) = zipped.next().unwrap(); + let (left_2, &right_2) = zipped.next().unwrap(); + let (left_3, &right_3) = zipped.next().unwrap(); + // ensure that the alpha byte is greater than zero, meaning that this pixel shouldn't be transparent + if right_3 > 0 { + *left_0 = right_0; + *left_1 = right_1; + *left_2 = right_2; + *left_3 = right_3; + } + } + overlay_framebuffer_index += width; + } +} diff --git a/src/mouse.rs b/src/mouse.rs new file mode 100644 index 0000000..6ae653d --- /dev/null +++ b/src/mouse.rs @@ -0,0 +1,14 @@ +// mouse.rs + +pub struct Mouse { + pub x: u16, + pub y: u16, + pub click: bool, + pub held: bool, +} + +impl Mouse { + pub fn new() -> Self { + Mouse { x: 0, y: 0, click: false, held: false } + } +} \ No newline at end of file