diff --git a/.gitignore b/.gitignore index e76d8cd..a2191a0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ /target .idea .vscode/ +.zed roms TODO.md .fpt_debug_history diff --git a/Cargo.lock b/Cargo.lock index 1c56ff7..f69ce55 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "ab_glyph" -version = "0.2.23" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80179d7dd5d7e8c285d67c4a1e652972a92de7475beddfb92028c76463b13225" +checksum = "6f90148830dac590fac7ccfe78ec4a8ea404c60f75a24e16407a71f0f40de775" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -39,9 +39,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -53,7 +53,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289" dependencies = [ "android-properties", - "bitflags 2.4.2", + "bitflags 2.5.0", "cc", "cesu8", "jni", @@ -75,47 +75,48 @@ checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" [[package]] name = "anstream" -version = "0.6.13" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -123,17 +124,16 @@ dependencies = [ [[package]] name = "arboard" -version = "3.3.2" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2041f1943049c7978768d84e6d0fd95de98b76d6c4727b09e78ec253d29fa58" +checksum = "9fb4009533e8ff8f1450a5bcbc30f4242a1d34442221f72314bea1f5dc9c7f89" dependencies = [ "clipboard-win", "log", - "objc", - "objc-foundation", - "objc_id", + "objc2 0.5.1", + "objc2-app-kit", + "objc2-foundation", "parking_lot", - "thiserror", "x11rb", ] @@ -151,9 +151,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "bitflags" @@ -163,9 +163,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "block" @@ -189,20 +189,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15b55663a85f33501257357e6421bb33e769d5c9ffb5ba0921c975a123e35e68" dependencies = [ "block-sys", - "objc2", + "objc2 0.4.1", +] + +[[package]] +name = "block2" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43ff7d91d3c1d568065b06c899777d1e48dcf76103a672a0adbc238a7f247f1e" +dependencies = [ + "objc2 0.5.1", ] [[package]] name = "bumpalo" -version = "3.15.4" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.14.3" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f" +checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" dependencies = [ "bytemuck_derive", ] @@ -226,9 +235,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "calloop" @@ -236,7 +245,7 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "log", "polling", "rustix", @@ -258,12 +267,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.90" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "065a29261d53ba54260972629f9ca6bffa69bac13cd1fed61420f7fa68b9f8bd" dependencies = [ "jobserver", "libc", + "once_cell", ] [[package]] @@ -293,51 +303,11 @@ dependencies = [ "libc", ] -[[package]] -name = "clap" -version = "4.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b230ab84b0ffdf890d5a10abdbc8b83ae1c4918275daea1ab8801f71536b2651" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" - [[package]] name = "clipboard-win" -version = "5.2.0" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f9a0700e0127ba15d1d52dd742097f821cd9c65939303a44d970465040a297" +checksum = "79f4473f5144e20d9aceaf2972478f06ddf687831eafeeb434fbaf0acc4144ad" dependencies = [ "error-code", ] @@ -380,15 +350,15 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "combine" -version = "4.6.6" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ "bytes", "memchr", @@ -396,9 +366,9 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] @@ -421,9 +391,9 @@ checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "core-graphics" -version = "0.23.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "970a29baf4110c26fedbc7f82107d42c23f7e88e404c4577ed73fe99ff85a212" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -490,9 +460,9 @@ dependencies = [ [[package]] name = "downcast-rs" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" [[package]] name = "ecolor" @@ -525,7 +495,7 @@ dependencies = [ "parking_lot", "percent-encoding", "raw-window-handle 0.5.2", - "raw-window-handle 0.6.0", + "raw-window-handle 0.6.1", "static_assertions", "thiserror", "wasm-bindgen", @@ -557,7 +527,7 @@ dependencies = [ "arboard", "egui", "log", - "raw-window-handle 0.6.0", + "raw-window-handle 0.6.1", "smithay-clipboard", "web-time", "webbrowser", @@ -588,12 +558,6 @@ dependencies = [ "bytemuck", ] -[[package]] -name = "endian-type" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" - [[package]] name = "env_filter" version = "0.1.0" @@ -655,17 +619,6 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" -[[package]] -name = "fd-lock" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947" -dependencies = [ - "cfg-if", - "rustix", - "windows-sys 0.52.0", -] - [[package]] name = "fdeflate" version = "0.3.4" @@ -677,9 +630,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.28" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "miniz_oxide", @@ -728,16 +681,6 @@ dependencies = [ "rstest", ] -[[package]] -name = "fpt-cli" -version = "0.1.0" -dependencies = [ - "clap", - "fpt", - "hlua", - "rustyline", -] - [[package]] name = "fpt-egui" version = "0.1.0" @@ -746,7 +689,6 @@ dependencies = [ "egui", "env_logger", "fpt", - "fpt-cli", "js-sys", "log", "wasm-bindgen", @@ -861,9 +803,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", "libc", @@ -905,7 +847,7 @@ version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18fcd4ae4e86d991ad1300b8f57166e5be0c95ef1f63f3f5b827f8a164548746" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "cfg_aliases", "cgl", "core-foundation", @@ -915,7 +857,7 @@ dependencies = [ "glutin_wgl_sys", "icrate", "libloading", - "objc2", + "objc2 0.4.1", "once_cell", "raw-window-handle 0.5.2", "wayland-sys", @@ -966,25 +908,15 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" - -[[package]] -name = "heck" -version = "0.4.1" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] -name = "hlua" -version = "0.4.1" +name = "hermit-abi" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9db71fff2e55b83d24bbbdd9ad13f0d1ff79bc265f544370f39ee0825d54e4" -dependencies = [ - "libc", - "lua52-sys", -] +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "home" @@ -1007,9 +939,9 @@ version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d3aaff8a54577104bafdf686ff18565c3b6903ca5782a2026ef06e2c7aa319" dependencies = [ - "block2", + "block2 0.3.0", "dispatch", - "objc2", + "objc2 0.4.1", ] [[package]] @@ -1037,14 +969,20 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.5" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + [[package]] name = "jni" version = "0.21.1" @@ -1069,9 +1007,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.28" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" dependencies = [ "libc", ] @@ -1093,9 +1031,9 @@ checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" [[package]] name = "libloading" @@ -1104,7 +1042,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -1113,7 +1051,7 @@ version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "libc", "redox_syscall 0.4.1", ] @@ -1132,9 +1070,9 @@ checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -1146,17 +1084,6 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" -[[package]] -name = "lua52-sys" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d451db153c94e455dc817d388f9674f6232425c28db3509e90251c55b8df2f94" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - [[package]] name = "malloc_buf" version = "0.0.6" @@ -1168,9 +1095,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "memmap2" @@ -1183,9 +1110,9 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ "autocfg", ] @@ -1206,13 +1133,13 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "jni-sys", "log", "ndk-sys", "num_enum", "raw-window-handle 0.5.2", - "raw-window-handle 0.6.0", + "raw-window-handle 0.6.1", "thiserror", ] @@ -1231,26 +1158,6 @@ dependencies = [ "jni-sys", ] -[[package]] -name = "nibble_vec" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" -dependencies = [ - "smallvec", -] - -[[package]] -name = "nix" -version = "0.27.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" -dependencies = [ - "bitflags 2.4.2", - "cfg-if", - "libc", -] - [[package]] name = "nohash-hasher" version = "0.2.0" @@ -1259,9 +1166,9 @@ checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -1296,22 +1203,11 @@ dependencies = [ "malloc_buf", ] -[[package]] -name = "objc-foundation" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" -dependencies = [ - "block", - "objc", - "objc_id", -] - [[package]] name = "objc-sys" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c71324e4180d0899963fc83d9d241ac39e699609fc1025a850aadac8257459" +checksum = "da284c198fb9b7b0603f8635185e85fbd5b64ee154b1ed406d489077de2d6d60" [[package]] name = "objc2" @@ -1320,7 +1216,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d" dependencies = [ "objc-sys", - "objc2-encode", + "objc2-encode 3.0.0", +] + +[[package]] +name = "objc2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b25e1034d0e636cd84707ccdaa9f81243d399196b8a773946dcffec0401659" +dependencies = [ + "objc-sys", + "objc2-encode 4.0.1", +] + +[[package]] +name = "objc2-app-kit" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb79768a710a9a1798848179edb186d1af7e8a8679f369e4b8d201dd2a034047" +dependencies = [ + "block2 0.5.0", + "objc2 0.5.1", + "objc2-core-data", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e092bc42eaf30a08844e6a076938c60751225ec81431ab89f5d1ccd9f958d6c" +dependencies = [ + "block2 0.5.0", + "objc2 0.5.1", + "objc2-foundation", ] [[package]] @@ -1330,12 +1259,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" [[package]] -name = "objc_id" -version = "0.1.1" +name = "objc2-encode" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +checksum = "88658da63e4cc2c8adb1262902cd6af51094df0488b760d6fd27194269c0950a" + +[[package]] +name = "objc2-foundation" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfaefe14254871ea16c7d88968c0ff14ba554712a20d76421eec52f0a7fb8904" dependencies = [ - "objc", + "block2 0.5.0", + "objc2 0.5.1", ] [[package]] @@ -1364,9 +1300,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" dependencies = [ "lock_api", "parking_lot_core", @@ -1374,15 +1310,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.5", ] [[package]] @@ -1393,9 +1329,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -1424,12 +1360,13 @@ dependencies = [ [[package]] name = "polling" -version = "3.5.0" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24f040dee2588b4963afb4e420540439d126f73fdacf4a9c486a96d840bac3c9" +checksum = "645493cf344456ef24219d02a768cf1fb92ddf8c92161679ae3d91b91a637be3" dependencies = [ "cfg-if", "concurrent-queue", + "hermit-abi", "pin-project-lite", "rustix", "tracing", @@ -1447,9 +1384,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] @@ -1465,23 +1402,13 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] -[[package]] -name = "radix_trie" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" -dependencies = [ - "endian-type", - "nibble_vec", -] - [[package]] name = "raw-window-handle" version = "0.5.2" @@ -1490,9 +1417,9 @@ checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" [[package]] name = "raw-window-handle" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544" +checksum = "8cc3bcbdb1ddfc11e700e62968e6b4cc9c75bb466464ad28fb61c5b2c964418b" [[package]] name = "redox_syscall" @@ -1512,11 +1439,20 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +dependencies = [ + "bitflags 2.5.0", +] + [[package]] name = "regex" -version = "1.10.3" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", @@ -1537,15 +1473,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "relative-path" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e898588f33fdd5b9420719948f9f2a32c922a246964576f71ba7f24f80610fbc" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" [[package]] name = "rstest" @@ -1587,39 +1523,17 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.31" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "errno", "libc", "linux-raw-sys", "windows-sys 0.52.0", ] -[[package]] -name = "rustyline" -version = "13.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02a2d683a4ac90aeef5b1013933f6d977bd37d51ff3f4dad829d4931a7e6be86" -dependencies = [ - "bitflags 2.4.2", - "cfg-if", - "clipboard-win", - "fd-lock", - "home", - "libc", - "log", - "memchr", - "nix", - "radix_trie", - "unicode-segmentation", - "unicode-width", - "utf8parse", - "winapi", -] - [[package]] name = "same-file" version = "1.0.6" @@ -1649,18 +1563,18 @@ checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.200" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.200" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb" dependencies = [ "proc-macro2", "quote", @@ -1693,9 +1607,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smithay-client-toolkit" @@ -1703,7 +1617,7 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "calloop", "calloop-wayland-source", "cursor-icon", @@ -1748,17 +1662,11 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "strsim" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" - [[package]] name = "syn" -version = "2.0.52" +version = "2.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" dependencies = [ "proc-macro2", "quote", @@ -1767,18 +1675,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" dependencies = [ "proc-macro2", "quote", @@ -1866,12 +1774,6 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" -[[package]] -name = "unicode-width" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" - [[package]] name = "url" version = "2.5.0" @@ -1997,7 +1899,7 @@ version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82fb96ee935c2cea6668ccb470fb7771f6215d1691746c2d896b447a00ad3f1f" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "rustix", "wayland-backend", "wayland-scanner", @@ -2009,7 +1911,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "cursor-icon", "wayland-backend", ] @@ -2031,7 +1933,7 @@ version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "wayland-backend", "wayland-client", "wayland-scanner", @@ -2043,7 +1945,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -2056,7 +1958,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "wayland-backend", "wayland-client", "wayland-protocols", @@ -2108,9 +2010,9 @@ dependencies = [ [[package]] name = "webbrowser" -version = "0.8.13" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1b04c569c83a9bb971dd47ec6fd48753315f4bf989b9b04a2e7ca4d7f0dc950" +checksum = "db67ae75a9405634f5882791678772c94ff5f16a66535aae186e26aa0841fc8b" dependencies = [ "core-foundation", "home", @@ -2141,11 +2043,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -2178,7 +2080,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -2213,17 +2115,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -2240,9 +2143,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -2258,9 +2161,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -2276,9 +2179,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -2294,9 +2203,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -2312,9 +2221,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -2330,9 +2239,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -2348,20 +2257,20 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winit" -version = "0.29.14" +version = "0.29.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a3db69ffbe53a9babec7804da7a90f21020fcce1f2f5e5291e2311245b993d" +checksum = "0d59ad965a635657faf09c8f062badd885748428933dad8e8bdd64064d92e5ca" dependencies = [ "ahash", "android-activity", "atomic-waker", - "bitflags 2.4.2", + "bitflags 2.5.0", "bytemuck", "calloop", "cfg_aliases", @@ -2375,12 +2284,12 @@ dependencies = [ "memmap2", "ndk", "ndk-sys", - "objc2", + "objc2 0.4.1", "once_cell", "orbclient", "percent-encoding", "raw-window-handle 0.5.2", - "raw-window-handle 0.6.0", + "raw-window-handle 0.6.1", "redox_syscall 0.3.5", "rustix", "smithay-client-toolkit", @@ -2422,9 +2331,9 @@ dependencies = [ [[package]] name = "x11rb" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f25ead8c7e4cba123243a6367da5d3990e0d3affa708ea19dce96356bd9f1a" +checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" dependencies = [ "as-raw-xcb-connection", "gethostname", @@ -2437,9 +2346,9 @@ dependencies = [ [[package]] name = "x11rb-protocol" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e63e71c4b8bd9ffec2c963173a4dc4cbde9ee96961d4fcb4429db9929b606c34" +checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" [[package]] name = "xcursor" @@ -2453,7 +2362,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "dlib", "log", "once_cell", @@ -2468,24 +2377,24 @@ checksum = "054a8e68b76250b253f671d1268cb7f1ae089ec35e195b2efb2a4e9a836d0621" [[package]] name = "xml-rs" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" +checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "087eca3c1eaf8c47b94d02790dd086cd594b912d2043d4de4bfdd466b3befb7c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "6f4b6c273f496d8fd4eaf18853e6b448760225dc030ff2c485a786859aea6393" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index b8ad9b4..6ebd16a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,5 @@ resolver = "2" members = [ "fpt", - "fpt-cli", "fpt-egui", ] diff --git a/README.md b/README.md index ad5c1ed..e0abf32 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ Natively: `cargo run -p fpt-egui` WASM: + ``` rustup target add wasm32-unknown-unknown cargo install trunk @@ -14,18 +15,6 @@ cd fpt-egui RUSTFLAGS='--cfg=web_sys_unstable_apis' trunk serve ``` -## CLI - -`cargo run -p fpt-cli run ` - -Running the naive disassembler: - -`cargo run -p fpt-cli dump ` - -Running the debugger: - -`cargo run -p fpt-cli debug` - ## Testing `cargo test` @@ -55,6 +44,7 @@ Running the debugger: ([Part 1](https://www.youtube.com/watch?v=RZUDEaLa5Nw), [Part 1.5](https://www.youtube.com/watch?v=t0V-D2YMhrs), [Part 2](https://www.youtube.com/watch?v=ecTQVa42sJc)) +- [Tetris disassembly](https://github.com/alexsteb/tetris_disassembly/blob/master/main.asm) ## Resources diff --git a/fpt-cli/Cargo.toml b/fpt-cli/Cargo.toml deleted file mode 100644 index 9ff85da..0000000 --- a/fpt-cli/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "fpt-cli" -version = "0.1.0" -edition = "2021" -default-run = "main" - -[dependencies] -clap = { version = "4.4.6", features = ["derive"] } -fpt = { path = "../fpt" } -rustyline = "13.0.0" -hlua = { version = "0.4.1" } - -[[bin]] -name = "main" -path = "src/main.rs" diff --git a/fpt-cli/src/debugger.rs b/fpt-cli/src/debugger.rs deleted file mode 100644 index 06204f0..0000000 --- a/fpt-cli/src/debugger.rs +++ /dev/null @@ -1,449 +0,0 @@ -use std::cell::RefCell; -use std::fmt; -use std::fs::File; -use std::io::Write; -use std::rc::Rc; - -use fpt::Gameboy; -use hlua::AnyHashableLuaValue as LuaValue; -use hlua::Lua; - -const ALIASES: [(&str, &str); 7] = [ - ("b", "_G['break']"), - ("break", "_G['break']"), - ("c", "_G['continue']"), - ("continue", "_G['continue']"), - ("load", "load_rom"), - ("n", "debug_commands['next']"), - ("next", "debug_commands['next']"), -]; - -fn alias_expand(cmd: String, dti: &mut DebuggerTextInterface) -> String { - ALIASES.iter().fold(cmd, |cmd, (name, value)| { - let name_with_space = name.to_string() + " "; - let name_with_paren = name.to_string() + "("; - let value_with_paren = value.to_string() + "("; - - if cmd == *name || cmd.starts_with(&name_with_space) { - if cmd == *name { - dti.last_repeatable_command = Some(format!("{value}()")); - format!("{value}()") - } else if !cmd.starts_with(&(name_with_space.clone() + "'")) { - cmd.replacen(&name_with_space, &(value_with_paren.clone() + "'"), 1) + "')" - } else { - cmd.replacen(&name_with_space, &value_with_paren, 1) + ")" - } - } else if cmd.starts_with(&name_with_paren) { - cmd.replace(&name_with_paren, &value_with_paren) - } else { - cmd - } - }) -} - -#[derive(Debug)] -pub enum Breakpoint { - OnPc(u16), - OnOpcode(u8), - OnCB(u8), -} - -impl fmt::Display for Breakpoint { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Breakpoint::OnPc(pc) => { - write!(f, "breakpoint: {}", pc) - } - Breakpoint::OnOpcode(opcode) => { - write!(f, "on_opcode: {}", opcode) - } - Breakpoint::OnCB(opcode) => { - write!(f, "on_cb: {}", opcode) - } - } - } -} -impl Breakpoint { - fn check(&self, gameboy: &Gameboy) -> bool { - match self { - Breakpoint::OnPc(pc) => gameboy.cpu().pc() == *pc, - Breakpoint::OnOpcode(opcode) => gameboy.cpu().mem8(gameboy.cpu().pc()) == *opcode, - Breakpoint::OnCB(opcode) => { - gameboy.cpu().mem8(gameboy.cpu().pc()) == *opcode && gameboy.cpu().next_cb() - } - } - } -} -pub struct Debugger { - gameboy: Rc>, - breakpoints: Vec, -} - -impl Debugger { - fn new() -> Self { - let gameboy = Rc::new(RefCell::new(Gameboy::new())); - Self::with_gameboy(gameboy) - } - - pub fn with_gameboy(gameboy: Rc>) -> Self { - Self { - gameboy, - breakpoints: Vec::new(), - } - } - - pub fn check(&self) -> bool { - for breakpoint in &self.breakpoints { - if breakpoint.check(&self.gameboy.borrow()) { - return true; - } - } - - false - } - - pub fn start(&mut self) { - let mut gameboy = self.gameboy.borrow_mut(); - loop { - println!("{:#02X}: {}", gameboy.cpu().pc(), gameboy.cpu().decode()); - if self.check() { - gameboy.instruction(); - break; - } - gameboy.instruction(); - } - } - - pub fn next(&mut self) { - let mut gameboy = self.gameboy.borrow_mut(); - println!("{:#02X}: {}", gameboy.cpu().pc(), gameboy.cpu().decode()); - gameboy.instruction(); - } - - pub fn set_breakpoint(&mut self, breakpoint: Breakpoint) { - self.breakpoints.push(breakpoint); - } - - pub fn list_breakpoints(&self) -> String { - self.breakpoints - .iter() - .map(|breakpoint| breakpoint.to_string()) - .intersperse("\n".to_string()) - .collect::() - } - - pub fn pc(&self) -> u16 { - self.gameboy.borrow().cpu().pc() - } -} - -pub struct DebuggerTextInterface<'a> { - lua: Lua<'a>, - last_repeatable_command: Option, -} - -impl DebuggerTextInterface<'_> { - #[allow(clippy::new_without_default)] - pub fn new() -> Self { - let debugger = Debugger::new(); - let mut lua = Lua::new(); - lua.openlibs(); - - { - let mut aliases_table = lua.empty_array("_aliases"); - for (name, value) in ALIASES { - aliases_table.set(name, value); - } - } - - lua.execute::<()>( - r#" - function _help() - available_functions = {} - for name, _fn in pairs(debug_commands) do - table.insert(available_functions, name) - end - table.sort(available_functions) - - s = "Available debugging functions" - s = "\n" .. s .. "\n" .. ("-"):rep(#s) .. "\n" - for _i, name in ipairs(available_functions) do - s = s .. " - " .. name .. "\n" - end - - s = s .. "\nAlias Expansion\n-------- -----------\n" - for alias, expansion in pairs(_aliases) do - s = s .. string.format("%-8s %s\n", alias, expansion) - end - return s - end - - setmetatable(_G, { - __index = function(_, key) - if debug_commands[key] then - return debug_commands[key] - else - return _help() - end - end - }) - "#, - ) - .unwrap(); - - { - let mut debug_commands = lua.empty_array("debug_commands"); - - let dbg_pointer = Rc::new(RefCell::new(debugger)); - let d1 = dbg_pointer.clone(); - - debug_commands.set( - "continue", - hlua::function0(move || -> LuaValue { - d1.borrow_mut().start(); - LuaValue::LuaNil - }), - ); - - let d1 = dbg_pointer.clone(); - debug_commands.set( - "next", - hlua::function0(move || -> LuaValue { - d1.borrow_mut().next(); - LuaValue::LuaNil - }), - ); - - let d1 = dbg_pointer.clone(); - debug_commands.set( - "breakpoints", - hlua::function0(move || -> LuaValue { - LuaValue::LuaString(d1.borrow_mut().list_breakpoints()) - }), - ); - - let d1 = dbg_pointer.clone(); - debug_commands.set( - "break", - hlua::function1(move |pc: u16| -> LuaValue { - d1.borrow_mut().set_breakpoint(Breakpoint::OnPc(pc)); - LuaValue::LuaString(format!("set breakpoint on pc: {}", pc)) - }), - ); - - let d1 = dbg_pointer.clone(); - debug_commands.set( - "break_on_opcode", - hlua::function1(move |opcode: u8| -> LuaValue { - d1.borrow_mut().set_breakpoint(Breakpoint::OnOpcode(opcode)); - LuaValue::LuaString(format!("set breakpoint on opcode: {}", opcode)) - }), - ); - - let d1 = dbg_pointer.clone(); - debug_commands.set( - "break_on_cb", - hlua::function1(move |opcode: u8| -> LuaValue { - d1.borrow_mut().set_breakpoint(Breakpoint::OnCB(opcode)); - LuaValue::LuaString(format!("set breakpoint on cb: {}", opcode)) - }), - ); - - let d1 = dbg_pointer.clone(); - debug_commands.set( - "pc", - hlua::function0(move || -> LuaValue { - LuaValue::LuaNumber(d1.borrow().pc().into()) - }), - ); - - let d1 = dbg_pointer.clone(); - debug_commands.set( - "af", - hlua::function0(move || -> LuaValue { - LuaValue::LuaNumber(d1.borrow().gameboy.borrow().cpu().af().into()) - }), - ); - - let d1 = dbg_pointer.clone(); - debug_commands.set( - "bc", - hlua::function0(move || -> LuaValue { - LuaValue::LuaNumber(d1.borrow().gameboy.borrow().cpu().bc().into()) - }), - ); - - let d1 = dbg_pointer.clone(); - debug_commands.set( - "de", - hlua::function0(move || -> LuaValue { - LuaValue::LuaNumber(d1.borrow().gameboy.borrow().cpu().de().into()) - }), - ); - - let d1 = dbg_pointer.clone(); - debug_commands.set( - "hl", - hlua::function0(move || -> LuaValue { - LuaValue::LuaNumber(d1.borrow().gameboy.borrow().cpu().hl().into()) - }), - ); - - let d1 = dbg_pointer.clone(); - debug_commands.set( - "sp", - hlua::function0(move || -> LuaValue { - LuaValue::LuaNumber(d1.borrow().gameboy.borrow().cpu().sp().into()) - }), - ); - - let d1 = dbg_pointer.clone(); - debug_commands.set( - "mem", - hlua::function1(move |address: u16| -> LuaValue { - LuaValue::LuaNumber(d1.borrow().gameboy.borrow().cpu().mem8(address).into()) - }), - ); - - let d1 = dbg_pointer.clone(); - debug_commands.set( - "next_cb", - hlua::function0(move || -> LuaValue { - LuaValue::LuaNumber(d1.borrow().gameboy.borrow().cpu().next_cb().into()) - }), - ); - - let d1 = dbg_pointer.clone(); - debug_commands.set( - "clock_cycle", - hlua::function0(move || -> LuaValue { - LuaValue::LuaString( - d1.borrow() - .gameboy - .borrow() - .cpu() - .clock_cycles() - .to_string(), - ) - }), - ); - - let d1 = dbg_pointer.clone(); - debug_commands.set( - "load_rom", - hlua::function1(move |filename: String| -> LuaValue { - let rom = std::fs::read(filename).unwrap(); - d1.borrow().gameboy.borrow_mut().load_rom(&rom); - let game_name = String::from_utf8( - d1.borrow() - .gameboy - .borrow() - .bus() - .memory_mut() - .slice(0x134..0x143) - .to_vec(), - ) - .unwrap_or("???".to_string()); - LuaValue::LuaString(format!("Loaded [{game_name}]")) - }), - ); - - let d1 = dbg_pointer.clone(); - debug_commands.set( - "mem_dump", - hlua::function0(move || -> LuaValue { - LuaValue::LuaString( - (0..0xFFFF) - .map(|i| { - format!( - "{:#02X} {:#02X}", - i, - d1.borrow().gameboy.borrow().cpu().mem8(i) - ) - }) - .intersperse("\n".to_string()) - .collect::(), - ) - }), - ); - - let d1 = dbg_pointer.clone(); - debug_commands.set( - "mem_dump_ranged", - hlua::function2(move |start: u16, end: u16| -> LuaValue { - LuaValue::LuaString( - (start..end) - .map(|i| { - format!( - "{:#02X} {:#02X}", - i, - d1.borrow().gameboy.borrow().cpu().mem8(i) - ) - }) - .intersperse("\n".to_string()) - .collect::(), - ) - }), - ); - - let d1 = dbg_pointer.clone(); - debug_commands.set( - "screenshot", - hlua::function1(move |filename: String| -> LuaValue { - // Assumes the user wants a .pgm file - let mut file = File::create(&filename) - .unwrap_or_else(|_| panic!("Couldn't open file \"{filename}\"")); - - // TODO: code dedup - // Write the header for a 160x144 PGM image with 4 shades of gray - write!(file, "P2\n# Game Boy screenshot: {filename}\n160 140\n3\n") - .expect("Couldn't write PGM header"); - - // Our Game Boy's framebuffer seems to have a direct correspondence to this! - let d1 = d1.borrow(); - let gameboy = d1.gameboy.borrow(); - let frame = gameboy.get_frame(); - - for line in frame.array_chunks::<160>() { - let pgm_line = line - .iter() - .map(|p| (b'3' - *p) as char) // ASCII from '0' to '3' - .intersperse(' ') - .collect::() - + "\n"; - file.write_all(pgm_line.as_bytes()) - .expect("Couldn't write PGM line"); - } - - // Report success - LuaValue::LuaString(format!("Screenshot written to {filename}\n")) - }), - ); - } - - Self { - lua, - last_repeatable_command: None, - } - } - - pub fn run(&mut self, mut cmd: String) { - if cmd.is_empty() { - match self.last_repeatable_command { - Some(ref repeatable_command) => cmd.clone_from(repeatable_command), - None => return, - } - } - - let expanded_cmd = alias_expand(cmd.clone(), self); - let expanded_cmd = format!("print({expanded_cmd})"); - // eprintln!("[VERBOSE] input command: {}", &cmd); - // eprintln!("[VERBOSE] expanded command: {}", &expanded_cmd); - - let result = self.lua.execute::(&expanded_cmd); - - if let Err(err) = result { - eprintln!("{}", err); - } - } -} diff --git a/fpt-cli/src/lib.rs b/fpt-cli/src/lib.rs deleted file mode 100644 index 27d7067..0000000 --- a/fpt-cli/src/lib.rs +++ /dev/null @@ -1,4 +0,0 @@ -#![feature(array_chunks)] -#![feature(iter_intersperse)] - -pub mod debugger; diff --git a/fpt-cli/src/main.rs b/fpt-cli/src/main.rs deleted file mode 100644 index 2bcda9f..0000000 --- a/fpt-cli/src/main.rs +++ /dev/null @@ -1,115 +0,0 @@ -#![feature(array_chunks)] -#![feature(iter_intersperse)] - -use std::fs; - -use clap::{Args, Parser, Subcommand}; -use debugger::DebuggerTextInterface; -use fpt::Gameboy; -use rustyline::error::ReadlineError; -use rustyline::{DefaultEditor, Result}; - -pub mod debugger; - -#[derive(Parser, Debug)] -#[command(author, version, about, long_about = None)] -struct Cli { - #[command(subcommand)] - command: Commands, -} - -#[derive(Subcommand, Debug)] -enum Commands { - Debug {}, - Dump(Dump), - Run(Run), -} - -#[derive(Debug, Args)] -struct Dump { - rom: String, -} - -#[derive(Debug, Args)] -struct Run { - rom: String, - #[arg(short, long)] - debug: Option, -} - -fn debug() -> Result<()> { - let mut debugger_interface = DebuggerTextInterface::new(); - - let mut rl = DefaultEditor::new()?; - if rl.load_history(".fpt_debug_history").is_err() { - println!("No previous history."); - } - loop { - let readline = rl.readline(">> "); - match readline { - Ok(line) => { - rl.add_history_entry(&line)?; - debugger_interface.run(line); - } - Err(ReadlineError::Interrupted) => { - println!("CTRL-C"); - break; - } - Err(ReadlineError::Eof) => { - println!("CTRL-D"); - break; - } - Err(err) => { - println!("Error: {:?}", err); - break; - } - } - } - rl.save_history(".fpt_debug_history")?; - Ok(()) -} - -fn dump(args: Dump) -> Result<()> { - let mut gb = Gameboy::new(); - let rom = fs::read(args.rom).unwrap(); - gb.load_rom(&rom); - loop { - let inst = gb.cpu().decode(); - let result: Vec = (1..inst.size) - .map(|i| format!("{:#02X}", gb.cpu().mem8(gb.cpu().pc() + i as u16))) - .collect(); - println!( - "{:#02X}: {} ({:#02X}{}{})", - gb.cpu().pc(), - inst, - inst.opcode, - if result.is_empty() { "" } else { " " }, - result.join(" ") - ); - // TODO: this is very, very stupid as it doesn't follow jumps, so it can - // read data as code. how do decompilers even work? - let next_pc = gb.cpu().pc() + inst.size as u16; - gb.cpu_mut().set_pc(next_pc); - } -} - -fn run(args: Run) -> Result<()> { - let mut gameboy = Gameboy::new(); - let rom = fs::read(args.rom).unwrap(); - gameboy.load_rom(&rom); - loop { - if args.debug.unwrap_or(false) { - println!("{:#02X}: {}", gameboy.cpu().pc(), gameboy.cpu().decode()); - } - gameboy.instruction(); - } -} - -fn main() -> Result<()> { - let args = Cli::parse(); - match args.command { - Commands::Debug {} => debug(), - Commands::Dump(args) => dump(args), - Commands::Run(args) => run(args), - } -} diff --git a/fpt-egui/Cargo.toml b/fpt-egui/Cargo.toml index 8ad741e..d7cec2d 100644 --- a/fpt-egui/Cargo.toml +++ b/fpt-egui/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" [dependencies] fpt = { path = "../fpt" } -fpt-cli = { path = "../fpt-cli" } egui = "0.26.2" eframe = { version = "0.26.2", default-features = false, features = ["glow"] } log = "0.4.14" diff --git a/fpt-egui/src/main.rs b/fpt-egui/src/main.rs index 5a6d053..56910f8 100644 --- a/fpt-egui/src/main.rs +++ b/fpt-egui/src/main.rs @@ -1,15 +1,15 @@ #![feature(lazy_cell)] #![feature(array_chunks)] -use std::cell::{Ref, RefCell, RefMut}; -use std::rc::Rc; use std::time::Duration; use eframe::Frame; -use egui::{Align, Color32, Context, Layout, TextureOptions, Ui}; +use egui::{ + menu, CentralPanel, Color32, ColorImage, Context, Grid, Key, RichText, ScrollArea, SidePanel, + TextureHandle, TextureOptions, TopBottomPanel, Ui, Vec2, ViewportBuilder, ViewportCommand, +}; use fpt::ppu::tile::Tile; use fpt::{bitwise, Gameboy}; -use fpt_cli::debugger::Debugger; use log::info; // TODO: the gameboy doesn't run at exactly 60fps @@ -71,46 +71,57 @@ fn now() -> f64 { } pub struct FPT { + gb: Gameboy, + cycles_since_last_frame: u32, + accum_time: f64, egui_frame_count: u64, gb_frame_count: u64, - accum_time: f64, - image: egui::ColorImage, - texture: Option, + paused: bool, + slow_factor: f64, - tiles: egui::ColorImage, - tiles_texture: Option, + debug_console: Vec, + debug_console_cmd: String, + debug_console_last_cmd: String, + debug_console_was_focused: bool, + code: Vec<(u16, String)>, - bg_map: egui::ColorImage, - bg_map_texture: Option, + image: ColorImage, + texture: Option, - gb: Rc>, - dbg: Debugger, - paused: bool, - slow_factor: f64, - cycles_since_last_frame: u32, - total_cycles: u64, + tiles: ColorImage, + tiles_texture: Option, + + bg_map: ColorImage, + bg_map_texture: Option, } impl Default for FPT { fn default() -> Self { - let gameboy = Rc::new(RefCell::new(Gameboy::new())); Self { + gb: Gameboy::new(), + cycles_since_last_frame: 0, + accum_time: 0.0, egui_frame_count: 0, gb_frame_count: 0, - accum_time: 0.0, - image: egui::ColorImage::new([WIDTH, HEIGHT], Color32::TRANSPARENT), + + paused: false, + slow_factor: 1.0, + + debug_console: vec![], + debug_console_cmd: String::new(), + debug_console_last_cmd: String::new(), + debug_console_was_focused: false, + code: Vec::new(), + + image: ColorImage::new([WIDTH, HEIGHT], Color32::TRANSPARENT), texture: None, - tiles: egui::ColorImage::new([TV_X_SIZE, TV_Y_SIZE], Color32::TRANSPARENT), + + tiles: ColorImage::new([TV_X_SIZE, TV_Y_SIZE], Color32::TRANSPARENT), tiles_texture: None, - bg_map: egui::ColorImage::new([BMV_X_SIZE, BMV_Y_SIZE], Color32::TRANSPARENT), + + bg_map: ColorImage::new([BMV_X_SIZE, BMV_Y_SIZE], Color32::TRANSPARENT), bg_map_texture: None, - gb: gameboy.clone(), - dbg: Debugger::with_gameboy(gameboy), - paused: false, - slow_factor: 1.0, - cycles_since_last_frame: 0, - total_cycles: 0, } } } @@ -118,12 +129,12 @@ impl Default for FPT { impl FPT { /// Called once before the first frame. pub fn new(_cc: &eframe::CreationContext) -> Self { - let app = FPT::default(); + let mut app = FPT::default(); #[cfg(not(target_arch = "wasm32"))] if std::env::var("CI").is_err() { const ROM_PATH: &str = "roms/Tetris_World_Rev_1.gb"; if let Ok(rom) = std::fs::read(ROM_PATH) { - app.gb.borrow_mut().load_rom(&rom); + app.gb.load_rom(&rom); } else { panic!("Unable to open {}", ROM_PATH); } @@ -131,23 +142,13 @@ impl FPT { app } - /// Gameboy accessor - fn gb(&self) -> Ref<'_, Gameboy> { - self.gb.borrow() - } - - /// Gameboy accessor, mutable edition - fn gb_mut(&mut self) -> RefMut<'_, Gameboy> { - self.gb.borrow_mut() - } - fn top_panel(&mut self, ctx: &Context) { #[cfg(not(target_arch = "wasm32"))] - egui::TopBottomPanel::top("top_panel").show(ctx, |ui| { - egui::menu::bar(ui, |ui| { + TopBottomPanel::top("top_panel").show(ctx, |ui| { + menu::bar(ui, |ui| { ui.menu_button("File", |ui| { if ui.button("Quit").clicked() { - ctx.send_viewport_cmd(egui::ViewportCommand::Close) + ctx.send_viewport_cmd(ViewportCommand::Close) } }); ui.add_space(16.0); @@ -161,38 +162,53 @@ impl FPT { let delta_time = ui.input(|i| i.unstable_dt) as f64; self.accum_time += delta_time; - // if self.slow_factor != 1.0 { - let cycles = self.accum_time.div_euclid(T_CYCLE * self.slow_factor) as u32; - self.accum_time -= cycles as f64 * T_CYCLE * self.slow_factor; - for _ in 0..cycles { + let cycles_want = self.accum_time.div_euclid(T_CYCLE * self.slow_factor) as u32; + let mut cycles_ran = 0; + while cycles_ran < cycles_want { // TODO: care for double speed mode - self.gb_mut().cpu_mut().t_cycle(); - self.gb_mut().ppu_mut().step(1); + let pc = self.gb.cpu().pc(); + let ran_inst = self.gb.cpu_mut().t_cycle(); + self.gb.ppu_mut().step(1); self.cycles_since_last_frame += 1; - if self.cycles_since_last_frame == self.gb().cycles_in_one_frame() { - frame = Some(*self.gb().get_frame()); // Copies the whole [u8; WIDTH * HEIGHT] into frame + if self.cycles_since_last_frame == self.gb.cycles_in_one_frame() { + frame = Some(*self.gb.get_frame()); // Copies the whole [u8; WIDTH * HEIGHT] into frame self.gb_frame_count += 1; self.cycles_since_last_frame = 0; } + cycles_ran += 1; + if let Some(inst) = ran_inst { + // TODO: only need to do this formatting work if the instruction actually isn't in the code vec + let result: Vec = (1..inst.size) + .map(|i| format!("{:#02X}", self.gb.cpu().mem8(pc + i as u16))) + .collect(); + let str = format!( + "{:#06X}: {} ({:#02X}{}{})", + pc, + inst.mnemonic, + inst.opcode, + if result.is_empty() { "" } else { " " }, + result.join(" ") + ); + // TODO: since this is ran much more often than the rendering code, + // it'd probably be best to have an O(1) insert here and then sort before rendering + match self.code.binary_search_by_key(&pc, |&(pc, _)| pc) { + Ok(pos) => { + if str != self.code[pos].1 { + self.code[pos].1 = str + } + } + Err(pos) => self.code.insert(pos, (pc, str)), + } + // TODO: check breakpoints + // TODO: this breaks *after* the instruction has been executed + } } - self.total_cycles += cycles as u64; + self.accum_time -= cycles_ran as f64 * T_CYCLE * self.slow_factor; if let Some(frame) = frame { for (i, &gb_pixel) in frame.iter().enumerate() { self.image.pixels[i] = PALETTE[gb_pixel as usize]; } } - // } else if self.accum_time >= SIXTY_FPS_FRAMETIME { - // self.accum_time -= SIXTY_FPS_FRAMETIME; - // self.gb_frame_count += 1; - // self.cycles_since_last_frame = 0; - // self.total_cycles += 70224; - // // Run for a whole frame and decode the resulting picture into our GUI's image - // let mut gb = self.gb.borrow_mut(); - // let frame = gb.advance_frame(); - // for (i, &gb_pixel) in frame.iter().enumerate() { - // self.image.pixels[i] = PALETTE[gb_pixel as usize]; - // } - // } } #[allow(dead_code)] @@ -222,8 +238,8 @@ impl FPT { } #[allow(dead_code)] - fn debug_info(&self, ui: &mut Ui) { - egui::Grid::new("my_grid").striped(true).show(ui, |ui| { + fn timing_info(&self, ui: &mut Ui) { + Grid::new("my_grid").striped(true).show(ui, |ui| { macro_rules! stat { ($label:literal : $fmt:literal, $value:expr) => { ui.colored_label(Color32::LIGHT_GRAY, $label); @@ -244,8 +260,7 @@ impl FPT { } fn get_tile(&self, tile_i: usize) -> Tile { - let gb = self.gb(); - let bus = gb.bus(); + let bus = self.gb.bus(); let lcdc4 = bitwise::test_bit8::<4>(bus.lcdc()); let tile_address = 16 * tile_i + if lcdc4 || tile_i > 127 { @@ -256,218 +271,283 @@ impl FPT { bus.with_span(tile_address, Tile::load) } - fn debug_panel(&mut self, ui: &mut Ui) { - egui::ScrollArea::vertical() - .id_source("debug_panel") - .show(ui, |ui| { - ui.heading("VRAM"); - ui.separator(); - ui.horizontal_wrapped(|ui| { - for tile_i in 0..fpt::ppu::tile::NUM_TILES { - let tile = self.get_tile(tile_i); - for y in 0..TILE_SIZE { - let yy = y - + (tile_i / TV_COLS + 1) * TV_BORDER_SIZE - + (tile_i / TV_COLS) * TILE_SIZE; - for x in 0..TILE_SIZE { - let pixel = tile.get_pixel(y, x); - let xx = x - + (tile_i % TV_COLS + 1) * TV_BORDER_SIZE - + (tile_i % TV_COLS) * TILE_SIZE; - self.tiles[(xx, yy)] = PALETTE[pixel as usize]; - } - } - } - for b in 0..TV_NUM_HBORDERS { - for y in 0..TV_BORDER_SIZE { - for x in 0..TV_X_SIZE { - self.tiles[(x, y + b * (TILE_SIZE + TV_BORDER_SIZE))] = GREY; - } - } + fn debug_panel(&mut self, ctx: &Context, ui: &mut Ui) { + ui.collapsing("VRAM", |ui| { + ui.horizontal_wrapped(|ui| self.vram_viewer(ui)); + ui.horizontal(|ui| self.vram_registers(ui)); + }); + ui.horizontal(|ui| { + if ui + .button(if self.paused { "Continue" } else { "Pause" }) + .clicked() + { + self.paused = !self.paused; + } + ui.horizontal(|ui| { + ui.monospace("Slow factor:"); + ui.radio_value(&mut self.slow_factor, 0.1f64, "0.1"); + ui.radio_value(&mut self.slow_factor, 1f64, "1"); + ui.radio_value(&mut self.slow_factor, 10f64, "10"); + ui.radio_value(&mut self.slow_factor, 1000f64, "1000"); + ui.radio_value(&mut self.slow_factor, 1e6, "1_000_000"); + }); + }); + ui.horizontal_wrapped(|ui| { + macro_rules! cpu_register { + ($ui:expr, $high_label:literal : $high_value:expr, $low_label:literal : $low_value:expr) => { + $ui.colored_label(Color32::LIGHT_BLUE, $high_label); + $ui.monospace(format!("{:08b}", $high_value)); + $ui.code(format!("{:04X}", bitwise::word16($high_value, $low_value))); + $ui.monospace(format!("{:08b}", $low_value)); + $ui.colored_label(Color32::LIGHT_BLUE, $low_label); + } + } + let cpu = self.gb.cpu(); + ui.vertical(|ui| { + Grid::new("cpu_registers_a-e").num_columns(4).min_col_width(10.0).striped(true).show(ui, |ui| { + ui.colored_label(Color32::LIGHT_BLUE, "A"); + ui.monospace(format!("{:08b}", cpu.a())); + ui.code(format!("{:#04X}", cpu.a())); + ui.end_row(); + cpu_register!(ui, "B": cpu.b(), "C": cpu.c()); ui.end_row(); + cpu_register!(ui, "D": cpu.d(), "E": cpu.e()); ui.end_row(); + cpu_register!(ui, "H": cpu.a(), "L": cpu.f()); ui.end_row(); + }); + }); + ui.separator(); + ui.vertical(|ui| { + Grid::new("flags").num_columns(1).min_col_width(10.0).striped(true).show(ui, |ui| { + ui.colored_label(Color32::LIGHT_BLUE, "Z"); + ui.code(if cpu.z_flag() { "1" } else { "0" }); + ui.colored_label(Color32::LIGHT_BLUE, "N"); + ui.code(if cpu.n_flag() { "1" } else { "0" }); + ui.end_row(); + ui.colored_label(Color32::LIGHT_BLUE, "H"); + ui.code(if cpu.h_flag() { "1" } else { "0" }); + ui.colored_label(Color32::LIGHT_BLUE, "C"); + ui.code(if cpu.c_flag() { "1" } else { "0" }); + }); + ui.horizontal(|ui| { + ui.colored_label(Color32::LIGHT_BLUE, "SP"); + ui.code(format!("{:#06X}", cpu.sp())); + }); + ui.horizontal(|ui| { + ui.colored_label(Color32::LIGHT_BLUE, "PC"); + ui.code(format!("{:#06X}", cpu.pc())); + }); + }); + }); + // TODO: scroll into line of current pc (need to find index) + ui.collapsing("Code", |ui| { + ScrollArea::vertical().show_rows( + ui, + ui.text_style_height(&egui::TextStyle::Body), + self.code.len(), + |ui, row_range| { + for row in row_range { + ui.label(RichText::new(self.code[row].1.clone()).monospace()); } - for b in 0..TV_NUM_VBORDERS { - for x in 0..TV_BORDER_SIZE { - for y in 0..TV_Y_SIZE { - self.tiles[(x + b * (TILE_SIZE + TV_BORDER_SIZE), y)] = GREY; - } + }, + ); + }); + ui.collapsing("Console", |ui| { + ScrollArea::vertical() + .auto_shrink(false) + .stick_to_bottom(true) + // TODO: dirty hack to make the console input always stick to the bottom + .max_height(ui.available_rect_before_wrap().height() - 24.0) + .show_rows( + ui, + ui.text_style_height(&egui::TextStyle::Body), + self.debug_console.len(), + |ui, row_range| { + for row in row_range { + ui.label(RichText::new(self.debug_console[row].clone()).monospace()); } - } - let texture: &mut egui::TextureHandle = - self.tiles_texture.get_or_insert_with(|| { - ui.ctx().load_texture( - "tile_viewer", - self.tiles.clone(), - TextureOptions::NEAREST, - ) - }); - texture.set(self.tiles.clone(), TextureOptions::NEAREST); - ui.vertical(|ui| { - ui.label("Tile data"); - ui.image((texture.id(), TV_TEXTURE_SCALE * texture.size_vec2())); + }, + ); + let edit = egui::TextEdit::multiline(&mut self.debug_console_cmd) + .desired_rows(1) + .font(egui::TextStyle::Monospace) + .desired_width(f32::INFINITY); + let response = ui.add(edit); + if self.debug_console_was_focused { + response.request_focus(); + self.debug_console_was_focused = false; + } + if response.has_focus() && ctx.input(|i| i.key_pressed(Key::Enter)) { + self.debug_console_was_focused = true; + self.debug_console_cmd = self.debug_console_cmd.trim().to_string(); + if self.debug_console_cmd.is_empty() { + self.debug_console_cmd + .clone_from(&self.debug_console_last_cmd); + } + self.debug_console + .push(format!("> {}", self.debug_console_cmd)); + if self.debug_console_cmd == "d" { + self.gb.cpu().decode_ahead(5).iter().for_each(|(pc, inst)| { + let args = self + .gb + .bus() + .copy_range((*pc as usize)..((pc + inst.size as u16) as usize)) + .iter() + .fold(String::new(), |acc, &b| acc + &format!("{:#02X} ", b)) + .trim() + .to_string(); + self.debug_console + .push(format!("{:#06X}: {} ({})", pc, inst.mnemonic, args)); }); + } + self.debug_console_last_cmd + .clone_from(&self.debug_console_cmd); + self.debug_console_cmd = String::new(); + } + }); + } - let lcdc = self.gb().bus().lcdc(); - let bg_map_area = match bitwise::test_bit8::<3>(lcdc) { - false => 0x9800..0x9C00, - true => 0x9C00..0xA000 - }; - let bg_map_iter = bg_map_area.map(|addr| self.gb.borrow().bus().read(addr)); - - for (i, tile_i) in bg_map_iter.enumerate() { - let tile = self.get_tile(tile_i as usize); - for y in 0..TILE_SIZE { - let yy = y + (i / BMV_TILES_PER) * TILE_SIZE + BMV_BORDER_SIZE; - for x in 0..TILE_SIZE { - let pixel = tile.get_pixel(y, x); - let xx = x + (i % BMV_TILES_PER) * TILE_SIZE + BMV_BORDER_SIZE; - self.bg_map[(xx, yy)] = PALETTE[pixel as usize]; - } - } - } - // clear edges of bg_map viewer - for x in 0..BMV_X_SIZE { - self.bg_map[(x, 0)] = Color32::TRANSPARENT; - self.bg_map[(x, BMV_Y_SIZE - 1)] = Color32::TRANSPARENT; - } - for y in 0..BMV_Y_SIZE { - self.bg_map[(0, y)] = Color32::TRANSPARENT; - self.bg_map[(BMV_X_SIZE - 1, y)] = Color32::TRANSPARENT; - } - let top = self.gb().bus().scy() as usize; - let left = self.gb().bus().scx() as usize; - let bottom = ((self.gb().bus().scy() as u16 + 143u16) % 256u16) as usize; - let right = ((self.gb().bus().scx() as u16 + 159u16) % 256u16) as usize; - let btop = top; - let bleft = left; - let bbottom = bottom + 2 * BMV_BORDER_SIZE; - let bright = right + 2 * BMV_BORDER_SIZE; - for x in bleft..(bright + 1) { - self.bg_map[(x, btop)] = GREY; - self.bg_map[(x, bbottom)] = GREY; - } - for y in btop..(bbottom + 1) { - self.bg_map[(bleft, y)] = GREY; - self.bg_map[(bright, y)] = GREY; - } - let texture: &mut egui::TextureHandle = - self.bg_map_texture.get_or_insert_with(|| { - ui.ctx().load_texture( - "bg_map_viewer", - self.bg_map.clone(), - TextureOptions::NEAREST, - ) - }); - texture.set(self.bg_map.clone(), TextureOptions::NEAREST); - ui.vertical(|ui| { - ui.label("BG Map"); - ui.image((texture.id(), BMV_TEXTURE_SCALE * texture.size_vec2())); - }); - }); - ui.collapsing("Registers", |ui| { - ui.horizontal(|ui| { - let gb = self.gb(); - let bus = gb.bus(); - egui::Grid::new("VRAM-registers-1").striped(true).show(ui, |ui| { - ui.monospace("LCDC"); - ui.monospace(format!("{:08b}", bus.lcdc())); - ui.end_row(); - ui.monospace("STAT"); - ui.monospace(format!("{:08b}", bus.stat())); - ui.end_row(); - }); - ui.separator(); - egui::Grid::new("VRAM-registers-2").striped(true).show(ui, |ui| { - ui.monospace("LY"); - ui.monospace(format!("{:08b}", bus.ly())); - ui.end_row(); - ui.monospace("LYC"); - ui.monospace(format!("{:08b}", bus.lyc())); - ui.end_row(); - }); - ui.separator(); - egui::Grid::new("VRAM-registers-3").striped(true).show(ui, |ui| { - ui.monospace("SCX"); - ui.monospace(format!("{:08b}", bus.scx())); - ui.end_row(); - ui.monospace("SCY"); - ui.monospace(format!("{:08b}", bus.scy())); - ui.end_row(); - }); + fn vram_registers(&mut self, ui: &mut Ui) { + let bus = self.gb.bus(); + Grid::new("VRAM-registers-parent") + .striped(true) + .show(ui, |ui| { + ui.horizontal(|ui| { + Grid::new("VRAM-registers-1").striped(true).show(ui, |ui| { + ui.monospace("LCDC"); + ui.monospace(format!("{:08b}", bus.lcdc())); + ui.end_row(); + ui.monospace("STAT"); + ui.monospace(format!("{:08b}", bus.stat())); + ui.end_row(); }); + ui.separator(); }); - ui.add_space(20.0); - ui.heading("CPU"); - ui.separator(); - ui.horizontal_wrapped(|ui| { - macro_rules! cpu_register { - ($ui:expr, $high_label:literal : $high_value:expr, $low_label:literal : $low_value:expr) => { - $ui.colored_label(Color32::LIGHT_BLUE, $high_label); - $ui.monospace(format!("{:08b}", $high_value)); - $ui.code(format!("{:04X}", bitwise::word16($high_value, $low_value))); - $ui.monospace(format!("{:08b}", $low_value)); - $ui.colored_label(Color32::LIGHT_BLUE, $low_label); - } - } - let gb = self.gb(); - let cpu = gb.cpu(); - egui::Grid::new("cpu_registers_a-e").num_columns(4).min_col_width(10.0).striped(true).show(ui, |ui| { - cpu_register!(ui, "A": cpu.a(), "F": cpu.f()); ui.end_row(); - cpu_register!(ui, "B": cpu.b(), "C": cpu.c()); ui.end_row(); - cpu_register!(ui, "D": cpu.d(), "E": cpu.e()); ui.end_row(); + ui.horizontal(|ui| { + Grid::new("VRAM-registers-2").striped(true).show(ui, |ui| { + ui.monospace("LY"); + ui.monospace(format!("{:08b}", bus.ly())); + ui.end_row(); + ui.monospace("LYC"); + ui.monospace(format!("{:08b}", bus.lyc())); + ui.end_row(); }); ui.separator(); - ui.vertical(|ui| { - ui.horizontal(|ui| { - cpu_register!(ui, "H": cpu.h(), "L": cpu.l()); - }); - ui.horizontal(|ui| { - ui.colored_label(Color32::LIGHT_BLUE, "SP"); - ui.monospace(format!("{:016b}", cpu.sp())); - ui.code(format!("{:#04X}", cpu.sp())); - }); - ui.horizontal(|ui| { - ui.colored_label(Color32::LIGHT_BLUE, "PC"); - ui.monospace(format!("{:016b}", cpu.pc())); - ui.code(format!("{:#04X}", cpu.pc())); - }); - }); }); - ui.add_space(20.0); - ui.heading("Debugger:"); - ui.separator(); ui.horizontal(|ui| { - if ui.button(if self.paused { "Continue" } else { "Pause" }).clicked() { - self.paused = !self.paused; - } - ui.horizontal(|ui| { - ui.monospace("Slow factor:"); - ui.add(egui::DragValue::new(&mut self.slow_factor).clamp_range(1..=1000).speed(0.5)); - }); - ui.with_layout(Layout::right_to_left(Align::Max), |ui| { - ui.monospace(self.dbg.pc().to_string()); - ui.label("PC: "); - ui.separator(); + Grid::new("VRAM-registers-3").striped(true).show(ui, |ui| { + ui.monospace("SCX"); + ui.monospace(format!("{:08b}", bus.scx())); + ui.end_row(); + ui.monospace("SCY"); + ui.monospace(format!("{:08b}", bus.scy())); + ui.end_row(); }); }); - let breakpoints_string = self.dbg.list_breakpoints(); - if breakpoints_string.is_empty() { - ui.centered_and_justified(|ui| ui.label("No breakpoints (WIP)")); - } else { - ui.monospace(breakpoints_string); - } }); } + fn vram_viewer(&mut self, ui: &mut Ui) { + for tile_i in 0..fpt::ppu::tile::NUM_TILES { + let tile = self.get_tile(tile_i); + for y in 0..TILE_SIZE { + let yy = + y + (tile_i / TV_COLS + 1) * TV_BORDER_SIZE + (tile_i / TV_COLS) * TILE_SIZE; + for x in 0..TILE_SIZE { + let pixel = tile.get_pixel(y, x); + let xx = x + + (tile_i % TV_COLS + 1) * TV_BORDER_SIZE + + (tile_i % TV_COLS) * TILE_SIZE; + self.tiles[(xx, yy)] = PALETTE[pixel as usize]; + } + } + } + for b in 0..TV_NUM_HBORDERS { + for y in 0..TV_BORDER_SIZE { + for x in 0..TV_X_SIZE { + self.tiles[(x, y + b * (TILE_SIZE + TV_BORDER_SIZE))] = GREY; + } + } + } + for b in 0..TV_NUM_VBORDERS { + for x in 0..TV_BORDER_SIZE { + for y in 0..TV_Y_SIZE { + self.tiles[(x + b * (TILE_SIZE + TV_BORDER_SIZE), y)] = GREY; + } + } + } + let texture: &mut TextureHandle = self.tiles_texture.get_or_insert_with(|| { + ui.ctx() + .load_texture("tile_viewer", self.tiles.clone(), TextureOptions::NEAREST) + }); + texture.set(self.tiles.clone(), TextureOptions::NEAREST); + ui.vertical(|ui| { + ui.label("Tile data"); + ui.image((texture.id(), TV_TEXTURE_SCALE * texture.size_vec2())); + }); + + let lcdc = self.gb.bus().lcdc(); + let bg_map_area = match bitwise::test_bit8::<3>(lcdc) { + false => 0x9800..0x9C00, + true => 0x9C00..0xA000, + }; + let bg_map_iter = bg_map_area.map(|addr| self.gb.bus().read(addr)); + + for (i, tile_i) in bg_map_iter.enumerate() { + let tile = self.get_tile(tile_i as usize); + for y in 0..TILE_SIZE { + let yy = y + (i / BMV_TILES_PER) * TILE_SIZE + BMV_BORDER_SIZE; + for x in 0..TILE_SIZE { + let pixel = tile.get_pixel(y, x); + let xx = x + (i % BMV_TILES_PER) * TILE_SIZE + BMV_BORDER_SIZE; + self.bg_map[(xx, yy)] = PALETTE[pixel as usize]; + } + } + } + // clear edges of bg_map viewer + for x in 0..BMV_X_SIZE { + self.bg_map[(x, 0)] = Color32::TRANSPARENT; + self.bg_map[(x, BMV_Y_SIZE - 1)] = Color32::TRANSPARENT; + } + for y in 0..BMV_Y_SIZE { + self.bg_map[(0, y)] = Color32::TRANSPARENT; + self.bg_map[(BMV_X_SIZE - 1, y)] = Color32::TRANSPARENT; + } + let top = self.gb.bus().scy() as usize; + let left = self.gb.bus().scx() as usize; + let bottom = ((self.gb.bus().scy() as u16 + 143u16) % 256u16) as usize; + let right = ((self.gb.bus().scx() as u16 + 159u16) % 256u16) as usize; + let btop = top; + let bleft = left; + let bbottom = bottom + 2 * BMV_BORDER_SIZE; + let bright = right + 2 * BMV_BORDER_SIZE; + for x in bleft..(bright + 1) { + self.bg_map[(x, btop)] = GREY; + self.bg_map[(x, bbottom)] = GREY; + } + for y in btop..(bbottom + 1) { + self.bg_map[(bleft, y)] = GREY; + self.bg_map[(bright, y)] = GREY; + } + let texture: &mut TextureHandle = self.bg_map_texture.get_or_insert_with(|| { + ui.ctx().load_texture( + "bg_map_viewer", + self.bg_map.clone(), + TextureOptions::NEAREST, + ) + }); + texture.set(self.bg_map.clone(), TextureOptions::NEAREST); + ui.vertical(|ui| { + ui.label("BG Map"); + ui.image((texture.id(), BMV_TEXTURE_SCALE * texture.size_vec2())); + }); + } + fn central_panel(&mut self, ctx: &Context, ui: &mut Ui) { - // Emulator + screen - // let frame_start = now(); - // let gb_frame_count_before = self.gb_frame_count; if !self.paused { self.emulator(ui); } // TODO repeated work in 1st repaint // TODO: should be in new? - let texture: &mut egui::TextureHandle = self.texture.get_or_insert_with(|| { + let texture: &mut TextureHandle = self.texture.get_or_insert_with(|| { ui.ctx() .load_texture("my-image", self.image.clone(), TextureOptions::NEAREST) }); @@ -482,15 +562,14 @@ impl FPT { impl eframe::App for FPT { fn update(&mut self, ctx: &Context, _frame: &mut Frame) { self.top_panel(ctx); - egui::SidePanel::right("right_panel") + SidePanel::right("right_panel") .resizable(true) - .default_width(350.0) .show(ctx, |ui| { - self.debug_info(ui); - self.debug_panel(ui); + // self.timing_info(ui); + self.debug_panel(ctx, ui); }); - egui::CentralPanel::default().show(ctx, |ui| { + CentralPanel::default().show(ctx, |ui| { self.central_panel(ctx, ui); }); } @@ -502,8 +581,8 @@ fn main() -> eframe::Result<()> { env_logger::init(); let native_options = eframe::NativeOptions { - viewport: egui::ViewportBuilder { - inner_size: Some(egui::Vec2::new(950.0, 700.0)), + viewport: ViewportBuilder { + inner_size: Some(Vec2::new(950.0, 700.0)), ..Default::default() }, ..Default::default() diff --git a/fpt/src/lr35902.rs b/fpt/src/lr35902.rs index 41b61e7..4cfc508 100644 --- a/fpt/src/lr35902.rs +++ b/fpt/src/lr35902.rs @@ -3,7 +3,7 @@ use std::fmt; use instructions::{Instruction, InstructionKind, INSTRUCTIONS}; use super::memory::Bus; -use crate::bitwise as bw; +use crate::{bitwise as bw, memory}; pub mod instructions; @@ -18,7 +18,7 @@ pub struct LR35902 { ime: bool, imenc: bool, mem: Bus, - next_cb: bool, + prefix_cb: bool, clock_cycles: u64, inst_cycle_count: u8, branch_taken: bool, @@ -48,12 +48,13 @@ impl LR35902 { ime: false, imenc: false, mem: memory, - next_cb: false, + prefix_cb: false, clock_cycles: 0, inst_cycle_count: 0, branch_taken: false, }; - cpu.mem.load_bootrom(include_bytes!("../dmg0.bin")); + // TODO: should be done elsewhere, separation of concerns yada-yada? + cpu.mem.load_bootrom(); cpu } @@ -195,7 +196,7 @@ impl LR35902 { self.af = bw::set_bit16::<4>(self.af, value); } - // other + // other getters/setters pub fn pc(&self) -> u16 { self.pc } @@ -203,9 +204,6 @@ impl LR35902 { pub fn set_pc(&mut self, pc: u16) { self.pc = pc; } - pub fn next_cb(&self) -> bool { - self.next_cb - } pub fn interrupt_master_enable(&self) -> bool { self.ime @@ -219,10 +217,6 @@ impl LR35902 { self.imenc = true; } - pub fn set_next_cb(&mut self, value: bool) { - self.next_cb = value; - } - pub fn clock_cycles(&self) -> u64 { self.clock_cycles } @@ -247,7 +241,7 @@ impl LR35902 { self.inst_cycle_count = inst_cycle_count; } - // helpers + // Memory pub fn mem8(&self, index: u16) -> u8 { self.mem.read(index) } @@ -257,6 +251,7 @@ impl LR35902 { } pub fn set_mem8(&mut self, index: u16, value: u8) { + self.register_write_triggers(index, value); self.mem.write(index, value); } @@ -265,6 +260,13 @@ impl LR35902 { self.set_mem8(index, bw::get_byte16::<0>(value)); } + fn register_write_triggers(&mut self, index: u16, value: u8) { + if index == memory::map::BANK as u16 && value != 0 { + self.mem.unload_bootrom(); + } + } + + // Decoding /// get 8 bit immediate at position pc + 1 + pos fn get_d8(&self, pos: u8) -> u8 { self.mem8(self.pc + pos as u16 + 1) @@ -289,6 +291,7 @@ impl LR35902 { self.set_mem8(self.hl(), value); } + // Instruction logic fn half_carry8(&self, x: u8, y: u8) -> bool { ((x & 0x0f) + (y & 0x0f)) > 0x0f } @@ -542,7 +545,7 @@ impl LR35902 { fn reti(&mut self) { // TODO: The interrupt master enable flag is returned to its pre-interrupt status. - // BUT: https://gbdev.io/pandocs/Interrupts.htm claims that RETI is EI followed by RET + // BUT: https://gbdev.io/pandocs/Interrupts.htm claims that RETI is EI followed by RET self.set_interrupt_master_enable_next_instruction(); // RET @@ -558,36 +561,47 @@ impl LR35902 { self.set_h_flag(true); } - //pub fn load_rom(&mut self, rom: Vec) { - // self.mem.bus().load_cartridge(&rom); - //} - - //fn load_bootrom(&mut self, bootrom: &[u8; 256]) { - // self.mem.bus().load_bootrom(bootrom); - //} - - pub fn decode(&self) -> Instruction { + fn decode(&self) -> Instruction { let mut opcode = self.mem8(self.pc()) as u16; - if self.next_cb() { + if self.prefix_cb { opcode += 0x100; } INSTRUCTIONS[opcode as usize] } + pub fn decode_ahead(&self, n: usize) -> Vec<(u16, Instruction)> { + let mut ret = Vec::<(u16, Instruction)>::with_capacity(n + 1); + ret.push((self.pc(), self.decode())); + // TODO: decode can return "PREFIX CB" - not good for the disasm + // if ret[0].mnemonic == "PREFIX CB" {} + for i in 1..(n + 1) { + let last_inst = ret[i - 1]; + let next_pc = last_inst.0 + last_inst.1.size as u16; + let mut next_inst_opcode_index = self.mem8(next_pc) as usize; + if last_inst.1.mnemonic == "PREFIX CB" { + next_inst_opcode_index += 0x100; + } + ret.push((next_pc, INSTRUCTIONS[next_inst_opcode_index])); + } + ret + } + /// Run one t-cycle - from actual crystal @ 4 or 8 MHz (double speed mode) - pub fn t_cycle(&mut self) { + /// Returns a instruction if we actually mutated CPU state, since we only + /// execute the instruction itself on its last t-cycle + pub fn t_cycle(&mut self) -> Option { let instruction = self.decode(); self.set_inst_cycle_count(self.inst_cycle_count() + 1); // Only actually mutate CPU state on the last t-cycle of the instruction if self.inst_cycle_count() < instruction.cycles { - return; + return None; } if self.imenc { self.set_interrupt_master_enable(true); self.imenc = false; } - if self.next_cb() { - self.set_next_cb(false); + if self.prefix_cb { + self.prefix_cb = false; } self.execute(instruction); if !self.branch_taken() { @@ -601,6 +615,7 @@ impl LR35902 { self.set_clock_cycles(self.clock_cycles() + cycles as u64); self.set_branch_taken(false); self.set_inst_cycle_count(0); + Some(instruction) } /// Run one complete instruction - NOT a machine cycle (4 t-cycles) @@ -1551,7 +1566,7 @@ impl LR35902 { } 0xCB => { // PREFIX CB - self.set_next_cb(true); + self.prefix_cb = true; } 0xCC => { // CALL Z,a16 diff --git a/fpt/src/lr35902/instructions.rs b/fpt/src/lr35902/instructions.rs index eaa9e8c..b3021c6 100644 --- a/fpt/src/lr35902/instructions.rs +++ b/fpt/src/lr35902/instructions.rs @@ -1,5 +1,3 @@ -use std::fmt; - #[derive(Clone, Copy, PartialEq, Debug)] pub struct Instruction { pub opcode: u16, @@ -10,10 +8,16 @@ pub struct Instruction { pub kind: InstructionKind, } -// TODO -impl fmt::Display for Instruction { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.mnemonic) +impl Default for Instruction { + fn default() -> Self { + Self { + opcode: 0, + mnemonic: "", + size: 0, + cycles: 0, + cycles_not_taken: 0, + kind: InstructionKind::NI, + } } } diff --git a/fpt/src/memory.rs b/fpt/src/memory.rs index 6c191e3..5605dfe 100644 --- a/fpt/src/memory.rs +++ b/fpt/src/memory.rs @@ -25,8 +25,7 @@ pub mod map { /// User Program Area (32 KB) /// 0x0000..0x4000 From cartridge, usually a fixed bank - /// 0x4000..0x8000 From cartridge, switchable bank via mapper (if any) - pub const USER_PROGRAM: MemoryRange = 0x0000..0x8000; + /// 0x4000..0x8000 From cartridge, switchable bank via mapper (if any) pub const USER_PROGRAM: MemoryRange = 0x0000..0x8000; /// Video RAM (8 KB) - In CGB mode, switchable bank 0/1 pub const VRAM: MemoryRange = 0x8000..0xA000; @@ -143,8 +142,8 @@ pub mod map { /// Window X position plus 7 pub const WX: Address = 0xFF4B; - /// Set to non-zero to disable boot ROM - pub const DISABLE_BOOTROM: Address = 0xFF50; + /// BANK register: Set to non-zero to disable boot ROM + pub const BANK: Address = 0xFF50; //------------------------------------------------------------------------- // CGB extra @@ -177,8 +176,7 @@ pub mod map { pub const OCPD: Address = 0xFF6B; /// Object priority mode (CGB) pub const OPRI: Address = 0xFF6C; - /// WRAM bank (CGB) - pub const SVBK: Address = 0xFF70; + /// WRAM bank (CGB) pub const SVBK: Address = 0xFF70; /// Audio digital outputs 1 & 2 (CGB) pub const PCM12: Address = 0xFF76; /// Audio digital outputs 3 & 4 (CGB) @@ -205,7 +203,7 @@ pub mod map { pub struct Memory { mem: [u8; 65536], cartridge: Vec, - bootrom: [u8; 256], + bootrom: &'static [u8; 256], } impl PartialEq for Memory { @@ -225,7 +223,7 @@ impl Memory { Self { mem: [0; 65536], cartridge: Vec::new(), - bootrom: [0; 256], + bootrom: include_bytes!("../dmg0.bin"), } } @@ -259,18 +257,19 @@ impl Bus { self.0.borrow_mut() } - pub fn load_bootrom(&mut self, bootrom: &[u8; 256]) { - self.memory_mut().bootrom.clone_from_slice(bootrom); + pub fn load_bootrom(&mut self) { + let bootrom = self.memory().bootrom; self.clone_from_slice(map::BOOTROM, bootrom); } + pub fn unload_bootrom(&mut self) { + let cartridge = self.memory_mut().cartridge[0x0000..0x0100].to_vec(); + self.clone_from_slice(map::BOOTROM, &cartridge); + } + pub fn load_cartridge(&mut self, cartridge: &[u8]) { - if cartridge.len() < 0x8000 { - println!("This is not a rom, fuck you!"); - panic!(); - } self.memory_mut().cartridge = cartridge.to_vec(); - self.clone_from_slice(0x100..0x8000, &cartridge[0x100..cartridge.len()]); + self.clone_from_slice(0x0100..0x8000, &cartridge[0x0100..0x8000]); } pub fn read(&self, address: GBAddress) -> u8 { diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 210c2dc..0c62282 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly" +channel = "nightly-2024-05-02" components = [ "rustfmt", "rustc-dev" , "clippy"] profile = "minimal"