Compare commits

..

27 Commits

Author SHA1 Message Date
Mwa
128a53bd3b improved debug 2026-03-27 22:40:28 +01:00
Mwa
689f4b77fd slightly improved asm debug message 2026-03-26 21:24:14 +01:00
Mwa
96c3a514f2 fixed up debug PC/SP addr 2026-03-26 20:26:51 +01:00
Mwa
e97b4c4ee4 fixed up debug command 2026-03-26 20:11:32 +01:00
Mwa
a51b6589f0 removed subdir 2026-03-26 17:07:00 +01:00
Mwa
cebc8fcc5b bitmap to asm moved to the other repo 2026-03-26 13:18:51 +01:00
Mwa
b664538923 added color to img 2026-03-25 09:42:23 +01:00
Mwa
3525db5299 added a warn when frame lag 2026-03-24 23:16:33 +01:00
Mwa
8d7cb5e6f3 fixed import on non-debug build 2026-03-24 15:36:52 +01:00
Mwa
ced0e13f6b improved debug interface 2026-03-23 19:19:38 +01:00
Mwa
c6b58dbc21 again, some minor perf improvement, probably be the last 2026-03-21 00:08:45 +01:00
Mwa
af111c5992 minor interupt on halt responsivity improvement and final Cargo.toml args 2026-03-20 19:30:00 +01:00
Mwa
b5962c6b50 minor performance improvement for jump/call 2026-03-20 11:18:48 +01:00
Mwa
ff6427b020 performance improvement 2026-03-20 11:08:18 +01:00
Mwa
c72e133cde Implemented correct behavior for lsl, asr, lsr (mask and correct for input = 32) 2026-03-19 21:35:49 +01:00
Mwa
c844f8d806 added nosize arg 2026-03-18 15:07:05 +01:00
Mwa
5c5d8471fa minor graphic modification 2026-03-17 23:10:58 +01:00
Mwa
94120273bb better rgba 2026-03-17 22:04:21 +01:00
Mwa
978bb30fdb Merge branch 'main' of ssh://gitea.jthillard.fr:222/mwa/bisare_sim_rs 2026-03-17 21:21:53 +01:00
Mwa
5dd9328008 fic debug build 2026-03-17 21:21:46 +01:00
mwa
f6cc53075a clarified entry point meaning 2026-03-17 20:16:33 +00:00
Mwa
8fa56c5b6f compilation fix 2026-03-17 21:05:51 +01:00
Mwa
902ed046ca futex feature explained 2026-03-17 20:32:33 +01:00
Mwa
f17b849da2 busy wait for macos 2026-03-17 17:23:00 +01:00
Mwa
d04b6f35c3 busy wait for macos 2026-03-17 17:21:52 +01:00
Mwa
47efeef83d changed futex crate for mac compat (maybe) and image to bitmap assembly converter 2026-03-17 16:31:45 +01:00
Mwa
20f7c289ed -1 on unrecognized input and start bitmap converter 2026-03-17 13:22:33 +01:00
9 changed files with 1211 additions and 540 deletions

2
.cargo/config.toml Normal file
View File

@@ -0,0 +1,2 @@
[build]
rustflags = ["-Ctarget-cpu=native"]

617
Cargo.lock generated
View File

@@ -82,6 +82,56 @@ dependencies = [
"libc",
]
[[package]]
name = "anstream"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
[[package]]
name = "anstyle-parse"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
dependencies = [
"anstyle",
"once_cell_polyfill",
"windows-sys 0.61.2",
]
[[package]]
name = "arrayref"
version = "0.3.9"
@@ -117,16 +167,6 @@ dependencies = [
"regex",
]
[[package]]
name = "atomic-wait"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a55b94919229f2c42292fd71ffa4b75e83193bffdd77b1e858cd55fd2d0b0ea8"
dependencies = [
"libc",
"windows-sys 0.42.0",
]
[[package]]
name = "atomic-waker"
version = "1.1.2"
@@ -165,6 +205,9 @@ name = "bitflags"
version = "2.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
dependencies = [
"serde_core",
]
[[package]]
name = "block"
@@ -227,9 +270,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.2.56"
version = "1.2.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2"
checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423"
dependencies = [
"find-msvc-tools",
"jobserver",
@@ -261,6 +304,92 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "chrono"
version = "0.4.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
dependencies = [
"iana-time-zone",
"num-traits",
"serde",
"windows-link",
]
[[package]]
name = "clap"
version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap-repl"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ffd4e57297ee7a10fb637964a79fd4bf5c8d22fd4ceaac5d3964d55df9e9e38"
dependencies = [
"clap",
"clap_complete",
"console",
"nu-ansi-term",
"reedline",
"shlex",
]
[[package]]
name = "clap_builder"
version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
dependencies = [
"anstream",
"anstyle",
"clap_lex 1.1.0",
"strsim",
]
[[package]]
name = "clap_complete"
version = "4.5.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c677cd0126f3026d8b093fa29eae5d812fde5c05bc66dbb29d0374eea95113a"
dependencies = [
"clap",
"clap_lex 0.7.7",
"is_executable",
"pathdiff",
"shlex",
"unicode-xid",
]
[[package]]
name = "clap_derive"
version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.117",
]
[[package]]
name = "clap_lex"
version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
[[package]]
name = "clap_lex"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
[[package]]
name = "codespan-reporting"
version = "0.11.1"
@@ -268,9 +397,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
dependencies = [
"termcolor",
"unicode-width",
"unicode-width 0.1.14",
]
[[package]]
name = "colorchoice"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
[[package]]
name = "com"
version = "0.6.0"
@@ -321,6 +456,19 @@ dependencies = [
"crossbeam-utils",
]
[[package]]
name = "console"
version = "0.15.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8"
dependencies = [
"encode_unicode",
"libc",
"once_cell",
"unicode-width 0.2.2",
"windows-sys 0.59.0",
]
[[package]]
name = "core-foundation"
version = "0.9.4"
@@ -367,6 +515,32 @@ version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "crossterm"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6"
dependencies = [
"bitflags 2.11.0",
"crossterm_winapi",
"mio",
"parking_lot",
"rustix 0.38.44",
"serde",
"signal-hook",
"signal-hook-mio",
"winapi",
]
[[package]]
name = "crossterm_winapi"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
dependencies = [
"winapi",
]
[[package]]
name = "cursor-icon"
version = "1.2.0"
@@ -411,6 +585,18 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
[[package]]
name = "either"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "encode_unicode"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
[[package]]
name = "equivalent"
version = "1.0.2"
@@ -427,6 +613,17 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "fd-lock"
version = "4.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78"
dependencies = [
"cfg-if",
"rustix 1.1.4",
"windows-sys 0.59.0",
]
[[package]]
name = "find-msvc-tools"
version = "0.1.9"
@@ -621,6 +818,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
version = "0.5.2"
@@ -633,6 +836,30 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
[[package]]
name = "iana-time-zone"
version = "0.1.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"log",
"wasm-bindgen",
"windows-core 0.62.2",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "indexmap"
version = "2.13.0"
@@ -643,6 +870,30 @@ dependencies = [
"hashbrown 0.16.1",
]
[[package]]
name = "is_executable"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baabb8b4867b26294d818bf3f651a454b6901431711abb96e296245888d6e8c4"
dependencies = [
"windows-sys 0.60.2",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
[[package]]
name = "itertools"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
dependencies = [
"either",
]
[[package]]
name = "jni"
version = "0.21.1"
@@ -806,6 +1057,18 @@ dependencies = [
"paste",
]
[[package]]
name = "mio"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
dependencies = [
"libc",
"log",
"wasi",
"windows-sys 0.61.2",
]
[[package]]
name = "naga"
version = "0.19.2"
@@ -865,6 +1128,15 @@ dependencies = [
"jni-sys",
]
[[package]]
name = "nu-ansi-term"
version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "num-traits"
version = "0.2.19"
@@ -876,9 +1148,9 @@ dependencies = [
[[package]]
name = "num_enum"
version = "0.7.5"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c"
checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26"
dependencies = [
"num_enum_derive",
"rustversion",
@@ -886,9 +1158,9 @@ dependencies = [
[[package]]
name = "num_enum_derive"
version = "0.7.5"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7"
checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8"
dependencies = [
"proc-macro-crate",
"proc-macro2",
@@ -1120,15 +1392,21 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.21.3"
version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
[[package]]
name = "once_cell_polyfill"
version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
name = "orbclient"
version = "0.3.50"
version = "0.3.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52ad2c6bae700b7aa5d1cc30c59bdd3a1c180b09dbaea51e2ae2b8e1cf211fdd"
checksum = "59aed3b33578edcfa1bc96a321d590d31832b6ad55a26f0313362ce687e9abd6"
dependencies = [
"libc",
"libredox",
@@ -1181,6 +1459,12 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "pathdiff"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
[[package]]
name = "percent-encoding"
version = "2.3.2"
@@ -1352,6 +1636,26 @@ dependencies = [
"bitflags 2.11.0",
]
[[package]]
name = "reedline"
version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bfa8cb0ad84c396c936d8abb814703d7042a433d2da75a0c7060cbdc89109f3"
dependencies = [
"chrono",
"crossterm",
"fd-lock",
"itertools",
"nu-ansi-term",
"serde",
"strip-ansi-escapes",
"strum",
"strum_macros",
"thiserror",
"unicode-segmentation",
"unicode-width 0.1.14",
]
[[package]]
name = "regex"
version = "1.12.3"
@@ -1475,6 +1779,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
"serde_derive",
]
[[package]]
@@ -1503,13 +1808,46 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "signal-hook"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
dependencies = [
"libc",
"signal-hook-registry",
]
[[package]]
name = "signal-hook-mio"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc"
dependencies = [
"libc",
"mio",
"signal-hook",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
dependencies = [
"errno",
"libc",
]
[[package]]
name = "simu"
version = "0.1.0"
dependencies = [
"atomic-wait",
"clap",
"clap-repl",
"parse_int",
"pixels",
"wait_on_address",
"winit",
"winit_input_helper",
]
@@ -1590,6 +1928,40 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
[[package]]
name = "strip-ansi-escapes"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a8f8038e7e7969abb3f1b7c2a811225e9296da208539e0f79c5251d6cac0025"
dependencies = [
"vte",
]
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "strum"
version = "0.26.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
[[package]]
name = "strum_macros"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.117",
]
[[package]]
name = "syn"
version = "1.0.109"
@@ -1668,18 +2040,18 @@ dependencies = [
[[package]]
name = "toml_datetime"
version = "1.0.0+spec-1.1.0"
version = "1.0.1+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e"
checksum = "9b320e741db58cac564e26c607d3cc1fdc4a88fd36c879568c07856ed83ff3e9"
dependencies = [
"serde_core",
]
[[package]]
name = "toml_edit"
version = "0.25.4+spec-1.1.0"
version = "0.25.5+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7193cbd0ce53dc966037f54351dbbcf0d5a642c7f0038c382ef9e677ce8c13f2"
checksum = "8ca1a40644a28bce036923f6a431df0b34236949d111cc07cb6dca830c9ef2e1"
dependencies = [
"indexmap",
"toml_datetime",
@@ -1689,9 +2061,9 @@ dependencies = [
[[package]]
name = "toml_parser"
version = "1.0.9+spec-1.1.0"
version = "1.0.10+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4"
checksum = "7df25b4befd31c4816df190124375d5a20c6b6921e2cad937316de3fccd63420"
dependencies = [
"winnow",
]
@@ -1745,18 +2117,53 @@ version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
[[package]]
name = "unicode-width"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
[[package]]
name = "unicode-xid"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "vte"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "231fdcd7ef3037e8330d8e17e61011a2c244126acc0a982f4040ac3f9f0bc077"
dependencies = [
"memchr",
]
[[package]]
name = "wait_on_address"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f46f0d222fdc7fac38a2ad9f0fabdc5af18d0c9d12c5fc52438509cf88674cf"
dependencies = [
"js-sys",
"libc",
"rustversion",
"wasm-bindgen",
"web-sys",
"windows-sys 0.61.2",
]
[[package]]
name = "walkdir"
version = "2.5.0"
@@ -1767,6 +2174,12 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasip2"
version = "1.0.2+wasi-0.2.9"
@@ -2124,7 +2537,7 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
dependencies = [
"windows-core",
"windows-core 0.52.0",
"windows-targets 0.52.6",
]
@@ -2137,6 +2550,41 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-core"
version = "0.62.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link",
"windows-result",
"windows-strings",
]
[[package]]
name = "windows-implement"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.117",
]
[[package]]
name = "windows-interface"
version = "0.59.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.117",
]
[[package]]
name = "windows-link"
version = "0.2.1"
@@ -2144,18 +2592,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.42.0"
name = "windows-result"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
dependencies = [
"windows_aarch64_gnullvm 0.42.2",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm 0.42.2",
"windows_x86_64_msvc 0.42.2",
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
dependencies = [
"windows-link",
]
[[package]]
@@ -2185,6 +2636,15 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-sys"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets 0.53.5",
]
[[package]]
name = "windows-sys"
version = "0.61.2"
@@ -2218,13 +2678,30 @@ dependencies = [
"windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
"windows_i686_gnullvm",
"windows_i686_gnullvm 0.52.6",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc 0.52.6",
]
[[package]]
name = "windows-targets"
version = "0.53.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
dependencies = [
"windows-link",
"windows_aarch64_gnullvm 0.53.1",
"windows_aarch64_msvc 0.53.1",
"windows_i686_gnu 0.53.1",
"windows_i686_gnullvm 0.53.1",
"windows_i686_msvc 0.53.1",
"windows_x86_64_gnu 0.53.1",
"windows_x86_64_gnullvm 0.53.1",
"windows_x86_64_msvc 0.53.1",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
@@ -2237,6 +2714,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
@@ -2249,6 +2732,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
@@ -2261,12 +2750,24 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
@@ -2279,6 +2780,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_i686_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
@@ -2291,6 +2798,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
@@ -2303,6 +2816,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
@@ -2315,6 +2834,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]]
name = "winit"
version = "0.30.13"
@@ -2379,9 +2904,9 @@ dependencies = [
[[package]]
name = "winnow"
version = "0.7.15"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945"
checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8"
dependencies = [
"memchr",
]
@@ -2457,18 +2982,18 @@ checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f"
[[package]]
name = "zerocopy"
version = "0.8.42"
version = "0.8.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3"
checksum = "efbb2a062be311f2ba113ce66f697a4dc589f85e78a4aea276200804cea0ed87"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.42"
version = "0.8.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f"
checksum = "0e8bc7269b54418e7aeeef514aa68f8690b8c0489a06b0136e5f57c4c5ccab89"
dependencies = [
"proc-macro2",
"quote",

View File

@@ -3,4 +3,5 @@ resolver = "3"
members = ["simu","asm"]
[profile.release]
debug = "line-tables-only"
opt-level = 2
# panic = "abort"

View File

@@ -31,9 +31,10 @@ syntaxe supplémentaire supportée:
## Features
rajouter --features=[liste séparé par des virgules]
- div_mul: Support des instruction de multiplication / division
- rgba: Écran au format RGBA plutot que 0BGR
- rgba: Écran au format RGBA plutot que 0BGR (alpha ignoré mais stocké)
- rich_keyboard: rajoute trois champs de mmio pour le clavier. Voir MMIO
- debug: repl similaire a la version python du simulateur
- futex: accélère le programme. ne marche pas sur les macs. actif par default, utiliser --no-default-features pour le desactiver
### instruction spéciale:
halt (jump 0) met le programme en pause, mais on peut se reveiller par des interuptions
@@ -43,7 +44,7 @@ call 0 termine l'exécution du simulateur proprement
## mmio:
- 0x01000000 à 0x0112c000 : Écran en lecture/écriture. un pixel par 32bits, de gauche a droite puis de bas en haut.
Format de pixel en 0BGR, 4 bits par couleur.
Passage au format RGBA (a pour alpha) avec la feature rgba
Passage au format RGBA (alpha ignoré, mais stocké) avec la feature rgba
- 0x01200000 : Clavier (scancode) (lecture seule)
- 0x01200004 : Horloge (millisecondes écoulé depuis le début de la simulation, wrappe tout les 49 jours) (lecture seule)
- 0x01200008 : Boutons de la souris (OR des boutons préssés) Gauche = 1, Droit=2, Clic Molette = 3, Autres non testé (lecture seule)
@@ -78,6 +79,7 @@ de même, `reti` ne peut pas être appellé par une sous fonction appellée depu
Les intéruptions et leurs arguments, par priorité croissante:
### 0: Point d'entrée
C'est ici que le programme commence. Seul cas d'utilisation
(ce n'est pas vraiment une interruption, juste la première entrée dans la jump table)
### 1: MMIO
Doivent être activé par le MMIO a l'adresse 0x01201000, en y écrivant le OR des (1<<identifiant)
On toujours pour argument (r0) leur identifiant

View File

@@ -207,7 +207,9 @@ impl Instruction {
}
};
if jump_distance > 15 {
println!("Error, cannot skip more than 15 instructions");
println!(
"Error, cannot skip {jump_distance} which is more than 15 instructions"
);
return Err(());
}
encode_op2(11, cond.into(), jump_distance, reg.into(), *op2)

View File

@@ -4,15 +4,21 @@ version = "0.1.0"
edition = "2024"
[dependencies]
atomic-wait = "1.1.0"
pixels = "0.15.0"
winit = { version = "0.30.13", features = ["x11", "x11-dl", "x11rb", "ahash", "bytemuck", "memmap2", "rwh_06", "sctk", "sctk-adwaita"] }
winit_input_helper = "0.17.0"
parse_int = { version = "0.9.0", optional = true }
wait_on_address = { version = "0.1.4", optional = true }
clap-repl = { version = "0.3.2", optional = true }
clap = { version = "4.6.0", optional = true }
[features]
default = ["futex"]
div_mul = []
rgba = []
rich_keyboard = []
debug = ["dep:parse_int"]
debug = ["dep:parse_int","dep:clap-repl","dep:clap"]
futex = ["dep:wait_on_address"]
clap-repl = ["dep:clap-repl"]
clap = ["dep:clap"]

View File

@@ -1,15 +1,17 @@
use crate::wait::WaitOnAtomic;
#[cfg(feature = "debug")]
use std::collections::HashMap;
use std::{
hint::{likely, unlikely, unreachable_unchecked},
hint::{cold_path, likely, unlikely, unreachable_unchecked},
io::Read,
mem::transmute,
ops::{Index, IndexMut},
process::exit,
sync::atomic::AtomicU32,
time::{self, Instant},
};
#[cfg(not(feature = "debug"))]
use std::process::exit;
pub(crate) struct SharedState {
pub(crate) keyboard: [AtomicU32; 4],
pub(crate) screen_buf: [AtomicU32; 480 * 640],
@@ -32,17 +34,26 @@ enum Op2 {
}
struct Reg(u8);
#[allow(unused)] //constructed by transmute
#[repr(u8)]
enum Cond {
Ifeq,
Ifne,
Iflt,
Ifge,
Ifgt,
Ifle,
Ifult,
Ifuge,
Ifugt,
Ifule,
Ifeq = 0b000,
Ifne = 0b0001,
UK1 = 2,
UK2 = 3,
UK3 = 4,
UK4 = 5,
UK5 = 6,
UK6 = 7,
Iflt = 0b1000,
Ifge = 0b1001,
Ifgt = 0b1010,
Ifle = 0b1011,
Ifult = 0b1100,
Ifuge = 0b1101,
Ifugt = 0b1110,
Ifule = 0b1111,
}
#[derive(Debug)]
@@ -73,20 +84,10 @@ pub enum MMIOInterupt {
}
impl From<u8> for Cond {
#[inline(always)]
fn from(value: u8) -> Self {
match value {
0b0000 => Cond::Ifeq,
0b0001 => Cond::Ifne,
0b1000 => Cond::Iflt,
0b1001 => Cond::Ifge,
0b1010 => Cond::Ifgt,
0b1011 => Cond::Ifle,
0b1100 => Cond::Ifult,
0b1101 => Cond::Ifuge,
0b1110 => Cond::Ifugt,
0b1111 => Cond::Ifule,
_ => iot(),
}
//unsafe if called with value >= 15 buuut only ever called on actually an u4 so it's ok
unsafe { transmute(value) }
}
}
@@ -108,8 +109,9 @@ impl From<u32> for InteruptKind {
}
impl Cond {
fn eval(self, a: u32, b: u32) -> bool {
match self {
#[inline(always)]
fn eval(self, a: u32, b: u32) -> Option<bool> {
Some(match self {
Cond::Ifeq => a == b,
Cond::Ifne => a != b,
Cond::Iflt => (a as i32) < (b as i32),
@@ -120,10 +122,12 @@ impl Cond {
Cond::Ifuge => a >= b,
Cond::Ifugt => a > b,
Cond::Ifule => a <= b,
}
_ => return None,
})
}
}
#[allow(unused)] //depen on features
enum Instruction {
Copy(Reg, Op2),
Add(Reg, Reg, Op2),
@@ -162,7 +166,6 @@ impl TryFrom<u32> for Instruction {
Ok(match value >> 30 {
0b00 => {
let t = value & (1 << 29); // 3rd bit set
let value = value - t;
let t = t != 0;
if t {
Self::Call(value)
@@ -274,6 +277,7 @@ impl Display for Cond {
Cond::Ifuge => write!(f, "ifuge"),
Cond::Ifugt => write!(f, "ifugt"),
Cond::Ifule => write!(f, "ifule"),
_ => write!(f, "unknown"),
}
}
}
@@ -312,7 +316,7 @@ pub(crate) fn instr_to_text(i: u32, a: u32, book: &HashMap<u32, String>) -> Stri
format!("skip {} {cond} {reg} {op2}", addr(d as u32))
}
Instruction::Jump(a) => format!("jump {}", addr(a)),
Instruction::Call(a) => format!("call {}", addr(a)),
Instruction::Call(a) => format!("call {}", addr(a % 0x1000_0000)),
Instruction::Ret() => format!("ret"),
Instruction::Reti() => format!("reti"),
Instruction::Swi() => format!("swi"),
@@ -337,7 +341,7 @@ pub struct Computer {
#[cfg(feature = "debug")]
pub(crate) error: bool,
#[cfg(feature = "debug")]
pub(crate) book: HashMap<u32, String>,
pub(crate) book: (HashMap<u32, String>, HashMap<String, u32>),
}
impl Index<Reg> for Computer {
@@ -354,10 +358,6 @@ impl IndexMut<Reg> for Computer {
}
}
fn iot() -> ! {
exit(1);
}
impl Computer {
pub fn new(filename: String) -> Self {
let mut new = Self {
@@ -370,7 +370,7 @@ impl Computer {
#[cfg(feature = "debug")]
error: false,
#[cfg(feature = "debug")]
book: HashMap::new(),
book: (HashMap::new(), HashMap::new()),
};
let mut buf = String::new();
std::fs::File::open(filename)
@@ -388,14 +388,16 @@ impl Computer {
while let Some((_, line)) = lines.next() {
if let Some([addr, s]) = line.split_ascii_whitespace().collect::<Vec<_>>().as_array() {
if let Ok(i) = u32::from_str_radix(addr, 16) {
new.book.insert(i, s.to_string());
new.book.0.insert(i, s.to_string());
new.book.1.insert(s.to_string(), i);
}
}
}
new
}
#[inline(always)]
pub fn step(&mut self) {
pub fn step(&mut self, s: usize) {
match self.interupts {
InteruptState::Disabled => {}
InteruptState::Enabled => {
@@ -414,311 +416,345 @@ impl Computer {
}
InteruptState::Serving(..) => {}
}
for _ in 0..s {
//potentially just changed by interupt.
let next_opcode = self.ram[self.pc];
//potentially just changed by interupt.
let next_opcode = self.ram[self.pc];
let instruction = Instruction::try_from(next_opcode);
let instruction = Instruction::try_from(next_opcode);
match instruction {
Ok(instruction) => {
match instruction {
Instruction::Copy(reg, op2) => {
self[reg] = self.resolve(op2);
self.pc += 1;
}
Instruction::Add(reg, reg1, op2) => {
self[reg] = self[reg1] + self.resolve(op2);
self.pc += 1;
}
Instruction::Sub(reg, reg1, op2) => {
self[reg] = self[reg1] - self.resolve(op2);
self.pc += 1;
}
Instruction::Or(reg, reg1, op2) => {
self[reg] = self[reg1] | self.resolve(op2);
self.pc += 1;
}
Instruction::And(reg, reg1, op2) => {
self[reg] = self[reg1] & self.resolve(op2);
self.pc += 1;
}
Instruction::Xor(reg, reg1, op2) => {
self[reg] = self[reg1] ^ self.resolve(op2);
self.pc += 1;
}
Instruction::Lsl(reg, reg1, op2) => {
self[reg] = self[reg1] << self.resolve(op2);
self.pc += 1;
}
Instruction::Lsr(reg, reg1, op2) => {
self[reg] = self[reg1] >> self.resolve(op2);
self.pc += 1;
}
Instruction::Asr(reg, reg1, op2) => {
self[reg] = (self[reg1] as i32 >> self.resolve(op2)) as u32;
self.pc += 1;
}
Instruction::Umull(reg, reg1, op2) => {
self[reg] = self[reg1].wrapping_mul(self.resolve(op2));
self.pc += 1;
}
Instruction::Smull(reg, reg1, op2) => {
self[reg] =
(self[reg1] as i32).wrapping_mul(self.resolve(op2) as i32) as u32;
self.pc += 1;
}
Instruction::Umulh(reg, reg1, op2) => {
self[reg] = self[reg1].widening_mul(self.resolve(op2)).1;
self.pc += 1;
}
Instruction::Smulh(reg, reg1, op2) => {
self[reg] =
(self[reg1] as i32).widening_mul(self.resolve(op2) as i32).1 as u32;
self.pc += 1;
}
Instruction::Div(reg, reg1, op2) => {
self.pc += 1;
let d = self.resolve(op2);
if unlikely(d == 0) {
self.serve_interupt(
InteruptKind::DivByZero,
[reg.0.into(), self[reg1]],
);
return;
match instruction {
Ok(instruction) => {
match instruction {
Instruction::Copy(reg, op2) => {
self[reg] = self.resolve(op2);
self.pc += 1;
}
self[reg] = self[reg1] / d;
}
Instruction::Mod(reg, reg1, op2) => {
self[reg] = self[reg1] % self.resolve(op2);
self.pc += 1
}
Instruction::Store(reg, op2, reg1) => {
self.pc += 1;
let addr = (self[reg].wrapping_add(self.resolve(op2))) as usize;
if !addr.is_multiple_of(4) {
self.serve_interupt(
InteruptKind::IllegalLoadStore,
[1, addr as u32, self[reg1]],
);
return;
Instruction::Add(reg, reg1, op2) => {
self[reg] = self[reg1] + self.resolve(op2);
self.pc += 1;
}
if addr <= 0x00ffffff {
self.ram[addr / 4] = self[reg1];
} else if addr <= 0x00ff_ffff + 480 * 640 * 4 {
let buf_addr = (addr - 0x0100_0000) / 4;
let dat = self[reg1] & 0x00FF_FFFF;
(&SHARED.screen_buf[buf_addr])
.store(dat, std::sync::atomic::Ordering::Relaxed);
} else if addr == 0x0120_1000 {
(&SHARED.external_enabled_interupts)
.store(self[reg1], std::sync::atomic::Ordering::Relaxed);
} else {
self.serve_interupt(InteruptKind::IllegalOpcode, [next_opcode]);
Instruction::Sub(reg, reg1, op2) => {
self[reg] = self[reg1] - self.resolve(op2);
self.pc += 1;
}
}
Instruction::Load(reg, reg1, op2) => {
self.pc += 1;
let addr = (self[reg1].wrapping_add(self.resolve(op2))) as usize;
if !addr.is_multiple_of(4) {
self.serve_interupt(
InteruptKind::IllegalLoadStore,
[0, addr as u32, reg.0 as u32],
);
return;
Instruction::Or(reg, reg1, op2) => {
self[reg] = self[reg1] | self.resolve(op2);
self.pc += 1;
}
self[reg] = if addr <= 0x00ffffff {
self.ram[addr / 4]
} else if addr <= 0x00ffffff + 480 * 640 * 4 {
let buf_addr = (addr - 0x0100_0000) / 4;
(&SHARED.screen_buf[buf_addr])
.load(std::sync::atomic::Ordering::Relaxed)
} else {
match addr as isize - 0x0120_0000 {
#[cfg(feature = "rich_keyboard")]
-12 => {
SHARED.keyboard[0].load(std::sync::atomic::Ordering::Relaxed)
Instruction::And(reg, reg1, op2) => {
self[reg] = self[reg1] & self.resolve(op2);
self.pc += 1;
}
Instruction::Xor(reg, reg1, op2) => {
self[reg] = self[reg1] ^ self.resolve(op2);
self.pc += 1;
}
Instruction::Lsl(reg, reg1, op2) => {
self[reg] = (self[reg1] as u64).wrapping_shl(self.resolve(op2)) as u32;
self.pc += 1;
}
Instruction::Lsr(reg, reg1, op2) => {
self[reg] = (self[reg1] as u64).wrapping_shr(self.resolve(op2)) as u32;
self.pc += 1;
}
Instruction::Asr(reg, reg1, op2) => {
self[reg] = (self[reg1] as i64).wrapping_shr(self.resolve(op2)) as u32;
self.pc += 1;
}
Instruction::Umull(reg, reg1, op2) => {
self[reg] = self[reg1].wrapping_mul(self.resolve(op2));
self.pc += 1;
}
Instruction::Smull(reg, reg1, op2) => {
self[reg] =
(self[reg1] as i32).wrapping_mul(self.resolve(op2) as i32) as u32;
self.pc += 1;
}
Instruction::Umulh(reg, reg1, op2) => {
self[reg] = self[reg1].widening_mul(self.resolve(op2)).1;
self.pc += 1;
}
Instruction::Smulh(reg, reg1, op2) => {
self[reg] =
(self[reg1] as i32).widening_mul(self.resolve(op2) as i32).1 as u32;
self.pc += 1;
}
Instruction::Div(reg, reg1, op2) => {
self.pc += 1;
let d = self.resolve(op2);
if unlikely(d == 0) {
self.serve_interupt(
InteruptKind::DivByZero,
[reg.0.into(), self[reg1]],
);
return;
}
self[reg] = self[reg1] / d;
}
Instruction::Mod(reg, reg1, op2) => {
self[reg] = self[reg1] % self.resolve(op2);
self.pc += 1
}
Instruction::Store(reg, op2, reg1) => {
self.pc += 1;
let addr = (self[reg].wrapping_add(self.resolve(op2))) as usize;
if !addr.is_multiple_of(4) {
self.serve_interupt(
InteruptKind::IllegalLoadStore,
[1, addr as u32, self[reg1]],
);
return;
}
if addr <= 0x00ffffff {
self.ram[addr / 4] = self[reg1];
} else if addr <= 0x00ff_ffff + 480 * 640 * 4 {
let buf_addr = (addr - 0x0100_0000) / 4;
let dat = if cfg!(feature = "rgba") {
self[reg1]
} else {
self[reg1] & 0x00FF_FFFF
};
(&SHARED.screen_buf[buf_addr])
.store(dat, std::sync::atomic::Ordering::Relaxed);
} else if addr == 0x0120_1000 {
(&SHARED.external_enabled_interupts)
.store(self[reg1], std::sync::atomic::Ordering::Relaxed);
} else {
cold_path();
self.serve_interupt(InteruptKind::IllegalOpcode, [next_opcode]);
}
}
Instruction::Load(reg, reg1, op2) => {
self.pc += 1;
let addr = (self[reg1].wrapping_add(self.resolve(op2))) as usize;
if !addr.is_multiple_of(4) {
self.serve_interupt(
InteruptKind::IllegalLoadStore,
[0, addr as u32, reg.0 as u32],
);
return;
}
self[reg] = if addr <= 0x00ffffff {
self.ram[addr / 4]
} else if addr <= 0x00ffffff + 480 * 640 * 4 {
let buf_addr = (addr - 0x0100_0000) / 4;
(&SHARED.screen_buf[buf_addr])
.load(std::sync::atomic::Ordering::Relaxed)
} else {
match addr as isize - 0x0120_0000 {
#[cfg(feature = "rich_keyboard")]
-12 => SHARED.keyboard[0]
.load(std::sync::atomic::Ordering::Relaxed),
#[cfg(feature = "rich_keyboard")]
-8 => SHARED.keyboard[1]
.load(std::sync::atomic::Ordering::Relaxed),
#[cfg(feature = "rich_keyboard")]
-4 => SHARED.keyboard[2]
.load(std::sync::atomic::Ordering::Relaxed),
0 => SHARED.keyboard[3]
.load(std::sync::atomic::Ordering::Relaxed),
4 => time::Instant::now()
.duration_since(self.creation)
.as_millis()
as u32,
8 => SHARED.mouse[0].load(std::sync::atomic::Ordering::Relaxed),
12 => {
SHARED.mouse[1].load(std::sync::atomic::Ordering::Relaxed)
}
16 => {
SHARED.mouse[2].load(std::sync::atomic::Ordering::Relaxed)
}
//guaranted by the inequality and is multiple of 4
_ => {
cold_path();
self.serve_interupt(
InteruptKind::IllegalOpcode,
[next_opcode],
);
return;
}
}
#[cfg(feature = "rich_keyboard")]
-8 => SHARED.keyboard[1].load(std::sync::atomic::Ordering::Relaxed),
#[cfg(feature = "rich_keyboard")]
-4 => SHARED.keyboard[2].load(std::sync::atomic::Ordering::Relaxed),
0 => SHARED.keyboard[3].load(std::sync::atomic::Ordering::Relaxed),
4 => time::Instant::now()
.duration_since(self.creation)
.as_millis() as u32,
8 => SHARED.mouse[0].load(std::sync::atomic::Ordering::Relaxed),
12 => SHARED.mouse[1].load(std::sync::atomic::Ordering::Relaxed),
16 => SHARED.mouse[2].load(std::sync::atomic::Ordering::Relaxed),
//guaranted by the inequality and is multiple of 4
_ => {
self.serve_interupt(InteruptKind::IllegalOpcode, [next_opcode]);
return;
};
}
Instruction::Push(op2) => {
self.sp -= 1;
self.ram[self.sp] = self.resolve(op2);
self.pc += 1;
}
Instruction::Pop(reg) => {
self[reg] = self.ram[self.sp];
self.sp += 1;
self.pc += 1;
}
Instruction::Skip(d, cond, reg, op2) => {
self.pc += 1;
match cond.eval(self[reg], self.resolve(op2)) {
Some(false) => { /*Nothing*/ }
Some(true) => self.pc += d as usize,
None => {
cold_path();
self.serve_interupt(InteruptKind::IllegalOpcode, [next_opcode])
}
}
};
}
Instruction::Push(op2) => {
self.sp -= 1;
self.ram[self.sp] = self.resolve(op2);
self.pc += 1;
}
Instruction::Pop(reg) => {
self[reg] = self.ram[self.sp];
self.sp += 1;
self.pc += 1;
}
Instruction::Skip(d, cond, reg, op2) => {
self.pc += 1;
if cond.eval(self[reg], self.resolve(op2)) {
self.pc += d as usize
}
}
Instruction::Jump(mut addr) => {
if addr & (1 << 28) != 0 {
addr += 7 << 29;
} else if addr == 0 {
#[cfg(feature = "debug")]
{
match self.interupts {
InteruptState::Disabled => {
println!("program terminated");
Instruction::Jump(addr) => {
if unlikely(addr == 0) {
#[cfg(feature = "debug")]
{
match self.interupts {
InteruptState::Disabled => {
println!("program terminated");
self.error = true;
return;
}
_ => (),
}
if SHARED
.external_enabled_interupts
.load(std::sync::atomic::Ordering::Relaxed)
== 0
{
println!("Program terminated");
self.error = true;
return;
}
_ => (),
println!("awaiting interupt...");
}
if SHARED
.external_enabled_interupts
.load(std::sync::atomic::Ordering::Relaxed)
== 0
SHARED.external_interupts.wait(0);
return;
}
self.pc = ((addr + self.pc as u32) & 0x1FFF_FFFF) as usize;
}
Instruction::Call(addr) => {
//WARNING! addr still has the type bit set at this point!
self.sp -= 1;
self.ram[self.sp] = ((self.pc << 2) + 4) as u32;
if unlikely(addr == 0 + (1 << 29) /*t bit*/) {
#[cfg(feature = "debug")]
{
println!("Program terminated");
println!("program terminated");
self.error = true;
return;
}
println!("awaiting interupt...");
#[cfg(not(feature = "debug"))]
exit(0);
}
atomic_wait::wait(&SHARED.external_interupts, 0);
//The mask take care of both wrapping and shedding the t bit
self.pc = ((addr + self.pc as u32) & 0x1FFF_FFFF) as usize;
}
self.pc = (addr + self.pc as u32) as usize;
}
Instruction::Call(mut addr) => {
self.sp -= 1;
self.ram[self.sp] = ((self.pc << 2) + 4) as u32;
if addr & (1 << 28) != 0 {
addr += 7 << 29;
} else if unlikely(addr == 0) {
#[cfg(feature = "debug")]
{
println!("program terminated");
self.error = true;
return;
}
#[cfg(not(feature = "debug"))]
exit(0);
Instruction::Ret() => {
self.pc = (self.ram[self.sp] >> 2) as usize;
self.sp += 1;
}
self.pc = (addr + self.pc as u32) as usize;
}
Instruction::Ret() => {
self.pc = (self.ram[self.sp] >> 2) as usize;
self.sp += 1;
}
Instruction::Reti() => {
let mut ret_index = None;
let mut ret_value = 0;
Instruction::Reti() => {
let mut ret_index = None;
let mut ret_value = 0;
match self.interupts {
InteruptState::Serving(kind, prev) => {
match prev.highest_one() {
None => self.interupts = InteruptState::Enabled,
Some(i) => {
self.interupts =
InteruptState::Serving(i.into(), prev ^ (1 << i))
}
}
match kind {
InteruptKind::MMIO => {
(&SHARED.external_interupts)
.store(0, std::sync::atomic::Ordering::Release);
atomic_wait::wake_all(&SHARED.external_interupts);
//no need to check prev because MMIO is the lowest priority
self.interupts = InteruptState::Enabled
}
InteruptKind::Swi => {}
InteruptKind::DivByZero | InteruptKind::UnsupportedOpcode => {
ret_index = Some(self.regs[0]);
ret_value = self.regs[1];
}
InteruptKind::IllegalLoadStore => {
if self.regs[0] == 0 {
ret_value = self.regs[1];
ret_index = Some(self.regs[2]);
match self.interupts {
InteruptState::Serving(kind, prev) => {
match prev.highest_one() {
None => self.interupts = InteruptState::Enabled,
Some(i) => {
self.interupts =
InteruptState::Serving(i.into(), prev ^ (1 << i))
}
}
InteruptKind::IllegalOpcode => {}
match kind {
InteruptKind::MMIO => {
(&SHARED.external_interupts)
.store(0, std::sync::atomic::Ordering::Release);
SHARED.external_interupts.signal();
//no need to check prev because MMIO is the lowest priority
self.interupts = InteruptState::Enabled
}
InteruptKind::Swi => {}
InteruptKind::DivByZero
| InteruptKind::UnsupportedOpcode => {
ret_index = Some(self.regs[0]);
ret_value = self.regs[1];
}
InteruptKind::IllegalLoadStore => {
if self.regs[0] == 0 {
ret_value = self.regs[1];
ret_index = Some(self.regs[2]);
}
}
InteruptKind::IllegalOpcode => {}
}
}
_ => { /* This is a troubling case but ... well it's ok */ }
}
let ret = self.ram[self.sp];
self.pc = (ret & 0x0FFF_FFFF) as usize;
self.sp += 1 as usize;
for i in (0..(ret >> 28) as usize).rev() {
self.regs[i] = self.ram[self.sp];
self.sp += 1
}
if let Some(idx) = ret_index {
self.regs[idx as usize] = ret_value;
}
_ => { /* This is a troubling case but ... well it's ok */ }
}
let ret = self.ram[self.sp];
self.pc = (ret & 0x0FFF_FFFF) as usize;
self.sp += 1 as usize;
for i in (0..(ret >> 28) as usize).rev() {
self.regs[i] = self.ram[self.sp];
self.sp += 1
Instruction::Eint() => {
match self.interupts {
InteruptState::Disabled => self.interupts = InteruptState::Enabled,
_ => {}
}
self.pc += 1;
}
if let Some(idx) = ret_index {
self.regs[idx as usize] = ret_value;
}
}
Instruction::Eint() => {
match self.interupts {
InteruptState::Disabled => self.interupts = InteruptState::Enabled,
_ => {}
}
self.pc += 1;
}
Instruction::Dint() => {
self.interupts = InteruptState::Disabled;
self.pc += 1;
Instruction::Dint() => {
self.interupts = InteruptState::Disabled;
self.pc += 1;
(&SHARED.external_enabled_interupts)
.store(0, std::sync::atomic::Ordering::Relaxed);
(&SHARED.external_interupts).store(0, std::sync::atomic::Ordering::Relaxed);
atomic_wait::wake_all(&SHARED.external_interupts);
}
Instruction::Swi() => {
self.pc += 1;
self.serve_interupt(InteruptKind::Swi, []);
}
Instruction::GetStack(reg) => {
self[reg] = (self.sp << 2) as u32;
self.pc += 1;
}
Instruction::SetStack(op2) => {
let v = self.resolve(op2);
if likely(v.is_multiple_of(4)) {
self.sp = (v >> 2) as usize;
} else {
self.sp = usize::MAX //Yes, that means that clever program using sp to store information wont work on my emulator. Deal with it
(&SHARED.external_enabled_interupts)
.store(0, std::sync::atomic::Ordering::Relaxed);
(&SHARED.external_interupts)
.store(0, std::sync::atomic::Ordering::Relaxed);
SHARED.external_interupts.signal();
}
self.pc += 1;
Instruction::Swi() => {
self.pc += 1;
self.serve_interupt(InteruptKind::Swi, []);
}
Instruction::GetStack(reg) => {
self[reg] = (self.sp << 2) as u32;
self.pc += 1;
}
Instruction::SetStack(op2) => {
let v = self.resolve(op2);
if likely(v.is_multiple_of(4)) {
self.sp = (v >> 2) as usize;
} else {
self.sp = usize::MAX //Yes, that means that clever program using sp to store information wont work on my emulator. Deal with it
}
self.pc += 1;
}
};
}
Err((kind, rx, ry, op2, opcode)) => {
self.pc += 1;
match kind {
InteruptKind::UnsupportedOpcode => self.serve_interupt(
kind,
[rx.0.into(), self[ry], self.resolve(op2), opcode],
),
InteruptKind::IllegalOpcode => {
cold_path();
self.serve_interupt(kind, [next_opcode])
}
_ => unsafe { unreachable_unchecked() },
}
};
}
Err((kind, rx, ry, op2, opcode)) => {
self.pc += 1;
match kind {
InteruptKind::UnsupportedOpcode => self
.serve_interupt(kind, [rx.0.into(), self[ry], self.resolve(op2), opcode]),
InteruptKind::IllegalOpcode => self.serve_interupt(kind, [next_opcode]),
_ => unsafe { unreachable_unchecked() },
}
}
}
}
#[cfg(feature = "debug")]
pub fn debug_step(&mut self, s: usize) {
self.step(s);
}
#[inline(always)]
fn resolve(&self, op2: Op2) -> u32 {
match op2 {
Op2::Direct(v) => v,

View File

@@ -1,14 +1,8 @@
#![feature(
likely_unlikely,
widening_mul,
sync_unsafe_cell,
int_lowest_highest_one
)]
#![feature(likely_unlikely, widening_mul, int_lowest_highest_one)]
#![deny(clippy::all)]
use std::env::args;
use std::hint::unlikely;
use std::io::stdin;
use std::process::exit;
use std::sync::{
Arc,
@@ -17,18 +11,18 @@ use std::sync::{
use std::thread::scope;
use std::time::{Duration, Instant};
use pixels::{Error, Pixels, SurfaceTexture};
use pixels::wgpu::{BlendState, Color};
use pixels::{Error, Pixels, PixelsBuilder, SurfaceTexture};
use winit::application::ApplicationHandler;
use winit::dpi::LogicalSize;
use winit::event::WindowEvent;
use winit::event_loop::EventLoop;
use winit::platform::modifier_supplement::KeyEventExtModifierSupplement;
use winit::platform::scancode::PhysicalKeyExtScancode;
use winit::window::Window;
// use winit_input_helper::WinitInputHelper;
use crate::cpu::{Computer, MMIOInterupt};
mod wait;
use wait::WaitOnAtomic;
mod cpu;
use cpu::SHARED;
@@ -37,7 +31,7 @@ fn wait_int() {
while unlikely(v != 0) {
#[cfg(feature = "debug")]
println!("wating for interupt clear {v}");
atomic_wait::wait(&SHARED.external_interupts, v);
SHARED.external_interupts.wait(v);
v = (&SHARED.external_interupts).load(Acquire);
}
}
@@ -68,7 +62,12 @@ impl<'a> ApplicationHandler for App<'a> {
self.w = Some(window.clone());
let size = window.inner_size();
let surface_texture = SurfaceTexture::new(size.width, size.height, window);
self.pixels = Some(Pixels::new(WIDTH, HEIGHT, surface_texture).unwrap());
let pix = PixelsBuilder::new(WIDTH, HEIGHT, surface_texture)
.clear_color(Color::BLACK)
.blend_state(BlendState::REPLACE)
.build();
self.pixels = Some(pix.unwrap());
}
fn window_event(
@@ -93,20 +92,22 @@ impl<'a> ApplicationHandler for App<'a> {
print!("Keyboard event: ");
#[cfg(feature = "rich_keyboard")]
{
let kb0 = key_event
.text_with_all_modifiers()
.unwrap_or("")
.as_bytes()
.into_iter()
.fold(0, |a, e| a << 8 | (*e as u32));
use winit::platform::modifier_supplement::KeyEventExtModifierSupplement;
let kb0 = key_event.text_with_all_modifiers().map_or(u32::MAX, |s| {
s.as_bytes()
.into_iter()
.fold(0, |a, e| a << 8 | (*e as u32))
});
SHARED.keyboard[0].store(kb0, Relaxed);
let kb1 = key_event
.key_without_modifiers()
.to_text()
.unwrap_or("")
.as_bytes()
.into_iter()
.fold(0, |a, e| a << 8 | (*e as u32));
.map_or(u32::MAX, |s| {
s.as_bytes()
.into_iter()
.fold(0, |a, e| a << 8 | (*e as u32))
});
SHARED.keyboard[1].store(kb1, Relaxed);
let kb2 =
key_event.state.is_pressed() as u32 | ((key_event.repeat as u32) << 1);
@@ -122,7 +123,7 @@ impl<'a> ApplicationHandler for App<'a> {
(&SHARED.external_interupts).store(MMIOInterupt::Keyboard.into(), Release);
#[cfg(feature = "debug")]
println!("wake due to keyboard event");
atomic_wait::wake_all(&SHARED.external_interupts);
SHARED.external_interupts.signal();
}
}
WindowEvent::CursorMoved { position, .. } => {
@@ -151,7 +152,7 @@ impl<'a> ApplicationHandler for App<'a> {
(&SHARED.external_interupts).store(MMIOInterupt::MouseMove.into(), Release);
#[cfg(feature = "debug")]
println!("wake due mouse move");
atomic_wait::wake_all(&SHARED.external_interupts);
SHARED.external_interupts.signal();
}
}
// WindowEvent::MouseWheel {
@@ -185,7 +186,7 @@ impl<'a> ApplicationHandler for App<'a> {
(&SHARED.external_interupts).store(MMIOInterupt::MouseClick.into(), Release);
#[cfg(feature = "debug")]
println!("wake mouse click");
atomic_wait::wake_all(&SHARED.external_interupts);
SHARED.external_interupts.signal();
}
}
WindowEvent::ScaleFactorChanged { .. } => {
@@ -198,7 +199,7 @@ impl<'a> ApplicationHandler for App<'a> {
!= 0;
if enabled {
(&SHARED.external_interupts).store(MMIOInterupt::VSync.into(), Relaxed);
atomic_wait::wake_all(&SHARED.external_interupts);
SHARED.external_interupts.signal();
wait_int();
}
let pix = self.pixels.as_mut().unwrap();
@@ -207,14 +208,9 @@ impl<'a> ApplicationHandler for App<'a> {
for (addr, ubgr) in cpu::SHARED.screen_buf.iter().enumerate() {
let raw = ubgr.load(std::sync::atomic::Ordering::Relaxed);
#[cfg(not(feature = "rgba"))]
let rgba = [raw as u8, (raw >> 8) as u8, (raw >> 16) as u8, 0xff];
let rgba: [u8; 4] = raw.to_le_bytes();
#[cfg(feature = "rgba")]
let rgba = [
(raw >> 24) as u8,
(raw >> 16) as u8,
(raw >> 8) as u8,
raw as u8,
];
let rgba = raw.to_be_bytes();
for i in 0..4 {
screen[addr * 4 + i] = rgba[i];
}
@@ -265,6 +261,7 @@ impl<'a> ApplicationHandler for App<'a> {
let now = Instant::now();
if next < now {
next = now + Duration::from_secs_f64(1. / 30.);
println!("Warning: rendering is lagging!")
}
event_loop.set_control_flow(winit::event_loop::ControlFlow::WaitUntil(next));
if let Some(w) = self.w.as_ref() {
@@ -302,147 +299,13 @@ fn main() -> Result<(), Error> {
let mut simulation = Computer::new(program);
#[cfg(not(feature = "debug"))]
loop {
simulation.step();
simulation.step(64);
}
//ugly debug code, I should improve that using a real TUI crate
#[cfg(feature = "debug")]
{
let mut input = stdin().lines();
loop {
{
println!(
"interrupts are {:?}, with mmio interupts flags {}",
simulation.interupts,
SHARED.external_enabled_interupts.load(Relaxed)
);
for i in 0..8 {
println!(
"r{i} 0x{:08x} r{} 0x{:08x}",
simulation.regs[i],
i + 8,
simulation.regs[i + 8]
);
}
println!(
"SP: {:08x} PC: {:08x}",
simulation.sp * 4,
simulation.pc * 4
);
println!("RAM near SP");
let min_pc = (simulation.pc).min(0x0100_0000 / 4 - 8);
let min_sp = (simulation.sp).min(0x0100_0000 / 4 - 8);
for i in 0..8 {
println!(
"{:8x}: 0x{:08x}",
(min_sp + i) * 4,
simulation.ram[min_sp + i],
);
}
println!("Ram near PC");
for i in 0..8 {
let idx = min_pc + i;
let istr = simulation.ram[idx];
if let Some(s) = simulation.book.get(&(idx as u32 * 4)) {
println!("{s}:")
};
println!(
"{:8x}: 0x{:08x} {}",
idx * 4,
istr,
cpu::instr_to_text(istr, idx as u32 * 4, &simulation.book)
)
}
}
while {
let next = input.next().unwrap().unwrap();
let next: Vec<_> = next.split_ascii_whitespace().collect();
if next.len() > 0 {
match next[0] {
"s" | "step" => {
let n: usize = {
if next.len() >= 2 {
parse_int::parse(next[1]).unwrap_or(1)
} else {
1
}
};
for _ in 0..n {
if simulation.error {
println!("cannot step, cpu killed");
break;
}
simulation.step();
}
false
}
"r" | "run" => {
while !simulation.error {
simulation.step();
}
false
}
"p" | "print" => {
if next.len() >= 2 {
match parse_int::parse::<u32>(next[1]) {
Ok(i) => {
let v = simulation.ram[i as usize / 4];
println!(
"0x{:8x} -- {}",
v,
cpu::instr_to_text(v, i, &simulation.book)
);
true
}
Err(e) => {
println!("{e}");
true
}
}
} else {
println!("{HELP_MSG}");
true
}
}
"c" | "context" => false,
"u" | "up" => {
while !simulation.error
&& simulation.ram[simulation.pc] != 0x8800_0000
{
simulation.step();
}
false
}
"t" | "to" => {
if next.len() >= 2 {
match parse_int::parse::<u32>(next[1]) {
Ok(v) => {
while !simulation.error
&& simulation.pc != (v as usize / 4)
{
simulation.step();
}
false
}
Err(e) => {
println!("{e}");
true
}
}
} else {
println!("{HELP_MSG}");
true
}
}
_ => {
println!("{HELP_MSG}");
true
}
}
} else {
println!("{HELP_MSG}");
true
}
} {}
}
debug_loop(&mut simulation);
}
});
@@ -459,11 +322,210 @@ fn main() -> Result<(), Error> {
}
#[cfg(feature = "debug")]
const HELP_MSG: &str = "
step n - step trough n instructions (alias s)
run - run program until exit / error (alias r)
context - print context (alias c)
print n - print ram content at address n and next 8 (alias p)
up - run until the nex ret is reached (alias u)
to n - tun until PC = n (alias t)
";
fn debug_loop(com: &mut Computer) {
struct Wrap(DefaultCompleter, DefaultCompleter);
use clap::Parser;
use clap_repl::ClapEditor;
use clap_repl::reedline::{
Completer, DefaultCompleter, DefaultPrompt, DefaultPromptSegment, FileBackedHistory,
};
use crate::cpu::instr_to_text;
#[derive(Debug, Parser)]
#[command(name = "")] // This name will show up in clap's error messages, so it is important to set it to "".
enum Commands {
/// Step by single instrcution
#[command(alias = "s")]
Step {
///number of instruction to step (default one)
num: Option<usize>,
},
/// Run until program halt, or specified instruction is reached
#[command(alias = "r")]
Run {
/// Can be either a label or a address (support hex format)
desigantor: Option<String>,
},
/// run until the current function return.
#[command(alias = "u")]
Up,
/// Print memory at address. Support hexa format
#[command(alias = "p")]
Print { address: String },
/// Print the address associated with a label
#[command(alias = "l")]
Label { label: String },
/// Print context
#[command(alias = "c")]
Context,
}
let prompt = DefaultPrompt {
left_prompt: DefaultPromptSegment::Basic(">>".to_owned()),
right_prompt: DefaultPromptSegment::Empty,
};
let commands_comp = DefaultCompleter::new_with_wordlen(
["step", "run", "up", "print", "label", "help", "context"]
.map(|s| s.to_string())
.to_vec(),
0,
);
let mut labels_comp =
DefaultCompleter::with_inclusions("_0123456789".chars().collect::<Vec<_>>().as_slice())
.set_min_word_len(0);
labels_comp.insert(com.book.0.values().cloned().collect());
let editor = ClapEditor::<Commands>::builder()
.with_prompt(Box::new(prompt))
.with_editor_hook(|reed| {
reed.with_history(Box::new(
FileBackedHistory::with_file(1000, "debug_cmd.hist".into()).unwrap(),
))
.with_completer(Box::new(Wrap(commands_comp, labels_comp)))
.with_quick_completions(true)
.with_partial_completions(true)
})
.build();
debug_context(com);
editor.repl(|command| match command {
Commands::Step { num } => {
let steps = num.unwrap_or(1);
com.debug_step(steps);
debug_context(com);
}
Commands::Run { desigantor } => match desigantor {
Some(s) => match parse_int::parse::<usize>(s.as_str()) {
Ok(addr) => {
while com.pc != (addr / 4) && !com.error {
com.debug_step(1);
}
debug_context(com);
}
Err(_) => match com.book.1.get(s.as_str()).cloned() {
Some(addr) => {
while com.pc != (addr as usize / 4) && !com.error {
com.debug_step(1);
}
debug_context(com);
}
None => {
println!("Error, {s} cannot be interpreted as addr nor label")
}
},
},
None => {
while !com.error {
com.debug_step(64);
}
debug_context(com);
}
},
Commands::Up => {
let curr_sp = com.sp;
while (com.sp < curr_sp
|| (com.ram[com.pc] != (0b10001000 << 24) && com.ram[com.pc] != (0b10101000 << 24)))
&& !com.error
{
com.debug_step(1);
}
debug_context(com);
}
Commands::Print { address } => match parse_int::parse::<usize>(address.as_str()) {
Ok(addr) => match com.ram.get(addr / 4) {
Some(i) => {
println!(
"RAM at {addr:8x}: {:8x} {}",
i,
instr_to_text(*i, u32::MAX, &com.book.0)
)
}
None => println!("Cannot index RAM at address {addr:8x}"),
},
Err(_) => match com.book.1.get(address.as_str()).cloned() {
Some(addr) => println!(
"RAM at {addr:8x}: {:8x} {}",
com.ram[addr as usize / 4],
instr_to_text(com.ram[addr as usize / 4], addr, &com.book.0)
),
None => {
println!("Error, {address} cannot be interpreted as addr nor label")
}
},
},
Commands::Label { label } => match com.book.1.get(label.as_str()) {
Some(addr) => println!("label is at addr {addr}"),
None => println!("error: label not found"),
},
Commands::Context => debug_context(com),
});
exit(0);
impl Completer for Wrap {
fn complete(&mut self, line: &str, pos: usize) -> Vec<clap_repl::reedline::Suggestion> {
let trimmed = line.trim_start();
let line_parts = trimmed.splitn(2, ' ').collect::<Vec<_>>();
if line_parts.len() <= 1 {
self.0.complete(line, pos)
} else {
match line_parts[0] {
"r" | "run" | "p" | "print" | "l" | "label" => {
let trimmed_2 = line_parts[1].trim_start();
let offset = line.len() - trimmed_2.len();
let mut sub = self.1.complete(trimmed_2, pos - offset);
for sug in sub.iter_mut() {
use clap_repl::reedline::Span;
sug.span = Span {
start: sug.span.start + offset,
end: sug.span.end + offset,
}
}
sub
}
_ => Vec::new(),
}
}
}
}
}
#[cfg(feature = "debug")]
fn debug_context(com: &Computer) {
use crate::cpu::instr_to_text;
println!("Interupt state: {:?}", com.interupts);
for i in 0..8 {
println!(
"r{i} = {:8x} r{:<2} = {:8x}",
com.regs[i],
i + 8,
com.regs[i + 8]
);
}
println!("SP={:08x} PC={:08x}", com.sp * 4, com.pc * 4);
println!("RAM at SP | Ram at PC:");
let mut pc_lines = Vec::new();
for i in 0..16 {
match com.book.0.get(&((com.pc + i) as u32 * 4)) {
Some(label) => pc_lines.push(format!(" {label}:")),
None => {}
};
pc_lines.push(format!(
"{:08x} {}",
com.ram[com.pc + i],
instr_to_text(com.ram[com.pc + i], (com.pc + i) as u32 * 4, &com.book.0)
));
}
for (i, pc_l) in pc_lines.iter().enumerate() {
if com.sp + i < com.ram.len() {
println!("{:08x} | {pc_l}", com.ram[com.sp + i])
} else {
println!(" -- | {pc_l}")
}
}
}

35
simu/src/wait.rs Normal file
View File

@@ -0,0 +1,35 @@
use std::sync::atomic::AtomicU32;
#[cfg(feature = "futex")]
use wait_on_address::AtomicWait;
pub trait WaitOnAtomic {
fn wait(&self, v: u32);
fn signal(&self);
}
#[cfg(feature = "futex")]
impl WaitOnAtomic for AtomicU32 {
fn wait(&self, v: u32) {
<AtomicU32 as AtomicWait>::wait(self, v);
}
fn signal(&self) {
self.notify_one();
}
}
#[cfg(not(feature = "futex"))]
impl WaitOnAtomic for AtomicU32 {
fn wait(&self, v: u32) {
while self.load(std::sync::atomic::Ordering::Acquire) == v {
use std::{thread::sleep, time::Duration};
sleep(Duration::from_micros(500));
}
}
fn signal(&self) {
//
}
}