From e69ec33f854f3edeb973ca299750bcb436b5813f Mon Sep 17 00:00:00 2001 From: Cay Date: Sun, 12 Nov 2023 14:13:10 -0500 Subject: [PATCH 001/355] add editable memory/register prototype and scroll to executed line --- Cargo.lock | 442 +++++++++++++++++------------- Cargo.toml | 10 +- index.html | 2 + src/emulation_core/mips/memory.rs | 74 +++-- src/main.rs | 148 +++++++++- src/ui.rs | 1 + src/ui/console/component.rs | 37 ++- src/ui/hex_editor/component.rs | 193 +++++++++++++ src/ui/hex_editor/mod.rs | 1 + src/ui/hex_editor/util.rs | 0 src/ui/regview/component.rs | 66 ++++- src/ui/visual_datapath/mod.rs | 1 + static/backward.svg | 7 + static/cog.svg | 7 + static/folder-upload.svg | 7 + static/forward.svg | 7 + static/hammer.svg | 7 + static/next.svg | 7 + static/pause.svg | 7 + static/play.svg | 7 + static/previous.svg | 7 + static/rust-logo-blk.svg | 1 + static/stop.svg | 7 + static/styles/main.css | 11 +- static/styles/tailwind.css | 3 + tailwind.config.js | 5 + 26 files changed, 821 insertions(+), 244 deletions(-) create mode 100644 src/ui/hex_editor/component.rs create mode 100644 src/ui/hex_editor/mod.rs create mode 100644 src/ui/hex_editor/util.rs create mode 100644 static/backward.svg create mode 100644 static/cog.svg create mode 100644 static/folder-upload.svg create mode 100644 static/forward.svg create mode 100644 static/hammer.svg create mode 100644 static/next.svg create mode 100644 static/pause.svg create mode 100644 static/play.svg create mode 100644 static/previous.svg create mode 100644 static/rust-logo-blk.svg create mode 100644 static/stop.svg create mode 100644 static/styles/tailwind.css create mode 100644 tailwind.config.js diff --git a/Cargo.lock b/Cargo.lock index 353001015..195c342ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "akin" version = "0.4.0" @@ -20,6 +35,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "bincode" version = "1.3.3" @@ -37,9 +67,30 @@ checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9" [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "cc" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "cfg-if" @@ -53,24 +104,41 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "wasm-bindgen", ] +[[package]] +name = "console_log" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8aed40e4edbf4d3b4431ab260b63fdc40f5780a4766824329ea0f1eefe3c0f" +dependencies = [ + "log", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] [[package]] name = "futures" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" dependencies = [ "futures-channel", "futures-core", @@ -82,9 +150,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", "futures-sink", @@ -92,44 +160,44 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-io" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-macro" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] name = "futures-sink" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-util" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-channel", "futures-core", @@ -143,11 +211,17 @@ dependencies = [ "slab", ] +[[package]] +name = "gimli" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" + [[package]] name = "gloo" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a4bef6b277b3ab073253d4bca60761240cf8d6998f4bd142211957b69a61b20" +checksum = "28999cda5ef6916ffd33fb4a7b87e1de633c47c0dc6d97905fee1cdaa142b94d" dependencies = [ "gloo-console", "gloo-dialogs", @@ -210,9 +284,9 @@ dependencies = [ [[package]] name = "gloo-history" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd451019e0b7a2b8a7a7b23e74916601abf1135c54664e57ff71dcc26dfcdeb7" +checksum = "85725d90bf0ed47063b3930ef28e863658a7905989e9929a8708aab74a1d5e7f" dependencies = [ "gloo-events", "gloo-utils", @@ -226,14 +300,15 @@ dependencies = [ [[package]] name = "gloo-net" -version = "0.2.6" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9902a044653b26b99f7e3693a42f171312d9be8b26b5697bd1e43ad1f8a35e10" +checksum = "a66b4e3c7d9ed8d315fd6b97c8b1f74a7c6ecbbc2320e65ae7ed38b7068cc620" dependencies = [ "futures-channel", "futures-core", "futures-sink", "gloo-utils", + "http", "js-sys", "pin-project", "serde", @@ -283,9 +358,9 @@ dependencies = [ [[package]] name = "gloo-utils" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8e8fc851e9c7b9852508bc6e3f690f452f474417e8545ec9857b7f7377036b5" +checksum = "037fcb07216cb3a30f7292bd0176b050b7b9a052ba830ef7d5d65f6dc64ba58e" dependencies = [ "js-sys", "serde", @@ -325,27 +400,41 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.2.6" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ - "libc", + "bytes", + "fnv", + "itoa", ] +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "implicit-clone" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40fc102e70475c320b185cd18c1e48bba2d7210b63970a4d581ef903e4368ef7" +checksum = "7c6ecbd987bb94f1f3c76c6787879756cf4b6f73bfff48d79308e8c56b46f65f" dependencies = [ "indexmap", ] [[package]] name = "indexmap" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown", @@ -353,15 +442,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.5" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" -version = "0.3.61" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" dependencies = [ "wasm-bindgen", ] @@ -374,24 +463,30 @@ checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" [[package]] name = "libc" -version = "0.2.139" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "log" -version = "0.4.17" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] [[package]] name = "monaco" @@ -407,57 +502,66 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ "hermit-abi", "libc", ] +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "paste" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pin-project" -version = "1.0.12" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.12" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -478,12 +582,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.1.23" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97e3215779627f01ee256d2fad52f3d95e8e1c11e9fc6fd08f7cd455d5d5c78" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" dependencies = [ "proc-macro2", - "syn", + "syn 1.0.109", ] [[package]] @@ -495,7 +599,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "version_check", ] @@ -512,9 +616,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.51" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] @@ -538,39 +642,45 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.23" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustversion" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.12" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "serde" -version = "1.0.152" +version = "1.0.191" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "a834c4821019838224821468552240d4d95d14e751986442c816572d39a080c9" dependencies = [ "serde_derive", ] [[package]] name = "serde-wasm-bindgen" -version = "0.4.5" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf" +checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e" dependencies = [ "js-sys", "serde", @@ -579,20 +689,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.152" +version = "1.0.191" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +checksum = "46fa52d5646bce91b680189fe5b1c049d2ea38dabb4e2e7c8d00ca12cfbfbcfd" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] name = "serde_json" -version = "1.0.93" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -613,9 +723,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] @@ -636,7 +746,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn", + "syn 1.0.109", ] [[package]] @@ -644,12 +754,16 @@ name = "swim" version = "0.1.0" dependencies = [ "akin", + "cfg-if 0.1.10", + "console_log", "gloo", "gloo-console", "gloo-events", "gloo-utils", + "humantime", "js-sys", "levenshtein", + "log", "monaco", "strum", "strum_macros", @@ -662,9 +776,20 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.107" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -673,40 +798,39 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] name = "tokio" -version = "1.25.0" +version = "1.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" +checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" dependencies = [ - "autocfg", + "backtrace", "pin-project-lite", - "windows-sys", ] [[package]] name = "tokio-stream" -version = "0.1.11" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", "pin-project-lite", @@ -715,11 +839,10 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -727,29 +850,29 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "version_check" @@ -759,36 +882,36 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.39", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.34" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "wasm-bindgen", "web-sys", @@ -796,9 +919,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -806,90 +929,33 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" [[package]] name = "web-sys" -version = "0.3.61" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" dependencies = [ "js-sys", "wasm-bindgen", ] -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" - [[package]] name = "yew" version = "0.20.0" @@ -943,5 +1009,5 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] diff --git a/Cargo.toml b/Cargo.toml index c78e1ac3c..eee84db52 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ js-sys = "0.3.61" monaco = { git = "https://github.com/SWIM-ucf/rust-monaco", rev = "c9586e4af77131a15daf53e91e1ad5161a5265e8", features = ["yew-components"] } wasm-bindgen = "0.2.83" wasm-bindgen-futures = "0.4.33" -web-sys = {version = "0.3.60", features = ["CssStyleDeclaration", "Event", "HtmlCollection", "HtmlElement", "HtmlInputElement", "HtmlObjectElement", "SvgElement"]} +web-sys = {version = "0.3.60", features = ["CssStyleDeclaration", "Event", "HtmlCollection", "HtmlElement", "HtmlInputElement", "HtmlObjectElement", "SvgElement", "CanvasRenderingContext2d", "Document", "HtmlCanvasElement", "EventTarget", "InputEvent"]} yew = {version = "0.20.0", features = ["csr"] } yew-hooks = "0.2.0" @@ -28,4 +28,10 @@ yew-hooks = "0.2.0" levenshtein = "1.0.5" # Tests -akin = "0.4" \ No newline at end of file +akin = "0.4" + +# Logging +cfg-if = "0.1" +log = "0.4" +console_log = { version = "1", features = ["color"] } +humantime = "2.1.0" diff --git a/index.html b/index.html index 7d62cbe60..84d2ba58f 100644 --- a/index.html +++ b/index.html @@ -14,6 +14,8 @@ + + SWIM diff --git a/src/emulation_core/mips/memory.rs b/src/emulation_core/mips/memory.rs index 2abcf1921..d2f97ac1e 100644 --- a/src/emulation_core/mips/memory.rs +++ b/src/emulation_core/mips/memory.rs @@ -1,6 +1,7 @@ //! Data and instruction memory implementation and API. // pub const CAPACITY_BYTES: usize = 2^12; // 4KB +use log::debug; pub const CAPACITY_BYTES: usize = 64 * 1024; // 64 KB #[derive(Clone, Debug, PartialEq)] @@ -109,37 +110,60 @@ impl Memory { Ok(result) } - pub fn generate_formatted_hex(&self) -> String { - let mut string: String = "".to_string(); + pub fn parse_formatted_hex(&mut self, input: &str) -> Result<(), String> { + let mut address = 0; + for (i, line) in input.lines().enumerate() { + // Split each line into parts + let parts: Vec<&str> = line.split('\t').collect(); + let memory_address = &parts[0..2]; + parts[2..6] + .iter() + .try_for_each(|&part| -> Result<(), String> { + if address + 3 > CAPACITY_BYTES { + debug!("Address {} out of bounds", address); + () + } + let data = u32::from_str_radix(&part, 16).map_err(|e| e.to_string())?; + self.store_word(address as u64, data)?; + address += 4; + Ok(()) + })?; + } + Ok(()) + } +} - let mut base = 0; - while base < self.memory.len() { - string.push_str(&format!("0x{base:04x}:\t\t")); - let mut char_version: String = "".to_string(); +pub struct MemoryIter<'a> { + memory: &'a Memory, + current_address: usize, +} - for offset in 0..4 { - let word_address = base as u64 + (offset * 4); - if let Ok(word) = self.load_word(word_address) { - string.push_str(&format!("{word:08x}\t")); - char_version.push_str(&convert_word_to_chars(word)) - }; - } - string.push_str(&format!("{char_version}\n")); - base += 16; +impl<'a> MemoryIter<'a> { + pub fn new(memory: &'a Memory) -> MemoryIter<'a> { + MemoryIter { + memory, + current_address: 0 } - string } } -fn convert_word_to_chars(word: u32) -> String { - let mut chars = "".to_string(); - for shift in (0..4).rev() { - let byte = (word >> (shift * 8)) as u8; - if byte > 32 && byte < 127 { - chars.push(byte as char); +impl<'a> Iterator for MemoryIter<'a> { + // Words are 32 bits + type Item = (usize, Vec); + fn next(&mut self) -> Option { + self.current_address = (self.current_address + 3) & !3; + if self.current_address + 16 <= self.memory.memory.len() { + let address = self.current_address; + let words = (0..4) + .map(|i| self.memory + .load_word(address as u64 + (i * 4)) + .unwrap()) + .collect(); + + self.current_address += 16; + Some((address, words)) } else { - chars.push('.'); + None } } - chars -} +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index a59835a88..bb0b5ea79 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,28 +8,33 @@ use emulation_core::datapath::Datapath; use emulation_core::mips::datapath::MipsDatapath; use emulation_core::mips::datapath::Stage; use gloo::{dialogs::alert, file::FileList}; +use gloo_console::log; use js_sys::Object; use monaco::{ api::TextModel, sys::{ editor::{ IEditorMinimapOptions, IEditorScrollbarOptions, IMarkerData, IModelDecorationOptions, - IModelDeltaDecoration, IStandaloneEditorConstructionOptions, ISuggestOptions, + IModelDeltaDecoration, IStandaloneEditorConstructionOptions, ISuggestOptions, ScrollType }, IMarkdownString, MarkerSeverity, }, - yew::CodeEditor, + yew::{CodeEditor, CodeEditorLink}, }; use parser::parser_assembler_main::parser; use std::rc::Rc; use ui::console::component::Console; use ui::regview::component::Regview; +use ui::hex_editor::component::generate_formatted_hex; use wasm_bindgen::{JsCast, JsValue}; use wasm_bindgen_futures::spawn_local; use web_sys::HtmlInputElement; use yew::prelude::*; use yew::{html, Html, Properties}; use yew_hooks::prelude::*; +use log::Level; +use std::cell::RefCell; + // To load in the Fibonacci example, uncomment the CONTENT and fib_model lines // and comment the code, language, and text_model lines. IMPORTANT: @@ -58,6 +63,7 @@ fn app() -> Html { // was executed after the execute button is pressed. let executed_line = js_sys::Array::new(); let not_highlighted = js_sys::Array::new(); + let curr_line = Rc::new(RefCell::new(0.0)); // Setting up the options/parameters which // will highlight the previously executed line. @@ -75,6 +81,9 @@ fn app() -> Html { let parser_text_output = use_state_eq(String::new); let memory_text_output = use_state_eq(String::new); + let last_memory_text_model = use_mut_ref(|| TextModel::create(&memory_text_output, Some("ini"), None).unwrap()); + + let memory_text_model = use_mut_ref(|| TextModel::create(&memory_text_output, Some("ini"), None).unwrap()); // Since we want the Datapath to be independent from all the // events within the app, we will create it when the app loads. This is also done // since the scope will be open across all events involved with it. To achieve this, @@ -82,24 +91,53 @@ fn app() -> Html { // the ability to access and change its contents be mutable. let datapath = use_mut_ref(MipsDatapath::default); + let link = CodeEditorLink::new(); + + let on_editor_created = { + let text_model = Rc::clone(&text_model); + let curr_line = Rc::clone(&curr_line); + + use_callback( + move |editor_link: CodeEditorLink, _text_model| { + // log::trace!("render {editor_link:?}"); + let curr_line = curr_line.borrow_mut(); + match editor_link.with_editor(|editor| { + let raw_editor = editor.as_ref(); + // log!("We made it."); + // log!("Executed line: {}", *curr_line); + raw_editor.reveal_line_in_center(*curr_line, Some(ScrollType::Smooth)); + }) { + Some(()) => log!("Editor linked."), + None => log!("No editor :(") + }; + }, + text_model, + ) + }; + // This is where code is assembled and loaded into the emulation core's memory. let on_assemble_clicked = { let text_model = Rc::clone(&text_model); + let memory_text_model = Rc::clone(&memory_text_model); let datapath = Rc::clone(&datapath); let parser_text_output = parser_text_output.clone(); let trigger = use_force_update(); let executed_line = executed_line.clone(); let not_highlighted = not_highlighted.clone(); + // Clone the value before moving it into the closure + let last_memory_text_model = Rc::clone(&last_memory_text_model); + use_callback( move |_, text_model| { let mut datapath = datapath.borrow_mut(); let text_model = text_model.borrow_mut(); - + let memory_text_model = memory_text_model.borrow_mut(); // parses through the code to assemble the binary and retrieves programinfo for error marking and mouse hover let (program_info, assembled) = parser(text_model.get_value()); parser_text_output.set(program_info.console_out_post_assembly); + let last_memory_text_model = last_memory_text_model.borrow_mut(); let mut markers: Vec = vec![]; @@ -152,6 +190,9 @@ fn app() -> Html { } // log!(datapath.memory.to_string()); text_model.set_value(&program_info.updated_monaco_string); // Expands pseudo-instructions to their hardware counterpart. + let hexdump = &generate_formatted_hex(&datapath.memory); + memory_text_model.set_value(hexdump); + last_memory_text_model.set_value(hexdump); datapath.registers.pc = program_info.pc_starting_point as u64; } @@ -166,19 +207,28 @@ fn app() -> Html { // syscall instruction, which will halt the datapath. As you execute the // code, the previously executed line is highlighted. let on_execute_clicked = { - let text_model = Rc::clone(&text_model); let datapath = Rc::clone(&datapath); - let trigger = use_force_update(); + // Code editor + let text_model = Rc::clone(&text_model); let executed_line = executed_line.clone(); let not_highlighted = not_highlighted.clone(); let highlight_decor = highlight_decor.clone(); + let curr_line = Rc::clone(&curr_line); + + // Hex editor + let memory_text_model = Rc::clone(&memory_text_model); + let last_memory_text_model = Rc::clone(&last_memory_text_model); + let trigger = use_force_update(); use_callback( move |_, _| { let mut datapath = datapath.borrow_mut(); let text_model = text_model.borrow_mut(); let highlight_decor = highlight_decor.borrow_mut(); + let memory_text_model = memory_text_model.borrow_mut(); + let last_memory_text_model = last_memory_text_model.borrow_mut(); + let mut curr_line = curr_line.borrow_mut(); // Pull ProgramInfo from the parser let (programinfo, _) = parser(text_model.get_value()); @@ -186,11 +236,11 @@ fn app() -> Html { // Get the current line and convert it to f64 let list_of_line_numbers = programinfo.address_to_line_number; let index = datapath.registers.pc as usize / 4; - let curr_line = *list_of_line_numbers.get(index).unwrap_or(&0) as f64 + 1.0; // add one to account for the editor's line numbers + *curr_line = *list_of_line_numbers.get(index).unwrap_or(&0) as f64 + 1.0; // add one to account for the editor's line numbers // Setup the range let curr_model = text_model.as_ref(); - let curr_range = monaco::sys::Range::new(curr_line, 0.0, curr_line, 0.0); + let curr_range = monaco::sys::Range::new(*curr_line, 0.0, *curr_line, 0.0); // element to be stored in the stack to highlight the line let highlight_line: monaco::sys::editor::IModelDeltaDecoration = @@ -219,10 +269,34 @@ fn app() -> Html { .into(), ); + memory_text_model.as_ref().delta_decorations(¬_highlighted, &executed_line, None); + // log!("These are the stacks after the push"); // log!(executed_line.at(0)); // log!(not_highlighted.at(0)); + // Update memory + let last_memory_text_model_value = last_memory_text_model.get_value(); + let current_memory_text_model_value = memory_text_model.get_value(); + + if current_memory_text_model_value != last_memory_text_model_value { + match datapath.memory.parse_formatted_hex(¤t_memory_text_model_value) { + Ok(()) => { + log!("Memory updated successfully."); + }, + Err(err) => { + log!("Error updating memory: {}", err) + } + } + } + + let hexdump = &generate_formatted_hex(&datapath.memory); + + memory_text_model.set_value(hexdump); + last_memory_text_model.set_value(hexdump); + + // Execute instruction + datapath.execute_instruction(); // done with the highlight, prepare for the next one. @@ -240,16 +314,46 @@ fn app() -> Html { let on_execute_stage_clicked = { let datapath = Rc::clone(&datapath); + let trigger = use_force_update(); + + // Code editor let text_model = Rc::clone(&text_model); let executed_line = executed_line.clone(); let not_highlighted = not_highlighted.clone(); let highlight_decor = highlight_decor; - let trigger = use_force_update(); + + // Hex editor + let memory_text_model = Rc::clone(&memory_text_model); + let last_memory_text_model = Rc::clone(&last_memory_text_model); use_callback( move |_, _| { let mut datapath = datapath.borrow_mut(); let highlight_decor = highlight_decor.borrow_mut(); + + // Update memory + let memory_text_model = memory_text_model.borrow_mut(); + let last_memory_text_model = last_memory_text_model.borrow_mut(); + + let last_memory_text_model_value = last_memory_text_model.get_value(); + let current_memory_text_model_value = memory_text_model.get_value(); + + if current_memory_text_model_value != last_memory_text_model_value { + match datapath.memory.parse_formatted_hex(¤t_memory_text_model_value) { + Ok(()) => { + log!("Memory updated successfully."); + }, + Err(err) => { + log!("Error updating memory: {}", err) + } + } + } + + let hexdump = &generate_formatted_hex(&datapath.memory); + + memory_text_model.set_value(hexdump); + last_memory_text_model.set_value(hexdump); + if datapath.current_stage == Stage::InstructionDecode { // highlight on InstructionDecode since syscall stops at that stage. let text_model = text_model.borrow_mut(); @@ -290,14 +394,20 @@ fn app() -> Html { // This is how we will reset the datapath. // This will also clear any highlight on the editor. let on_reset_clicked = { - let text_model = Rc::clone(&text_model); let datapath = Rc::clone(&datapath); let trigger = use_force_update(); + + // Code editor + let text_model = Rc::clone(&text_model); let parser_text_output = parser_text_output.clone(); let executed_line = executed_line; let not_highlighted = not_highlighted; + // Hex editor + let memory_text_model = Rc::clone(&memory_text_model); + let last_memory_text_model = Rc::clone(&last_memory_text_model); + use_callback( move |_, _| { let mut datapath = datapath.borrow_mut(); @@ -312,6 +422,14 @@ fn app() -> Html { ); parser_text_output.set("".to_string()); datapath.reset(); + + // Clear hex editor content + let memory_text_model = memory_text_model.borrow_mut(); + let last_memory_text_model = last_memory_text_model.borrow_mut(); + + memory_text_model.set_value(""); + last_memory_text_model.set_value(""); + trigger.force_update(); }, (), @@ -448,16 +566,15 @@ fn app() -> Html { // Editor
- +
// Console - + // Right column - + } @@ -473,6 +590,8 @@ fn new_object() -> JsValue { #[derive(PartialEq, Properties)] pub struct SwimEditorProps { pub text_model: TextModel, + pub link: CodeEditorLink, + pub on_editor_created: Callback } fn get_options() -> IStandaloneEditorConstructionOptions { @@ -504,7 +623,7 @@ fn get_options() -> IStandaloneEditorConstructionOptions { #[function_component] pub fn SwimEditor(props: &SwimEditorProps) -> Html { html! { - + } } @@ -538,5 +657,6 @@ pub fn on_upload_file_clicked() { } fn main() { + console_log::init_with_level(Level::Debug); yew::Renderer::::new().render(); } diff --git a/src/ui.rs b/src/ui.rs index 095d4b1c5..4e363e9b6 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,5 +1,6 @@ //! User interface using Yew, organized into components. pub mod console; +pub mod hex_editor; pub mod regview; pub mod visual_datapath; diff --git a/src/ui/console/component.rs b/src/ui/console/component.rs index c19c52a8b..6fc385a93 100644 --- a/src/ui/console/component.rs +++ b/src/ui/console/component.rs @@ -4,15 +4,22 @@ use wasm_bindgen::JsCast; use web_sys::HtmlElement; use yew::prelude::*; use yew_hooks::prelude::*; +use std::rc::Rc; +use std::cell::RefCell; + + +use monaco::api::TextModel; use crate::emulation_core::mips::datapath::MipsDatapath; use crate::ui::visual_datapath::{DatapathSize, VisualDatapath}; +use crate::ui::hex_editor::component::HexEditor; +use crate::emulation_core::mips::memory::Memory; #[derive(PartialEq, Properties)] pub struct Consoleprops { pub datapath: MipsDatapath, pub parsermsg: String, - pub memorymsg: String, + pub memory_text_model: Rc>, } #[derive(Default, PartialEq)] @@ -21,6 +28,7 @@ enum TabState { Console, Datapath, Memory, + HexEditor } #[function_component(Console)] @@ -40,6 +48,7 @@ pub fn console(props: &Consoleprops) -> Html { "console" => TabState::Console, "datapath" => TabState::Datapath, "memory" => TabState::Memory, + "hex_editor" => TabState::HexEditor, _ => TabState::default(), }; @@ -89,13 +98,19 @@ pub fn console(props: &Consoleprops) -> Html {
- } else { -
-
-                        {props.datapath.memory.generate_formatted_hex() }
-                    
+ } else if *active_tab == TabState::HexEditor { +
+ // +
- } + } + // else { + //
+ //
+            //             {props.datapath.memory.generate_formatted_hex() }
+            //         
+ //
+ // }
if *active_tab == TabState::Console { @@ -115,11 +130,17 @@ pub fn console(props: &Consoleprops) -> Html { } else { } + + if *active_tab == TabState::HexEditor { + + } else { + + }
if *active_tab == TabState::Datapath {
- +
} diff --git a/src/ui/hex_editor/component.rs b/src/ui/hex_editor/component.rs new file mode 100644 index 000000000..50b630919 --- /dev/null +++ b/src/ui/hex_editor/component.rs @@ -0,0 +1,193 @@ +use yew::{function_component, html, Html, Properties, TargetCast, Component, Context}; +use crate::emulation_core::mips::memory::{Memory, MemoryIter}; +use yew::prelude::*; +use web_sys::Element; +use wasm_bindgen::{prelude::*, JsCast, JsValue}; +use web_sys::{ + CanvasRenderingContext2d, Document, HtmlCanvasElement, HtmlInputElement, InputEvent, +}; +use std::rc::Rc; +use std::cell::RefCell; +use log::debug; +use js_sys::{Array, Object, Function}; +use yew_hooks::prelude::*; + +use std::ops::{Deref, DerefMut}; + +use monaco::{ + api::TextModel, + sys::{ + editor::{ + IEditorMinimapOptions, IEditorScrollbarOptions, IMarkerData, IModelDecorationOptions, ICursorPositionChangedEvent, IStandaloneCodeEditor, + IModelDeltaDecoration, IStandaloneEditorConstructionOptions, ISuggestOptions, ICodeEditor, create + }, + IMarkdownString, MarkerSeverity, + languages::{ILanguageExtensionPoint, LanguageConfiguration} + }, + yew::{CodeEditor, CodeEditorLink}, +}; + +pub struct CursorPosition { + line_number: u32, + column_number: u32 +} +#[derive(PartialEq, Properties)] +pub struct HexEditorProps { + // #[prop_or_default] + // pub memory: Memory + pub memory_text_model: Rc> +} + +#[function_component(HexEditor)] +pub fn hex_editor(props: &HexEditorProps) -> Html { + // let memory_string = generate_formatted_hex(&props.memory); + + // let memory_text_model = use_mut_ref(|| TextModel::create(&memory_string, Some("ini"), None).unwrap()); + + + // let dirty_line = js_sys::Array::new(); + + // let cursor_position = CursorPosition { + // line_number: 0, + // column_number: 0 + // }; + + let editor_link = CodeEditorLink::new(); + + // Define the event listener + // pub fn handle_cursor_position_change (e: ICursorPositionChangedEvent) { + // debug!("{:?}", e.position()); + // }; + + // let editor_link_clone = editor_link.clone(); + + // // Use the use_effect hook to run code after the component is mounted + // use_effect(move || { + // // Access the CodeEditor instance after it's created + // if let Some(editor) = editor_link_clone.with_editor(|editor| { + // // Attach the event listener after the editor is created + // editor.on_did_change_cursor_position(handle_cursor_position_change.clone()) + // }) { + // // Perform cleanup if needed + + // } + // }); + + html! { + + } +} + +pub fn generate_formatted_hex(memory: &Memory) -> String { + let iterator = MemoryIter::new(&memory); + + let mut string: String = "".to_string(); + + for (address, words) in iterator { + string.push_str(&format!("0x{address:04x}:\t\t")); + let mut char_version: String = "".to_string(); + + for word in words { + string.push_str(&format!("{:08x}\t", word)); + char_version.push_str(&convert_word_to_chars(word)); + } + + string.push_str(&format!("{char_version}\n")); + } + + string +} + +fn convert_word_to_chars(word: u32) -> String { + let mut chars = "".to_string(); + for shift in (0..4).rev() { + let byte = (word >> (shift * 8)) as u8; + if byte > 32 && byte < 127 { + chars.push(byte as char); + } else { + chars.push('.'); + } + } + chars +} + + +fn get_options() -> IStandaloneEditorConstructionOptions { + let options = IStandaloneEditorConstructionOptions::default(); + options.set_theme("vs-dark".into()); + options.set_language("ini".into()); + options.set_scroll_beyond_last_line(false.into()); + options.set_automatic_layout(true.into()); + + let minimap = IEditorMinimapOptions::default(); + minimap.set_enabled(false.into()); + options.set_minimap(Some(&minimap)); + + let scrollbar = IEditorScrollbarOptions::default(); + scrollbar.set_always_consume_mouse_wheel(false.into()); + options.set_scrollbar(Some(&scrollbar)); + + let suggest = ISuggestOptions::default(); + suggest.set_show_keywords(false.into()); + suggest.set_show_variables(false.into()); + suggest.set_show_icons(false.into()); + suggest.set_show_words(false.into()); + suggest.set_filter_graceful(false.into()); + options.set_suggest(Some(&suggest)); + + options +} + + +// editor.onDidChangeModelContent(e => { +// if (/* your condition here */) { +// // your logic here +// overridenPosition = { lineNumber: 4, column: 2 }; // put your value here +// } +// }); + +// editor.onDidChangeCursorPosition(e => { +// if (overridenPosition != null) { +// editor.setPosition(overridenPosition); +// overridenPosition = null; +// } +// }); + +// pub struct HexEditor { +// node_ref: NodeRef, +// } + +// impl Component for HexEditor { +// type Message = (); +// type Properties = (); + +// // Properties from the parent component are store in Context +// fn create(_ctx: &Context) -> Self { +// Self { +// node_ref: NodeRef::default(), +// } +// } + +// fn view(&self, _ctx: &Context) -> Html { +// html! { +//
+// } +// } + +// fn rendered(&mut self, _ctx: &Context, _first_render: bool) { +// let has_attributes = self.node_ref +// .cast::() +// .unwrap() +// .has_attributes(); +// } +// } +// pub enum Msg { +// UpdateValue(String), +// UpdateAddress(String), +// } + diff --git a/src/ui/hex_editor/mod.rs b/src/ui/hex_editor/mod.rs new file mode 100644 index 000000000..9cea807e4 --- /dev/null +++ b/src/ui/hex_editor/mod.rs @@ -0,0 +1 @@ +pub mod component; diff --git a/src/ui/hex_editor/util.rs b/src/ui/hex_editor/util.rs new file mode 100644 index 000000000..e69de29bb diff --git a/src/ui/regview/component.rs b/src/ui/regview/component.rs index df7210e9c..202d7ab55 100644 --- a/src/ui/regview/component.rs +++ b/src/ui/regview/component.rs @@ -1,16 +1,27 @@ +use crate::emulation_core::mips::datapath::MipsDatapath; use crate::emulation_core::mips::registers::{GpRegisterType, GpRegisters}; //use gloo::console::log; use wasm_bindgen::JsCast; -use web_sys::HtmlElement; +use web_sys::{HtmlElement, InputEvent, HtmlInputElement}; use yew::prelude::*; +use yew::{html, Html}; +use std::rc::Rc; +use std::cell::RefCell; +// use log::debug; // datapath.coprocessor.fpr #[derive(PartialEq, Properties)] pub struct Regviewprops { pub gp: GpRegisters, pub fp: [u64; 32], + pub datapath: Rc> +} +#[derive(PartialEq, Properties)] +pub struct Regrowprops { + pub gp: GpRegisters, + pub fp: [u64; 32], + pub on_input: Callback<(InputEvent, GpRegisterType)>, } - #[derive(PartialEq, Properties)] pub struct Viewswitch { pub switch_view: bool, @@ -26,14 +37,30 @@ enum UnitState { Double, } +#[derive(Debug)] +enum Msg { + UpdateRegister(GpRegisterType, u64), +} + +pub struct InputData { + pub value: String, + pub event: InputEvent, +} + //Convert register to html through iterator -pub fn generate_gpr_rows(gp: GpRegisters) -> Html { - gp.into_iter() +pub fn generate_gpr_rows(props: &Regrowprops) -> Html { + + props.gp.into_iter() .map(|(register, data)| { + let on_input = Callback::clone(&props.on_input); html! { {get_gpr_name(register)} - {(data as i64).to_string()} + + + } }) @@ -144,6 +171,8 @@ pub fn get_gpr_name(register: GpRegisterType) -> String { pub fn regview(props: &Regviewprops) -> Html { let active_view = use_state_eq(UnitState::default); let switch_flag = use_state_eq(|| true); + + let datapath = Rc::clone(&props.datapath); let change_view = { let active_view = active_view.clone(); Callback::from(move |event: MouseEvent| { @@ -186,6 +215,31 @@ pub fn regview(props: &Regviewprops) -> Html { switch_flag, ) }; + + let on_input = Callback::from(move |args: (InputEvent, GpRegisterType)| { + let (e, register) = args; + let target = e.target(); + let input = target.unwrap().unchecked_into::(); + let val: u64 = input.value().parse().unwrap(); + let msg = Msg::UpdateRegister(register, val); + + let mut datapath = datapath.borrow_mut(); + + let write_destination: usize = register as usize; + if register == GpRegisterType::Pc { + datapath.registers.pc = val; + } + else { + datapath.registers.gpr[write_destination] = val; + } + }); + + let rowprops = Regrowprops { + gp: props.gp, + fp: props.fp, + on_input + }; + //log!("This is ", *switch_flag); html! {
@@ -248,7 +302,7 @@ pub fn regview(props: &Regviewprops) -> Html { else if *active_view == UnitState::Hex { {generate_gpr_rows_hex(props.gp)} } else { - {generate_gpr_rows(props.gp)} + {generate_gpr_rows(&rowprops)} } } else { if *active_view == UnitState::Bin { diff --git a/src/ui/visual_datapath/mod.rs b/src/ui/visual_datapath/mod.rs index 45790beb0..28a07a18f 100644 --- a/src/ui/visual_datapath/mod.rs +++ b/src/ui/visual_datapath/mod.rs @@ -375,6 +375,7 @@ impl VisualDatapath { } else { Self::set_inactive(&path)?; } + path.style().set_property("stroke-width", "10"); if path.tag_name() == "path" { // Set the initial state of this path: diff --git a/static/backward.svg b/static/backward.svg new file mode 100644 index 000000000..7b9498caf --- /dev/null +++ b/static/backward.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/static/cog.svg b/static/cog.svg new file mode 100644 index 000000000..05081d3c4 --- /dev/null +++ b/static/cog.svg @@ -0,0 +1,7 @@ + + +circle-left + + + + diff --git a/static/folder-upload.svg b/static/folder-upload.svg new file mode 100644 index 000000000..5302c6539 --- /dev/null +++ b/static/folder-upload.svg @@ -0,0 +1,7 @@ + + +circle-left + + + + diff --git a/static/forward.svg b/static/forward.svg new file mode 100644 index 000000000..c074308cc --- /dev/null +++ b/static/forward.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/static/hammer.svg b/static/hammer.svg new file mode 100644 index 000000000..98f283f0d --- /dev/null +++ b/static/hammer.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/static/next.svg b/static/next.svg new file mode 100644 index 000000000..848d571b5 --- /dev/null +++ b/static/next.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/static/pause.svg b/static/pause.svg new file mode 100644 index 000000000..692adbb17 --- /dev/null +++ b/static/pause.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/static/play.svg b/static/play.svg new file mode 100644 index 000000000..f3832db46 --- /dev/null +++ b/static/play.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/static/previous.svg b/static/previous.svg new file mode 100644 index 000000000..869c4e4af --- /dev/null +++ b/static/previous.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/static/rust-logo-blk.svg b/static/rust-logo-blk.svg new file mode 100644 index 000000000..1a6c762d4 --- /dev/null +++ b/static/rust-logo-blk.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/stop.svg b/static/stop.svg new file mode 100644 index 000000000..27be07d39 --- /dev/null +++ b/static/stop.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/static/styles/main.css b/static/styles/main.css index 26024710a..baa3201c0 100644 --- a/static/styles/main.css +++ b/static/styles/main.css @@ -69,8 +69,17 @@ body { max-height: 50%; } +.hex-wrapper { + border: 3px groove #ccc; + background: #012456; + color: #ccc; + word-break: break-all; + min-height: max(20%, 8em); + max-height: 50%; +} + .memory-view { - font-size: 1rem; + font-size: 1rem; } .datapath-wrapper { diff --git a/static/styles/tailwind.css b/static/styles/tailwind.css new file mode 100644 index 000000000..bd6213e1d --- /dev/null +++ b/static/styles/tailwind.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; \ No newline at end of file diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 000000000..f118e4075 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,5 @@ +module.exports = { + content: { + files: ["*.html", "./src/**/*.rs"], + }, +} \ No newline at end of file From 6a903236ab58dbc07dd1e2a348d5afa7cc394cc2 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Wed, 15 Nov 2023 18:13:08 -0500 Subject: [PATCH 002/355] Separate the main binary from a worker binary --- index.html | 2 ++ src/{ => bin}/main.rs | 20 +++++++------------- src/bin/worker.rs | 5 +++++ src/lib.rs | 5 +++++ 4 files changed, 19 insertions(+), 13 deletions(-) rename src/{ => bin}/main.rs (98%) create mode 100644 src/bin/worker.rs create mode 100644 src/lib.rs diff --git a/index.html b/index.html index 7d62cbe60..169778ced 100644 --- a/index.html +++ b/index.html @@ -2,6 +2,8 @@ + + diff --git a/src/main.rs b/src/bin/main.rs similarity index 98% rename from src/main.rs rename to src/bin/main.rs index a59835a88..fb589b86d 100644 --- a/src/main.rs +++ b/src/bin/main.rs @@ -1,12 +1,6 @@ -pub mod emulation_core; -pub mod parser; -#[cfg(test)] -pub mod tests; -pub mod ui; - -use emulation_core::datapath::Datapath; -use emulation_core::mips::datapath::MipsDatapath; -use emulation_core::mips::datapath::Stage; +use swim::emulation_core::datapath::Datapath; +use swim::emulation_core::mips::datapath::MipsDatapath; +use swim::emulation_core::mips::datapath::Stage; use gloo::{dialogs::alert, file::FileList}; use js_sys::Object; use monaco::{ @@ -20,10 +14,10 @@ use monaco::{ }, yew::CodeEditor, }; -use parser::parser_assembler_main::parser; +use swim::parser::parser_assembler_main::parser; use std::rc::Rc; -use ui::console::component::Console; -use ui::regview::component::Regview; +use swim::ui::console::component::Console; +use swim::ui::regview::component::Regview; use wasm_bindgen::{JsCast, JsValue}; use wasm_bindgen_futures::spawn_local; use web_sys::HtmlInputElement; @@ -34,7 +28,7 @@ use yew_hooks::prelude::*; // To load in the Fibonacci example, uncomment the CONTENT and fib_model lines // and comment the code, language, and text_model lines. IMPORTANT: // rename fib_model to text_model to have it work. -const CONTENT: &str = include_str!("../static/assembly_examples/fibonacci.asm"); +const CONTENT: &str = include_str!("../../static/assembly_examples/fibonacci.asm"); #[function_component(App)] fn app() -> Html { diff --git a/src/bin/worker.rs b/src/bin/worker.rs new file mode 100644 index 000000000..3071854da --- /dev/null +++ b/src/bin/worker.rs @@ -0,0 +1,5 @@ +use gloo_console::log; + +fn main() { + log!("Hello world from the worker!") +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 000000000..cad0e1f1a --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,5 @@ +pub mod emulation_core; +pub mod parser; +#[cfg(test)] +pub mod tests; +pub mod ui; \ No newline at end of file From 27ff21247e3d6c38b07041b728fd9194d8ba325e Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Sun, 26 Nov 2023 18:17:03 -0500 Subject: [PATCH 003/355] Implement basic agent code --- src/bin/worker.rs | 5 +++-- src/emulation_core/agent.rs | 13 +++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 src/emulation_core/agent.rs diff --git a/src/bin/worker.rs b/src/bin/worker.rs index 3071854da..5430906de 100644 --- a/src/bin/worker.rs +++ b/src/bin/worker.rs @@ -1,5 +1,6 @@ -use gloo_console::log; +use yew_agent::Registrable; +use swim::emulation_core::agent::EmulationCoreAgent; fn main() { - log!("Hello world from the worker!") + EmulationCoreAgent::registrar().register(); } \ No newline at end of file diff --git a/src/emulation_core/agent.rs b/src/emulation_core/agent.rs new file mode 100644 index 000000000..ef960e1af --- /dev/null +++ b/src/emulation_core/agent.rs @@ -0,0 +1,13 @@ +use yew_agent::prelude::*; +use futures::{SinkExt, StreamExt}; +use serde::{Deserialize, Serialize}; +use gloo_console::log; + +#[reactor(EmulationCoreAgent)] +pub async fn emulation_core_agent(mut scope: ReactorScope) { + log!("Hello world!"); + scope.send(1).await.unwrap(); + loop { + let _msg = scope.next().await; + } +} From ead0411c3534e9cb9d9c3acf01561071ea60f4f6 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Sun, 26 Nov 2023 19:27:23 -0500 Subject: [PATCH 004/355] Spawn newly created worker thread --- Cargo.lock | 848 +++++++++++++++++++++++++++++++----------- Cargo.toml | 3 + src/bin/main.rs | 3 + src/emulation_core.rs | 1 + 4 files changed, 640 insertions(+), 215 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 353001015..c63c9c952 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "akin" version = "0.4.0" @@ -20,6 +35,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "bincode" version = "1.3.3" @@ -37,9 +67,24 @@ checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9" [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "bytes" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -57,23 +102,36 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "futures" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" dependencies = [ "futures-channel", "futures-core", + "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -82,9 +140,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", "futures-sink", @@ -92,44 +150,55 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" + +[[package]] +name = "futures-executor" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] [[package]] name = "futures-io" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-macro" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] name = "futures-sink" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-util" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-channel", "futures-core", @@ -143,23 +212,61 @@ dependencies = [ "slab", ] +[[package]] +name = "getrandom" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "gloo" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28999cda5ef6916ffd33fb4a7b87e1de633c47c0dc6d97905fee1cdaa142b94d" +dependencies = [ + "gloo-console 0.2.3", + "gloo-dialogs 0.1.1", + "gloo-events 0.1.2", + "gloo-file 0.2.3", + "gloo-history 0.1.5", + "gloo-net 0.3.1", + "gloo-render 0.1.1", + "gloo-storage 0.2.2", + "gloo-timers 0.2.6", + "gloo-utils 0.1.7", + "gloo-worker 0.2.1", +] + [[package]] name = "gloo" -version = "0.8.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a4bef6b277b3ab073253d4bca60761240cf8d6998f4bd142211957b69a61b20" +checksum = "cd35526c28cc55c1db77aed6296de58677dbab863b118483a27845631d870249" dependencies = [ - "gloo-console", - "gloo-dialogs", - "gloo-events", - "gloo-file", - "gloo-history", - "gloo-net", - "gloo-render", - "gloo-storage", - "gloo-timers", - "gloo-utils", - "gloo-worker", + "gloo-console 0.3.0", + "gloo-dialogs 0.2.0", + "gloo-events 0.2.0", + "gloo-file 0.3.0", + "gloo-history 0.2.1", + "gloo-net 0.4.0", + "gloo-render 0.2.0", + "gloo-storage 0.3.0", + "gloo-timers 0.3.0", + "gloo-utils 0.2.0", + "gloo-worker 0.4.0", ] [[package]] @@ -168,7 +275,20 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82b7ce3c05debe147233596904981848862b068862e9ec3e34be446077190d3f" dependencies = [ - "gloo-utils", + "gloo-utils 0.1.7", + "js-sys", + "serde", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-console" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a17868f56b4a24f677b17c8cb69958385102fa879418052d60b50bc1727e261" +dependencies = [ + "gloo-utils 0.2.0", "js-sys", "serde", "wasm-bindgen", @@ -185,6 +305,16 @@ dependencies = [ "web-sys", ] +[[package]] +name = "gloo-dialogs" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4748e10122b01435750ff530095b1217cf6546173459448b83913ebe7815df" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + [[package]] name = "gloo-events" version = "0.1.2" @@ -195,6 +325,16 @@ dependencies = [ "web-sys", ] +[[package]] +name = "gloo-events" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27c26fb45f7c385ba980f5fa87ac677e363949e065a083722697ef1b2cc91e41" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + [[package]] name = "gloo-file" version = "0.2.3" @@ -202,7 +342,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d5564e570a38b43d78bdc063374a0c3098c4f0d64005b12f9bbe87e869b6d7" dependencies = [ "futures-channel", - "gloo-events", + "gloo-events 0.1.2", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-file" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97563d71863fb2824b2e974e754a81d19c4a7ec47b09ced8a0e6656b6d54bd1f" +dependencies = [ + "gloo-events 0.2.0", "js-sys", "wasm-bindgen", "web-sys", @@ -210,14 +362,31 @@ dependencies = [ [[package]] name = "gloo-history" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd451019e0b7a2b8a7a7b23e74916601abf1135c54664e57ff71dcc26dfcdeb7" +checksum = "85725d90bf0ed47063b3930ef28e863658a7905989e9929a8708aab74a1d5e7f" dependencies = [ - "gloo-events", - "gloo-utils", + "gloo-events 0.1.2", + "gloo-utils 0.1.7", "serde", - "serde-wasm-bindgen", + "serde-wasm-bindgen 0.5.0", + "serde_urlencoded", + "thiserror", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-history" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4022e82f5f9e03cb1251b13c0a967e0600e97aa179c617f6519bac40640160" +dependencies = [ + "getrandom", + "gloo-events 0.2.0", + "gloo-utils 0.2.0", + "serde", + "serde-wasm-bindgen 0.6.1", "serde_urlencoded", "thiserror", "wasm-bindgen", @@ -226,14 +395,36 @@ dependencies = [ [[package]] name = "gloo-net" -version = "0.2.6" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a66b4e3c7d9ed8d315fd6b97c8b1f74a7c6ecbbc2320e65ae7ed38b7068cc620" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils 0.1.7", + "http", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "gloo-net" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9902a044653b26b99f7e3693a42f171312d9be8b26b5697bd1e43ad1f8a35e10" +checksum = "8ac9e8288ae2c632fa9f8657ac70bfe38a1530f345282d7ba66a1f70b72b7dc4" dependencies = [ "futures-channel", "futures-core", "futures-sink", - "gloo-utils", + "gloo-utils 0.2.0", + "http", "js-sys", "pin-project", "serde", @@ -254,13 +445,38 @@ dependencies = [ "web-sys", ] +[[package]] +name = "gloo-render" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56008b6744713a8e8d98ac3dcb7d06543d5662358c9c805b4ce2167ad4649833" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + [[package]] name = "gloo-storage" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d6ab60bf5dbfd6f0ed1f7843da31b41010515c745735c970e821945ca91e480" dependencies = [ - "gloo-utils", + "gloo-utils 0.1.7", + "js-sys", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-storage" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc8031e8c92758af912f9bc08fbbadd3c6f3cfcbf6b64cdf3d6a81f0139277a" +dependencies = [ + "gloo-utils 0.2.0", "js-sys", "serde", "serde_json", @@ -281,11 +497,34 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "gloo-utils" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8e8fc851e9c7b9852508bc6e3f690f452f474417e8545ec9857b7f7377036b5" +checksum = "037fcb07216cb3a30f7292bd0176b050b7b9a052ba830ef7d5d65f6dc64ba58e" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-utils" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa" dependencies = [ "js-sys", "serde", @@ -302,8 +541,8 @@ checksum = "13471584da78061a28306d1359dd0178d8d6fc1c7c80e5e35d27260346e0516a" dependencies = [ "anymap2", "bincode", - "gloo-console", - "gloo-utils", + "gloo-console 0.2.3", + "gloo-utils 0.1.7", "js-sys", "serde", "wasm-bindgen", @@ -311,12 +550,49 @@ dependencies = [ "web-sys", ] +[[package]] +name = "gloo-worker" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76495d3dd87de51da268fa3a593da118ab43eb7f8809e17eb38d3319b424e400" +dependencies = [ + "bincode", + "futures", + "gloo-utils 0.2.0", + "gloo-worker-macros", + "js-sys", + "pinned", + "serde", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "gloo-worker-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956caa58d4857bc9941749d55e4bd3000032d8212762586fa5705632967140e7" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[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" @@ -325,43 +601,81 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.2.6" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "http" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ - "libc", + "bytes", + "fnv", + "itoa", ] [[package]] name = "implicit-clone" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40fc102e70475c320b185cd18c1e48bba2d7210b63970a4d581ef903e4368ef7" +checksum = "7c6ecbd987bb94f1f3c76c6787879756cf4b6f73bfff48d79308e8c56b46f65f" dependencies = [ - "indexmap", + "indexmap 1.9.3", +] + +[[package]] +name = "implicit-clone" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc06a255cbf402a52ae399c05a518c68c569c916ea11423620111df576b9b9bb" +dependencies = [ + "implicit-clone-derive", + "indexmap 2.1.0", +] + +[[package]] +name = "implicit-clone-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9311685eb9a34808bbb0608ad2fcab9ae216266beca5848613e95553ac914e3b" +dependencies = [ + "quote", + "syn 2.0.39", ] [[package]] name = "indexmap" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", ] [[package]] name = "itoa" -version = "1.0.5" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" -version = "0.3.61" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" dependencies = [ "wasm-bindgen", ] @@ -374,24 +688,30 @@ checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" [[package]] name = "libc" -version = "0.2.139" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "log" -version = "0.4.17" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] [[package]] name = "monaco" @@ -402,62 +722,71 @@ dependencies = [ "paste", "wasm-bindgen", "web-sys", - "yew", + "yew 0.20.0", ] [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ "hermit-abi", "libc", ] +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "paste" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project" -version = "1.0.12" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.12" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -478,12 +807,32 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.1.23" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97e3215779627f01ee256d2fad52f3d95e8e1c11e9fc6fd08f7cd455d5d5c78" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" dependencies = [ "proc-macro2", - "syn", + "syn 1.0.109", +] + +[[package]] +name = "prettyplease" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" +dependencies = [ + "proc-macro2", + "syn 2.0.39", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", ] [[package]] @@ -495,7 +844,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "version_check", ] @@ -512,9 +861,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.51" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" dependencies = [ "unicode-ident", ] @@ -526,7 +875,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03b55e106e5791fa5a13abd13c85d6127312e8e09098059ca2bc9b03ca4cf488" dependencies = [ "futures", - "gloo", + "gloo 0.8.1", "num_cpus", "once_cell", "pin-project", @@ -538,39 +887,56 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.23" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustversion" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.12" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "serde" -version = "1.0.152" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde-wasm-bindgen" -version = "0.4.5" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf" +checksum = "17ba92964781421b6cef36bf0d7da26d201e96d84e1b10e7ae6ed416e516906d" dependencies = [ "js-sys", "serde", @@ -579,20 +945,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.152" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] name = "serde_json" -version = "1.0.93" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -613,9 +979,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] @@ -636,7 +1002,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn", + "syn 1.0.109", ] [[package]] @@ -644,27 +1010,41 @@ name = "swim" version = "0.1.0" dependencies = [ "akin", - "gloo", - "gloo-console", - "gloo-events", - "gloo-utils", + "futures", + "gloo 0.8.1", + "gloo-console 0.2.3", + "gloo-events 0.1.2", + "gloo-utils 0.1.7", "js-sys", "levenshtein", "monaco", + "serde", "strum", "strum_macros", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "yew", + "yew 0.20.0", + "yew-agent", "yew-hooks", ] [[package]] name = "syn" -version = "1.0.107" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -673,53 +1053,68 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] name = "tokio" -version = "1.25.0" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ - "autocfg", + "backtrace", "pin-project-lite", - "windows-sys", ] [[package]] name = "tokio-stream" -version = "0.1.11" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", "pin-project-lite", "tokio", ] +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.1.0", + "toml_datetime", + "winnow", +] + [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -727,29 +1122,29 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "version_check" @@ -757,11 +1152,17 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -769,24 +1170,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.39", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.34" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" dependencies = [ "cfg-if", "js-sys", @@ -796,9 +1197,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -806,101 +1207,78 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" [[package]] name = "web-sys" -version = "0.3.61" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] -name = "windows-sys" -version = "0.42.0" +name = "winnow" +version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "memchr", ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.1" +name = "yew" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +checksum = "5dbecfe44343b70cc2932c3eb445425969ae21754a8ab3a0966981c1cf7af1cc" +dependencies = [ + "console_error_panic_hook", + "futures", + "gloo 0.8.1", + "implicit-clone 0.3.6", + "indexmap 1.9.3", + "js-sys", + "prokio", + "rustversion", + "serde", + "slab", + "thiserror", + "tokio", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "yew-macro 0.20.0", +] [[package]] name = "yew" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dbecfe44343b70cc2932c3eb445425969ae21754a8ab3a0966981c1cf7af1cc" +checksum = "5f1a03f255c70c7aa3e9c62e15292f142ede0564123543c1cc0c7a4f31660cac" dependencies = [ "console_error_panic_hook", "futures", - "gloo", - "implicit-clone", - "indexmap", + "gloo 0.10.0", + "implicit-clone 0.4.8", + "indexmap 2.1.0", "js-sys", "prokio", "rustversion", @@ -912,7 +1290,32 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "yew-macro", + "yew-macro 0.21.0", +] + +[[package]] +name = "yew-agent" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e27eaca61ea9d0e1a6589dce592283b0e62ced527d8a8b28447957295d588f5" +dependencies = [ + "futures", + "gloo-worker 0.4.0", + "serde", + "wasm-bindgen", + "yew 0.21.0", + "yew-agent-macro", +] + +[[package]] +name = "yew-agent-macro" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ad00f6c9436d25c9225ed0fd8eea27e6d2886c1387bf934afdf91e9131b8b77" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", ] [[package]] @@ -921,14 +1324,14 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "268e2367720311f19582235f5c021702d6be8ded13b7ee8dcacc71019d055d15" dependencies = [ - "gloo", + "gloo 0.8.1", "js-sys", "log", "serde", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "yew", + "yew 0.20.0", ] [[package]] @@ -939,9 +1342,24 @@ checksum = "b64c253c1d401f1ea868ca9988db63958cfa15a69f739101f338d6f05eea8301" dependencies = [ "boolinator", "once_cell", - "prettyplease", + "prettyplease 0.1.25", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "yew-macro" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02fd8ca5166d69e59f796500a2ce432ff751edecbbb308ca59fd3fe4d0343de2" +dependencies = [ + "boolinator", + "once_cell", + "prettyplease 0.2.15", "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] diff --git a/Cargo.toml b/Cargo.toml index c78e1ac3c..00af8ce40 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,9 @@ wasm-bindgen-futures = "0.4.33" web-sys = {version = "0.3.60", features = ["CssStyleDeclaration", "Event", "HtmlCollection", "HtmlElement", "HtmlInputElement", "HtmlObjectElement", "SvgElement"]} yew = {version = "0.20.0", features = ["csr"] } yew-hooks = "0.2.0" +yew-agent = "0.3.0" +serde = "1.0.193" +futures = "0.3.29" # Parser / Assembler levenshtein = "1.0.5" diff --git a/src/bin/main.rs b/src/bin/main.rs index fb589b86d..dbea2550c 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,6 +1,7 @@ use swim::emulation_core::datapath::Datapath; use swim::emulation_core::mips::datapath::MipsDatapath; use swim::emulation_core::mips::datapath::Stage; +use swim::emulation_core::agent::EmulationCoreAgent; use gloo::{dialogs::alert, file::FileList}; use js_sys::Object; use monaco::{ @@ -24,6 +25,7 @@ use web_sys::HtmlInputElement; use yew::prelude::*; use yew::{html, Html, Properties}; use yew_hooks::prelude::*; +use yew_agent::Spawnable; // To load in the Fibonacci example, uncomment the CONTENT and fib_model lines // and comment the code, language, and text_model lines. IMPORTANT: @@ -532,5 +534,6 @@ pub fn on_upload_file_clicked() { } fn main() { + let bridge = EmulationCoreAgent::spawner().spawn("./worker.js"); yew::Renderer::::new().render(); } diff --git a/src/emulation_core.rs b/src/emulation_core.rs index e62a37920..74cad3ccc 100644 --- a/src/emulation_core.rs +++ b/src/emulation_core.rs @@ -2,3 +2,4 @@ pub mod datapath; pub mod mips; +pub mod agent; \ No newline at end of file From 99f3156a284da522183b178dbd1ee58cf941d721 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Sun, 26 Nov 2023 19:46:08 -0500 Subject: [PATCH 005/355] Implement basic DatapathCommunicator and listen_for_updates function (design pending) --- src/emulation_core.rs | 3 ++- src/emulation_core/datapath_communicator.rs | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/emulation_core/datapath_communicator.rs diff --git a/src/emulation_core.rs b/src/emulation_core.rs index 74cad3ccc..0d8e00947 100644 --- a/src/emulation_core.rs +++ b/src/emulation_core.rs @@ -2,4 +2,5 @@ pub mod datapath; pub mod mips; -pub mod agent; \ No newline at end of file +pub mod agent; +mod datapath_communicator; \ No newline at end of file diff --git a/src/emulation_core/datapath_communicator.rs b/src/emulation_core/datapath_communicator.rs new file mode 100644 index 000000000..ab085d8d1 --- /dev/null +++ b/src/emulation_core/datapath_communicator.rs @@ -0,0 +1,21 @@ +use futures::stream::{SplitSink, SplitStream}; +use futures::StreamExt; +use gloo_console::log; +use yew::UseForceUpdateHandle; +use yew_agent::reactor::ReactorBridge; +use crate::emulation_core::agent::EmulationCoreAgent; + +pub struct DatapathCommunicator { + writer: SplitSink, i32>, + reader: SplitStream>, +} + +impl DatapathCommunicator { + pub async fn listen_for_updates(&mut self, update_handle: UseForceUpdateHandle) { + loop { + let update = self.reader.next().await; + log!(format!("Got update {:?}", update)); + update_handle.force_update(); + } + } +} \ No newline at end of file From 81f66c1de3e25e5c1a5136420346c88d57f747fa Mon Sep 17 00:00:00 2001 From: Cay Date: Wed, 27 Dec 2023 12:40:14 -0500 Subject: [PATCH 006/355] Updates code editor with changes to memory and widens datapath lines --- src/emulation_core/mips/instruction.rs | 413 ++++++++++++++++++++++++ src/emulation_core/mips/memory.rs | 65 +++- src/main.rs | 184 ++++++++--- src/parser/parser_assembler_main.rs | 2 +- src/tests/emulation_core.rs | 1 + src/tests/emulation_core/instruction.rs | 35 ++ src/ui/console/component.rs | 11 +- src/ui/hex_editor/component.rs | 115 +------ src/ui/regview/component.rs | 56 +++- src/ui/visual_datapath/mod.rs | 2 +- 10 files changed, 687 insertions(+), 197 deletions(-) create mode 100644 src/tests/emulation_core/instruction.rs diff --git a/src/emulation_core/mips/instruction.rs b/src/emulation_core/mips/instruction.rs index 126212d4a..b07970297 100644 --- a/src/emulation_core/mips/instruction.rs +++ b/src/emulation_core/mips/instruction.rs @@ -1,5 +1,7 @@ //! Abstract representation of an instruction. +use crate::parser::parser_structs_and_enums::GP_REGISTERS; + use super::constants::*; /// Register (R-Type) Instruction @@ -301,3 +303,414 @@ impl TryFrom for Instruction { } } } + + +pub fn find_register_name(binary: u8) -> Option<&'static str> { + for register in GP_REGISTERS { + if register.binary == binary { + // If a match is found, return the first name in the names array + return Some(register.names[0]); + } + } + // If no match is found, return None + None +} + +pub fn get_string_version(value: u32) -> Result { + let mut string_version = String::new(); + let op = (value >> 26) as u8; + let rs = ((value >> 21) & 0x1F) as u8; + let rt = ((value >> 16) & 0x1F) as u8; + let rd = ((value >> 11) & 0x1F) as u8; + let mut immediate = (value & 0xFFFF) as u16; + let mut imm_with_sign: i32 = 0; + + let mut imm_is_negative = false; + + if op == 0 && rs == 0 && rt == 0 && rd == 0 && immediate == 0 { + return Err(String::from("empty instruction")) + } + + if value & 0xF000 > 0 { + imm_is_negative = true; + immediate = !(immediate) + 1; + imm_with_sign = -1 * immediate as i32; + } + + let str_rt = match find_register_name(rt) { + Some(name) => name, + None => "##", + }; + let str_rs = match find_register_name(rs) { + Some(name) => name, + None => "##", + }; + let str_rd = match find_register_name(rd) { + Some(name) => name, + None => "##", + }; + let mut string_imm = immediate.to_string(); + let mut str_immediate = string_imm.as_str(); + + if imm_is_negative { + string_imm = imm_with_sign.to_string(); + str_immediate = string_imm.as_str(); + } + + let str_ft = str_rt; + let str_base = str_rs; + let str_offset = str_immediate; + + let funct = (value & 0x3F) as u8; + let shamt = (value & 0x3F) as u8; + let shamt_binary_str = format!("{:b}", shamt); + let str_shamt = shamt_binary_str.as_str(); + + match op { + // R-type instructions: + // add, sub, mul, div + // addu + // dadd, dsub, dmul, ddiv + // daddu, dsubu, dmulu, ddivu + // or, and, sll + // slt, sltu + // jalr, jr + // + // Includes syscall. + OPCODE_SPECIAL => { + match funct { + FUNCT_SYSCALL => Ok(String::from("syscall")), + FUNCT_ADD => { + string_version = format!("{} {} {} {}", "add", str_rd, str_rs, str_rt); + Ok(string_version) + }, + FUNCT_ADDU => { + string_version = format!("{} {} {} {}", "addu", str_rd, str_rs, str_rt); + Ok(string_version) + }, + FUNCT_DADD => { + string_version = format!("{} {} {} {}", "dadd", str_rd, str_rs, str_rt); + Ok(string_version) + }, + FUNCT_DADDU => { + string_version = format!("{} {} {} {}", "daddu", str_rd, str_rs, str_rt); + Ok(string_version) + }, + FUNCT_SUB => { + string_version = format!("{} {} {} {}", "sub", str_rd, str_rs, str_rt); + Ok(string_version) + }, + FUNCT_DSUB => { + string_version = format!("{} {} {} {}", "dsub", str_rd, str_rs, str_rt); + Ok(string_version) + }, + FUNCT_DSUBU => { + string_version = format!("{} {} {} {}", "dsubu", str_rd, str_rs, str_rt); + Ok(string_version) + }, + FUNCT_AND => { + string_version = format!("{} {} {} {}", "and", str_rd, str_rs, str_rt); + Ok(string_version) + }, + FUNCT_OR => { + string_version = format!("{} {} {} {}", "or", str_rd, str_rs, str_rt); + Ok(string_version) + }, + FUNCT_SLL => { + string_version = format!("{} {} {} {}", "sll", str_rd, str_rs, str_shamt); + Ok(string_version) + }, + FUNCT_SLT => { + string_version = format!("{} {} {} {}", "slt", str_rd, str_rs, str_rt); + Ok(string_version) + }, + FUNCT_SLTU => { + string_version = format!("{} {} {} {}", "sltu", str_rd, str_rs, str_shamt); + Ok(string_version) + }, + FUNCT_SOP32 => { + string_version = format!("{} {} {} {}", "or", str_rd, str_rs, str_rt); + Ok(string_version) + }, + FUNCT_SOP36 => match shamt as u8 { + // ENC_DIV == ENC_DDIV + ENC_DIV => { + string_version = format!("{} {} {}", "div", str_rs, str_rt); + Ok(string_version) + }, + _ => { + string_version = String::from("###"); + Ok(string_version) + } + }, + FUNCT_SOP33 | FUNCT_SOP37 => match shamt as u8 { + // ENC_DIVU == ENC_DDIVU + ENC_DIVU => { + string_version = format!("{} {} {}", "divu", str_rs, str_rt); + Ok(string_version) + }, + _ => { + string_version = String::from("###"); + Ok(string_version) + } + }, + FUNCT_SOP30 | FUNCT_SOP34 => match shamt as u8 { + // ENC_MUL == ENC_DMUL + ENC_MUL => { + string_version = format!("{} {} {} {}", "mul", str_rd, str_rs, str_rt); + Ok(string_version) + }, + _ => { + string_version = String::from("###"); + Ok(string_version) + } + }, + FUNCT_SOP31 | FUNCT_SOP35 => match shamt as u8 { + // ENC_MULU == ENC_DMULU + ENC_MULU => { + string_version = format!("{} {} {} {}", "mulu", str_rd, str_rs, str_rt); + Ok(string_version) + }, + _ => { + string_version = String::from("###"); + Ok(string_version) + } + }, + _ => { + string_version = String::from("###"); + Ok(string_version) + } + } + } + + // COP1 (coprocessor 1) + OPCODE_COP1 => { + // First break down the instruction by its `fmt`/`rs`/`bcc1` field. + // Also called `sub` (operation subcode) field. + let op = ((value >> 26) & 0x3F) as u8; + let sub = ((value >> 21) & 0x1F) as u8; + let ft = ((value >> 16) & 0x1F) as u8; // also rt + let fs = ((value >> 11) & 0x1F) as u8; // also rs + let fd = ((value >> 6) & 0x1F) as u8; + let function = (value & 0x3F) as u8; + let str_fs = match find_register_name(fs) { + Some(name) => name, + None => "##", + }; + let str_ft = match find_register_name(ft) { + Some(name) => name, + None => "##", + }; + let str_fd = match find_register_name(fd) { + Some(name) => name, + None => "##", + }; + + match sub { + // If it is the "s" or "d" fmts, use the `function` field. + FMT_SINGLE => { + match function { + // add.fmt, sub.fmt, mul.fmt, div.fmt + FUNCTION_ADD => { + let string_version = format!("add.s {} {} {}", str_fd, str_fs, str_ft); + Ok(string_version) + }, + FUNCTION_SUB => { + let string_version = format!("sub.s {} {} {}", str_fd, str_fs, str_ft); + Ok(string_version) + }, + FUNCTION_MUL => { + let string_version = format!("mul.s {} {} {}", str_fd, str_fs, str_ft); + Ok(string_version) + }, + FUNCTION_DIV => { + let string_version = format!("add.s {} {} {}", str_fd, str_fs, str_ft); + Ok(string_version) + }, + // Comparison instructions: + // c.eq.fmt, c.lt.fmt, c.le.fmt, c.ngt.fmt, c.nge.fmt + FUNCTION_C_EQ => { + let string_version = format!("c.eq.s {} {}", str_fs, str_ft); + Ok(string_version) + }, + FUNCTION_C_LT => { + let string_version = format!("c.lt.s {} {}", str_fs, str_ft); + Ok(string_version) + }, + FUNCTION_C_NGE => { + let string_version = format!("c.nge.s {} {}", str_fs, str_ft); + Ok(string_version) + }, + FUNCTION_C_LE => { + let string_version = format!("c.le.s {} {}", str_fs, str_ft); + Ok(string_version) + }, + FUNCTION_C_NGT => { + let string_version = format!("c.ngt.s {} {}", str_fs, str_ft); + Ok(string_version) + }, + _ => { + Err(format!( + "function `{function}` not supported for opcode {op}" + )) + }, + } + }, + FMT_DOUBLE => { + match function { + // add.fmt, sub.fmt, mul.fmt, div.fmt + FUNCTION_ADD => { + let string_version = format!("add.d {} {} {}", str_fd, str_fs, str_ft); + Ok(string_version) + }, + FUNCTION_SUB => { + let string_version = format!("sub.d {} {} {}", str_fd, str_fs, str_ft); + Ok(string_version) + }, + FUNCTION_MUL => { + let string_version = format!("mul.d {} {} {}", str_fd, str_fs, str_ft); + Ok(string_version) + }, + FUNCTION_DIV => { + let string_version = format!("add.d {} {} {}", str_fd, str_fs, str_ft); + Ok(string_version) + }, + // Comparison instructions: + // c.eq.fmt, c.lt.fmt, c.le.fmt, c.ngt.fmt, c.nge.fmt + FUNCTION_C_EQ => { + let string_version = format!("c.eq.d {} {}", str_fs, str_ft); + Ok(string_version) + }, + FUNCTION_C_LT => { + let string_version = format!("c.lt.d {} {}", str_fs, str_ft); + Ok(string_version) + }, + FUNCTION_C_NGE => { + let string_version = format!("c.nge.d {} {}", str_fs, str_ft); + Ok(string_version) + }, + FUNCTION_C_LE => { + let string_version = format!("c.le.d {} {}", str_fs, str_ft); + Ok(string_version) + }, + FUNCTION_C_NGT => { + let string_version = format!("c.ngt.d {} {}", str_fs, str_ft); + Ok(string_version) + }, + _ => { + Err(format!( + "function `{function}` not supported for opcode {op}" + )) + }, + } + }, + + // Move word to coprocessor 1 (mtc1) + // Move doubleword to coprocessor 1 (dmtc1) + // Move word from coprocessor 1 (mfc1) + // Move doubleword from coprocessor 1 (dmfc1) + SUB_MT => { + let string_version = format!("mtc1 {} {}", str_ft, str_fs); + Ok(string_version) + }, + SUB_DMT => { + let string_version = format!("dmtc1 {} {}", str_ft, str_fs); + Ok(string_version) + }, + SUB_MF => { + let string_version = format!("mfc1 {} {}", str_ft, str_fs); + Ok(string_version) + }, + SUB_DMF => { + let string_version = format!("dfmc1 {} {}", str_ft, str_fs); + Ok(string_version) + }, + + // Branch on coprocessor 1 true (bc1t) + // Branch on coprocessor 1 false (bc1f) + SUB_BC => { + string_version.push_str("bc1t"); + Ok(string_version) + }, + + _ => Err(format!("sub code `{sub}` not supported for opcode {op}")), + } + } + + // I-Type instructions: + OPCODE_ADDI => { + let string_version = format!("addi {} {} {}", str_rt, str_rs, str_immediate); + Ok(string_version) + }, + OPCODE_ADDIU => { + let string_version = format!("addiu {} {} {}", str_rt, str_rs, str_immediate); + Ok(string_version) + }, + OPCODE_DADDI => { + let string_version = format!("daddi {} {} {}", str_rt, str_rs, str_immediate); + Ok(string_version) + }, + OPCODE_DADDIU => { + let string_version = format!("daddi {} {} {}", str_rt, str_rs, str_immediate); + Ok(string_version) + }, + OPCODE_LW => { + let string_version = format!("lw {}, {} ({})", str_rt, str_immediate, str_rs); + Ok(string_version) + }, + OPCODE_SW => { + let string_version = format!("sw {}, {} ({})", str_rt, str_immediate, str_rs); + Ok(string_version) + }, + OPCODE_LUI => { + let string_version = format!("lui {} , {}", str_rt, str_immediate); + Ok(string_version) + }, + OPCODE_ORI => { + let string_version = format!("ori {} {} {}", str_rt, str_rs, str_immediate); + Ok(string_version) + }, + OPCODE_ANDI => { + let string_version = format!("andi {} {} {}", str_rt, str_rs, str_immediate); + Ok(string_version) + }, + OPCODE_REGIMM => { + let string_version = format!(" dahi {} {}", str_rs, str_immediate); + Ok(string_version) + }, + OPCODE_BEQ => { + let string_version = format!("beq {} {} {}", str_rs, str_rt, str_immediate); + Ok(string_version) + }, + OPCODE_BNE => { + let string_version = format!("beq {} {} {}", str_rs, str_rt, str_immediate); + Ok(string_version) + }, + // Store/load word to Coprocessor 1 + OPCODE_SWC1 => { + let string_version = format!("swc1 {} {} {}", str_ft, str_offset, str_base); + Ok(string_version) + }, + OPCODE_LWC1 => { + let string_version = format!("lwc1 {} {} {}", str_ft, str_offset, str_base); + Ok(string_version) + }, + OPCODE_J => { + let addr = value & 0x03ffffff; + let str_addr = format!("{:b}", addr); + let str_addr = str_addr.as_str(); + let string_version = format!("j {}", str_addr); + Ok(string_version) + }, + OPCODE_JAL => { + let addr = value & 0x03ffffff; + let str_addr = format!("{:b}", addr); + let str_addr = str_addr.as_str(); + + let string_version = format!("jal {}", str_addr); + Ok(string_version) + }, + + _ => Err(format!("opcode `{op}` not supported")), + } +} diff --git a/src/emulation_core/mips/memory.rs b/src/emulation_core/mips/memory.rs index d2f97ac1e..3288f56db 100644 --- a/src/emulation_core/mips/memory.rs +++ b/src/emulation_core/mips/memory.rs @@ -2,6 +2,7 @@ // pub const CAPACITY_BYTES: usize = 2^12; // 4KB use log::debug; +use super::instruction::get_string_version; pub const CAPACITY_BYTES: usize = 64 * 1024; // 64 KB #[derive(Clone, Debug, PartialEq)] @@ -9,6 +10,21 @@ pub struct Memory { pub memory: Vec, } +#[derive(Clone, Debug, PartialEq)] +pub struct UpdatedLine { + pub text: String, + pub line_number: usize +} + +impl UpdatedLine { + pub fn new(text: String, line_number: usize) -> Self { + UpdatedLine { + text, + line_number + } + } +} + impl Default for Memory { fn default() -> Self { Self { @@ -110,26 +126,41 @@ impl Memory { Ok(result) } - pub fn parse_formatted_hex(&mut self, input: &str) -> Result<(), String> { - let mut address = 0; - for (i, line) in input.lines().enumerate() { - // Split each line into parts + pub fn parse_hexdump(&mut self, input: &str) -> Result, String> { + let mut words = Vec::new(); + for line in input.lines() { let parts: Vec<&str> = line.split('\t').collect(); - let memory_address = &parts[0..2]; - parts[2..6] - .iter() - .try_for_each(|&part| -> Result<(), String> { - if address + 3 > CAPACITY_BYTES { - debug!("Address {} out of bounds", address); - () + for &part in &parts[2..6] { + let data = u32::from_str_radix(part, 16).map_err(|e| e.to_string())?; + words.push(data); + } + } + Ok(words) + } + + // Returns instructions that were updated with their string versions and line numbers + pub fn store_hexdump(&mut self, instructions: Vec) -> Result, String> { + let mut changed_lines: Vec = vec![]; + for (i, data) in instructions.iter().enumerate() { + let address = i as u64; + let line = match get_string_version(*data) { + Ok(string) => string, + Err(string) => string, + }; + let curr_word = match self.load_word(address * 4) { + Ok(data) => data, + Err(e) => { + debug!("{:?}", e); + 0 } - let data = u32::from_str_radix(&part, 16).map_err(|e| e.to_string())?; - self.store_word(address as u64, data)?; - address += 4; - Ok(()) - })?; + }; + if curr_word != *data { + changed_lines.push(UpdatedLine::new(line, i)); + self.store_word(address * 4, *data)? + } } - Ok(()) + + Ok(changed_lines) } } diff --git a/src/main.rs b/src/main.rs index bb0b5ea79..264d5a63b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,14 +8,15 @@ use emulation_core::datapath::Datapath; use emulation_core::mips::datapath::MipsDatapath; use emulation_core::mips::datapath::Stage; use gloo::{dialogs::alert, file::FileList}; -use gloo_console::log; +use log::debug; use js_sys::Object; +// use monaco::sys::editor::IModelContentChangedEvent; use monaco::{ api::TextModel, sys::{ editor::{ IEditorMinimapOptions, IEditorScrollbarOptions, IMarkerData, IModelDecorationOptions, - IModelDeltaDecoration, IStandaloneEditorConstructionOptions, ISuggestOptions, ScrollType + IModelDeltaDecoration, IStandaloneEditorConstructionOptions, ISuggestOptions, ScrollType, }, IMarkdownString, MarkerSeverity, }, @@ -80,10 +81,42 @@ fn app() -> Html { // Output strings for the console and memory viewers. let parser_text_output = use_state_eq(String::new); let memory_text_output = use_state_eq(String::new); + let pc_limit = use_state(|| 0); let last_memory_text_model = use_mut_ref(|| TextModel::create(&memory_text_output, Some("ini"), None).unwrap()); let memory_text_model = use_mut_ref(|| TextModel::create(&memory_text_output, Some("ini"), None).unwrap()); + + // let on_did_change_content_handler = { + // let memory_text_model = Rc::clone(&memory_text_model); + // Callback::from(move |e: &IModelContentChangedEvent| { + + // // handle the event + // }) + // }; + + // use_effect_with_deps( + // move |_| { + + // let memory_text_model = Rc::clone(&memory_text_model); + // let curr_memory_model = memory_text_model.borrow_mut().as_ref(); + // // create a JavaScript closure that calls the Yew callback + // let cb: Closure = Closure::new(move |event: Event| { + // // Inside the Closure, call the Yew callback + // if let Some(event) = event.dyn_ref::() { + // on_did_change_content_handler.emit(event); + // } + // }); + // let cb_func = cb.as_ref().unchecked_ref(); + + // // pass the &js_sys::Function to the on_did_change_content method + // curr_memory_model.on_did_change_content(cb_func); + + // cb.forget(); + // }, + // (), + // ); + // Since we want the Datapath to be independent from all the // events within the app, we will create it when the app loads. This is also done // since the scope will be open across all events involved with it. To achieve this, @@ -107,8 +140,8 @@ fn app() -> Html { // log!("Executed line: {}", *curr_line); raw_editor.reveal_line_in_center(*curr_line, Some(ScrollType::Smooth)); }) { - Some(()) => log!("Editor linked."), - None => log!("No editor :(") + Some(()) => debug!("Editor linked."), + None => debug!("No editor :(") }; }, text_model, @@ -127,6 +160,7 @@ fn app() -> Html { let not_highlighted = not_highlighted.clone(); // Clone the value before moving it into the closure let last_memory_text_model = Rc::clone(&last_memory_text_model); + let pc_limit = pc_limit.clone(); use_callback( @@ -136,6 +170,7 @@ fn app() -> Html { let memory_text_model = memory_text_model.borrow_mut(); // parses through the code to assemble the binary and retrieves programinfo for error marking and mouse hover let (program_info, assembled) = parser(text_model.get_value()); + pc_limit.set(assembled.len() * 4); parser_text_output.set(program_info.console_out_post_assembly); let last_memory_text_model = last_memory_text_model.borrow_mut(); @@ -269,36 +304,21 @@ fn app() -> Html { .into(), ); - memory_text_model.as_ref().delta_decorations(¬_highlighted, &executed_line, None); + // memory_text_model.as_ref().delta_decorations(¬_highlighted, &executed_line, None); // log!("These are the stacks after the push"); // log!(executed_line.at(0)); // log!(not_highlighted.at(0)); - // Update memory - let last_memory_text_model_value = last_memory_text_model.get_value(); - let current_memory_text_model_value = memory_text_model.get_value(); - - if current_memory_text_model_value != last_memory_text_model_value { - match datapath.memory.parse_formatted_hex(¤t_memory_text_model_value) { - Ok(()) => { - log!("Memory updated successfully."); - }, - Err(err) => { - log!("Error updating memory: {}", err) - } - } - } + // Execute instruction + datapath.execute_instruction(); + // Update memory let hexdump = &generate_formatted_hex(&datapath.memory); memory_text_model.set_value(hexdump); last_memory_text_model.set_value(hexdump); - // Execute instruction - - datapath.execute_instruction(); - // done with the highlight, prepare for the next one. executed_line.pop(); @@ -331,28 +351,8 @@ fn app() -> Html { let mut datapath = datapath.borrow_mut(); let highlight_decor = highlight_decor.borrow_mut(); - // Update memory let memory_text_model = memory_text_model.borrow_mut(); let last_memory_text_model = last_memory_text_model.borrow_mut(); - - let last_memory_text_model_value = last_memory_text_model.get_value(); - let current_memory_text_model_value = memory_text_model.get_value(); - - if current_memory_text_model_value != last_memory_text_model_value { - match datapath.memory.parse_formatted_hex(¤t_memory_text_model_value) { - Ok(()) => { - log!("Memory updated successfully."); - }, - Err(err) => { - log!("Error updating memory: {}", err) - } - } - } - - let hexdump = &generate_formatted_hex(&datapath.memory); - - memory_text_model.set_value(hexdump); - last_memory_text_model.set_value(hexdump); if datapath.current_stage == Stage::InstructionDecode { // highlight on InstructionDecode since syscall stops at that stage. @@ -385,12 +385,105 @@ fn app() -> Html { } else { datapath.execute_stage(); } + + // Update memory + let hexdump = &generate_formatted_hex(&datapath.memory); + + memory_text_model.set_value(hexdump); + last_memory_text_model.set_value(hexdump); trigger.force_update(); }, (), ) }; + let on_memory_clicked = { + let datapath = Rc::clone(&datapath); + let trigger = use_force_update(); + + // Code editor + let text_model = Rc::clone(&text_model); + + // Hex editor + let memory_text_model = Rc::clone(&memory_text_model); + let last_memory_text_model = Rc::clone(&last_memory_text_model); + + use_callback( + move |_, _| { + let mut datapath = datapath.borrow_mut(); + let text_model = text_model.borrow_mut(); + + let (programinfo, binary) = parser(text_model.get_value()); + + // Update memory + let memory_text_model = memory_text_model.borrow_mut(); + let last_memory_text_model = last_memory_text_model.borrow_mut(); + + let last_memory_text_model_value = last_memory_text_model.get_value(); + let current_memory_text_model_value = memory_text_model.get_value(); + + if current_memory_text_model_value != last_memory_text_model_value { + match datapath.memory.parse_hexdump(¤t_memory_text_model_value) { + Ok(instructions) => { + debug!("Memory parsed with no errors."); + match datapath.memory.store_hexdump(instructions) { + Ok(changed_lines) => { + debug!("Memory updated successfully. Changed lines:"); + debug!("{:?}", changed_lines); + for line in changed_lines { + debug!("{}", binary[line.line_number]); + debug!("{}", programinfo.address_to_line_number[line.line_number]); + let updated_line = programinfo.address_to_line_number[line.line_number] as f64 + 1.0; + let curr_model = text_model.as_ref(); + + let line_to_replace = curr_model.get_line_content(updated_line); + let mut start_line_column = 0.0; + let end_line_column = line_to_replace.len() as f64 + 2.0; + for (i, c) in line_to_replace.chars().enumerate() { + if c.is_alphanumeric() { + start_line_column = i as f64 + 1.0; + break; + } + } + debug!("Line to replace -> {:?}, {:?}: {:?}: {:?}: {:?}", line_to_replace, updated_line, start_line_column, updated_line, end_line_column); + + let edit_range = monaco::sys::Range::new(updated_line, start_line_column, updated_line, end_line_column); + let before_cursor_state = monaco::sys::Selection::new(updated_line, start_line_column, updated_line,end_line_column); + let edit_operations: monaco::sys::editor::IIdentifiedSingleEditOperation = Object::new().unchecked_into(); + edit_operations.set_range(&edit_range); + edit_operations.set_text(Some(&line.text)); + let edit_operations_array = js_sys::Array::new(); + edit_operations_array.push(&edit_operations); + let before_cursor_state_array = js_sys::Array::new(); + before_cursor_state_array.push(&before_cursor_state); + curr_model.push_edit_operations(&before_cursor_state_array, &edit_operations_array, None); + } + + }, + Err(err) => { + debug!("Error: {}", err) + } + }; + () + }, + Err(err) => { + debug!("Error updating memory: {}", err) + } + } + } + + let hexdump = &generate_formatted_hex(&datapath.memory); + + memory_text_model.set_value(hexdump); + last_memory_text_model.set_value(hexdump); + + trigger.force_update(); + + }, + (), + ) + }; + // This is how we will reset the datapath. // This will also clear any highlight on the editor. let on_reset_clicked = { @@ -561,6 +654,7 @@ fn app() -> Html { // +
@@ -574,7 +668,7 @@ fn app() -> Html {
// Right column - + } @@ -657,6 +751,6 @@ pub fn on_upload_file_clicked() { } fn main() { - console_log::init_with_level(Level::Debug); + console_log::init_with_level(Level::Debug).unwrap(); yew::Renderer::::new().render(); } diff --git a/src/parser/parser_assembler_main.rs b/src/parser/parser_assembler_main.rs index 482468b89..46ed9ab4e 100644 --- a/src/parser/parser_assembler_main.rs +++ b/src/parser/parser_assembler_main.rs @@ -918,7 +918,7 @@ pub fn read_instructions( //this instruction is not used in pseudo-instructions so we can push it to mouse_hover_string without checking if mouse_hover_string is empty let info = InstructionDescription{ - syntax: "lwc1 ft offset(base)".to_string(), + syntax: "lwc1 ft, offset(base)".to_string(), description: "Loads the contents of the 32-bit word at the specified memory address into `ft`.\n\nMemory address is calculated as the sum of `offset` and the contents of the `base` register.".to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); diff --git a/src/tests/emulation_core.rs b/src/tests/emulation_core.rs index e01c7c3d4..e37c6290d 100644 --- a/src/tests/emulation_core.rs +++ b/src/tests/emulation_core.rs @@ -1,3 +1,4 @@ pub mod memory; pub mod mips; pub mod registers; +pub mod instruction; diff --git a/src/tests/emulation_core/instruction.rs b/src/tests/emulation_core/instruction.rs new file mode 100644 index 000000000..219241042 --- /dev/null +++ b/src/tests/emulation_core/instruction.rs @@ -0,0 +1,35 @@ +use crate::emulation_core::mips::instruction::get_string_version; + +#[test] +fn get_string_version_from_binary() { + let instruction: u32 = 0b00110100000011100000000111110100; + + assert!(match get_string_version(instruction) { + Ok(string) => { + string.contains("ori $t6 $zero 500") + }, + _ => false, + }); +} +#[test] +fn get_string_version_from_hex() { + let instruction: u32 = 0x340e01f4; + + assert!(match get_string_version(instruction) { + Ok(string) => { + string.contains("ori $t6 $zero 500") + }, + _ => false, + }); +} + +#[test] +fn err_on_empty_instruction() { + + let instruction: u32 = 0b00000000000000000000000000000000; + + assert!(match get_string_version(instruction) { + Err(e) => e.contains("empty instruction"), + _ => false, + }); +} \ No newline at end of file diff --git a/src/ui/console/component.rs b/src/ui/console/component.rs index 6fc385a93..29a87947e 100644 --- a/src/ui/console/component.rs +++ b/src/ui/console/component.rs @@ -13,7 +13,6 @@ use monaco::api::TextModel; use crate::emulation_core::mips::datapath::MipsDatapath; use crate::ui::visual_datapath::{DatapathSize, VisualDatapath}; use crate::ui::hex_editor::component::HexEditor; -use crate::emulation_core::mips::memory::Memory; #[derive(PartialEq, Properties)] pub struct Consoleprops { @@ -100,17 +99,9 @@ pub fn console(props: &Consoleprops) -> Html { } else if *active_tab == TabState::HexEditor {
- //
- } - // else { - //
- //
-            //             {props.datapath.memory.generate_formatted_hex() }
-            //         
- //
- // } + }
if *active_tab == TabState::Console { diff --git a/src/ui/hex_editor/component.rs b/src/ui/hex_editor/component.rs index 50b630919..ed15f138e 100644 --- a/src/ui/hex_editor/component.rs +++ b/src/ui/hex_editor/component.rs @@ -1,84 +1,30 @@ -use yew::{function_component, html, Html, Properties, TargetCast, Component, Context}; +use yew::{function_component, html, Html, Properties}; use crate::emulation_core::mips::memory::{Memory, MemoryIter}; -use yew::prelude::*; -use web_sys::Element; -use wasm_bindgen::{prelude::*, JsCast, JsValue}; -use web_sys::{ - CanvasRenderingContext2d, Document, HtmlCanvasElement, HtmlInputElement, InputEvent, -}; use std::rc::Rc; use std::cell::RefCell; -use log::debug; -use js_sys::{Array, Object, Function}; -use yew_hooks::prelude::*; - -use std::ops::{Deref, DerefMut}; use monaco::{ api::TextModel, - sys::{ + sys:: editor::{ - IEditorMinimapOptions, IEditorScrollbarOptions, IMarkerData, IModelDecorationOptions, ICursorPositionChangedEvent, IStandaloneCodeEditor, - IModelDeltaDecoration, IStandaloneEditorConstructionOptions, ISuggestOptions, ICodeEditor, create + IEditorMinimapOptions, IEditorScrollbarOptions, IStandaloneEditorConstructionOptions, ISuggestOptions }, - IMarkdownString, MarkerSeverity, - languages::{ILanguageExtensionPoint, LanguageConfiguration} - }, yew::{CodeEditor, CodeEditorLink}, }; - -pub struct CursorPosition { - line_number: u32, - column_number: u32 -} #[derive(PartialEq, Properties)] pub struct HexEditorProps { - // #[prop_or_default] - // pub memory: Memory pub memory_text_model: Rc> } #[function_component(HexEditor)] pub fn hex_editor(props: &HexEditorProps) -> Html { - // let memory_string = generate_formatted_hex(&props.memory); - - // let memory_text_model = use_mut_ref(|| TextModel::create(&memory_string, Some("ini"), None).unwrap()); - - - // let dirty_line = js_sys::Array::new(); - - // let cursor_position = CursorPosition { - // line_number: 0, - // column_number: 0 - // }; - let editor_link = CodeEditorLink::new(); - - // Define the event listener - // pub fn handle_cursor_position_change (e: ICursorPositionChangedEvent) { - // debug!("{:?}", e.position()); - // }; - - // let editor_link_clone = editor_link.clone(); - - // // Use the use_effect hook to run code after the component is mounted - // use_effect(move || { - // // Access the CodeEditor instance after it's created - // if let Some(editor) = editor_link_clone.with_editor(|editor| { - // // Attach the event listener after the editor is created - // editor.on_did_change_cursor_position(handle_cursor_position_change.clone()) - // }) { - // // Perform cleanup if needed - - // } - // }); - html! { - } } @@ -142,52 +88,3 @@ fn get_options() -> IStandaloneEditorConstructionOptions { options } - - -// editor.onDidChangeModelContent(e => { -// if (/* your condition here */) { -// // your logic here -// overridenPosition = { lineNumber: 4, column: 2 }; // put your value here -// } -// }); - -// editor.onDidChangeCursorPosition(e => { -// if (overridenPosition != null) { -// editor.setPosition(overridenPosition); -// overridenPosition = null; -// } -// }); - -// pub struct HexEditor { -// node_ref: NodeRef, -// } - -// impl Component for HexEditor { -// type Message = (); -// type Properties = (); - -// // Properties from the parent component are store in Context -// fn create(_ctx: &Context) -> Self { -// Self { -// node_ref: NodeRef::default(), -// } -// } - -// fn view(&self, _ctx: &Context) -> Html { -// html! { -//
-// } -// } - -// fn rendered(&mut self, _ctx: &Context, _first_render: bool) { -// let has_attributes = self.node_ref -// .cast::() -// .unwrap() -// .has_attributes(); -// } -// } -// pub enum Msg { -// UpdateValue(String), -// UpdateAddress(String), -// } - diff --git a/src/ui/regview/component.rs b/src/ui/regview/component.rs index 202d7ab55..a6eba2e77 100644 --- a/src/ui/regview/component.rs +++ b/src/ui/regview/component.rs @@ -1,4 +1,5 @@ use crate::emulation_core::mips::datapath::MipsDatapath; +use crate::emulation_core::mips::memory::CAPACITY_BYTES; use crate::emulation_core::mips::registers::{GpRegisterType, GpRegisters}; //use gloo::console::log; use wasm_bindgen::JsCast; @@ -14,7 +15,8 @@ use std::cell::RefCell; pub struct Regviewprops { pub gp: GpRegisters, pub fp: [u64; 32], - pub datapath: Rc> + pub datapath: Rc>, + pub pc_limit: usize } #[derive(PartialEq, Properties)] pub struct Regrowprops { @@ -37,10 +39,10 @@ enum UnitState { Double, } -#[derive(Debug)] -enum Msg { - UpdateRegister(GpRegisterType, u64), -} +// #[derive(Debug)] +// enum Msg { +// UpdateRegister(GpRegisterType, i64), +// } pub struct InputData { pub value: String, @@ -49,7 +51,7 @@ pub struct InputData { //Convert register to html through iterator pub fn generate_gpr_rows(props: &Regrowprops) -> Html { - + props.gp.into_iter() .map(|(register, data)| { let on_input = Callback::clone(&props.on_input); @@ -57,8 +59,8 @@ pub fn generate_gpr_rows(props: &Regrowprops) -> Html { {get_gpr_name(register)} - @@ -171,8 +173,9 @@ pub fn get_gpr_name(register: GpRegisterType) -> String { pub fn regview(props: &Regviewprops) -> Html { let active_view = use_state_eq(UnitState::default); let switch_flag = use_state_eq(|| true); - + let datapath = Rc::clone(&props.datapath); + let pc_limit = props.pc_limit; let change_view = { let active_view = active_view.clone(); Callback::from(move |event: MouseEvent| { @@ -220,17 +223,42 @@ pub fn regview(props: &Regviewprops) -> Html { let (e, register) = args; let target = e.target(); let input = target.unwrap().unchecked_into::(); - let val: u64 = input.value().parse().unwrap(); - let msg = Msg::UpdateRegister(register, val); + let val: i64 = match input.value().parse() { + Ok(value) => { + input.style().set_property("color", "black").unwrap_or_default(); + value + }, + Err(_err) => { + input.style().set_property("color", "red").unwrap_or_default(); + return + } + }; + // let msg = Msg::UpdateRegister(register, val); let mut datapath = datapath.borrow_mut(); let write_destination: usize = register as usize; if register == GpRegisterType::Pc { - datapath.registers.pc = val; - } + // check if pc is more than the number of instructions + // or if it's not word aligned + if val > pc_limit as i64 || val % 4 != 0 + { + input.style().set_property("color", "red").unwrap_or_default(); + return + } + + datapath.registers.pc = val as u64; + } + // check if pc is more than memory capacity + // or if it's not word aligned + else if register == GpRegisterType::Sp { + if val > CAPACITY_BYTES as i64 || val < 0 || val % 4 != 0 { + input.style().set_property("color", "red").unwrap_or_default(); + return + } + } else { - datapath.registers.gpr[write_destination] = val; + datapath.registers.gpr[write_destination] = val as u64; } }); diff --git a/src/ui/visual_datapath/mod.rs b/src/ui/visual_datapath/mod.rs index 28a07a18f..8f8727af8 100644 --- a/src/ui/visual_datapath/mod.rs +++ b/src/ui/visual_datapath/mod.rs @@ -375,7 +375,7 @@ impl VisualDatapath { } else { Self::set_inactive(&path)?; } - path.style().set_property("stroke-width", "10"); + path.style().set_property("stroke-width", "10").unwrap(); if path.tag_name() == "path" { // Set the initial state of this path: From 1addaa0f64835422a5ced98f33d44ad82e7ef3b9 Mon Sep 17 00:00:00 2001 From: Cay Date: Sun, 14 Jan 2024 14:50:35 -0500 Subject: [PATCH 007/355] Prohibit edit operations beyond current line numbers and add ability to add lines of code through memory editor --- src/bin/main.rs | 75 +++++++++++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 28 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index 4ed97cf0d..cb0a07784 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -19,9 +19,9 @@ use monaco::{ }; use swim::parser::parser_assembler_main::parser; use std::rc::Rc; -use ui::console::component::Console; -use ui::regview::component::Regview; -use ui::hex_editor::component::generate_formatted_hex; +use swim::ui::console::component::Console; +use swim::ui::regview::component::Regview; +use swim::ui::hex_editor::component::generate_formatted_hex; use wasm_bindgen::{JsCast, JsValue}; use wasm_bindgen_futures::spawn_local; use web_sys::HtmlInputElement; @@ -36,7 +36,7 @@ use yew_agent::Spawnable; // To load in the Fibonacci example, uncomment the CONTENT and fib_model lines // and comment the code, language, and text_model lines. IMPORTANT: // rename fib_model to text_model to have it work. -const CONTENT: &str = include_str!("../../static/assembly_examples/fibonacci.asm"); +const CONTENT: &str = include_str!("../../static/assembly_examples/store_word.asm"); #[function_component(App)] fn app() -> Html { @@ -426,33 +426,52 @@ fn app() -> Html { Ok(changed_lines) => { debug!("Memory updated successfully. Changed lines:"); debug!("{:?}", changed_lines); + let mut lines_beyond_counter = programinfo.address_to_line_number.len(); + let mut curr_value = text_model.get_value().to_owned(); + let mut add_new_lines = false; for line in changed_lines { - debug!("{}", binary[line.line_number]); - debug!("{}", programinfo.address_to_line_number[line.line_number]); - let updated_line = programinfo.address_to_line_number[line.line_number] as f64 + 1.0; - let curr_model = text_model.as_ref(); - - let line_to_replace = curr_model.get_line_content(updated_line); - let mut start_line_column = 0.0; - let end_line_column = line_to_replace.len() as f64 + 2.0; - for (i, c) in line_to_replace.chars().enumerate() { - if c.is_alphanumeric() { - start_line_column = i as f64 + 1.0; - break; + if line.line_number < programinfo.address_to_line_number.len() { + debug!("{}", binary[line.line_number]); + debug!("{}", programinfo.address_to_line_number[line.line_number]); + let updated_line = programinfo.address_to_line_number[line.line_number] as f64 + 1.0; + let curr_model = text_model.as_ref(); + + let line_to_replace = curr_model.get_line_content(updated_line); + let mut start_line_column = 0.0; + let end_line_column = line_to_replace.len() as f64 + 2.0; + for (i, c) in line_to_replace.chars().enumerate() { + if c.is_alphanumeric() { + start_line_column = i as f64 + 1.0; + break; + } } + debug!("Line to replace -> {:?}, {:?}: {:?}: {:?}: {:?}", line_to_replace, updated_line, start_line_column, updated_line, end_line_column); + + let edit_range = monaco::sys::Range::new(updated_line, start_line_column, updated_line, end_line_column); + let before_cursor_state = monaco::sys::Selection::new(updated_line, start_line_column, updated_line,end_line_column); + let edit_operations: monaco::sys::editor::IIdentifiedSingleEditOperation = Object::new().unchecked_into(); + edit_operations.set_range(&edit_range); + edit_operations.set_text(Some(&line.text)); + let edit_operations_array = js_sys::Array::new(); + edit_operations_array.push(&edit_operations); + let before_cursor_state_array = js_sys::Array::new(); + before_cursor_state_array.push(&before_cursor_state); + curr_model.push_edit_operations(&before_cursor_state_array, &edit_operations_array, None); + } else if line.line_number == lines_beyond_counter { + debug!("Adding new line: {}", &line.text); + // check if we've added new lines already + if !add_new_lines { + // start adding new lines by getting a copy of the current text model to append to + add_new_lines = true; + curr_value = text_model.get_value(); + } + curr_value.push_str("\n"); + curr_value.push_str(&line.text); + lines_beyond_counter += 1; } - debug!("Line to replace -> {:?}, {:?}: {:?}: {:?}: {:?}", line_to_replace, updated_line, start_line_column, updated_line, end_line_column); - - let edit_range = monaco::sys::Range::new(updated_line, start_line_column, updated_line, end_line_column); - let before_cursor_state = monaco::sys::Selection::new(updated_line, start_line_column, updated_line,end_line_column); - let edit_operations: monaco::sys::editor::IIdentifiedSingleEditOperation = Object::new().unchecked_into(); - edit_operations.set_range(&edit_range); - edit_operations.set_text(Some(&line.text)); - let edit_operations_array = js_sys::Array::new(); - edit_operations_array.push(&edit_operations); - let before_cursor_state_array = js_sys::Array::new(); - before_cursor_state_array.push(&before_cursor_state); - curr_model.push_edit_operations(&before_cursor_state_array, &edit_operations_array, None); + } + if add_new_lines { + text_model.set_value(&curr_value); } }, From d1f5d6da9a9f107cff9cfbd16b82a02959f983bf Mon Sep 17 00:00:00 2001 From: Cay Date: Mon, 15 Jan 2024 11:15:00 -0500 Subject: [PATCH 008/355] start adding hex-editor selection --- src/ui/hex_editor/component.rs | 78 +++++++++++++++++++++++++++++++++- static/styles/main.css | 4 ++ 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/ui/hex_editor/component.rs b/src/ui/hex_editor/component.rs index ed15f138e..c0397d41e 100644 --- a/src/ui/hex_editor/component.rs +++ b/src/ui/hex_editor/component.rs @@ -1,7 +1,11 @@ -use yew::{function_component, html, Html, Properties}; +use js_sys::Object; +use wasm_bindgen::{closure::Closure, JsValue}; +use yew::{function_component, html, Html, Properties, use_callback, Callback, use_mut_ref, use_effect_with_deps}; use crate::emulation_core::mips::memory::{Memory, MemoryIter}; use std::rc::Rc; use std::cell::RefCell; +use log::debug; +use wasm_bindgen::JsCast; use monaco::{ api::TextModel, @@ -19,12 +23,84 @@ pub struct HexEditorProps { #[function_component(HexEditor)] pub fn hex_editor(props: &HexEditorProps) -> Html { let editor_link = CodeEditorLink::new(); + let text_model = Rc::clone(&props.memory_text_model); + let executed_line = js_sys::Array::new(); + let not_highlighted = js_sys::Array::new(); + let mut mutated = false; + + use_effect_with_deps( + move |_| { + + let memory_text_model = text_model.borrow_mut(); + + }, + executed_line, + ); + + // create a JavaScript closure + let cb = Closure::wrap(Box::new(move |event: monaco::sys::editor::ICursorSelectionChangedEvent| { + let highlight_decor = monaco::sys::editor::IModelDecorationOptions::default(); + highlight_decor.set_class_name("hexHighlight".into()); + + debug!("Selection: {:?}", event.selection()); + let selection = event.selection(); + let start_line_number = selection.selection_start_line_number(); + let end_line_number = selection.position_line_number(); + let start_column = selection.start_column(); + let end_column = selection.end_column(); + + let curr_range = monaco::sys::Range::new(start_line_number, start_column, end_line_number, end_column); + + // element to be stored in the stack to highlight the line + let highlight_line: monaco::sys::editor::IModelDeltaDecoration = + Object::new().unchecked_into(); + highlight_line.set_options(&highlight_decor); + let range_js = curr_range + .dyn_into::() + .expect("Hex range is not found."); + highlight_line.set_range(&monaco::sys::IRange::from(range_js)); + let highlight_js = highlight_line + .dyn_into::() + .expect("Hex highlight is not found."); + + if start_column > 8.0 && end_column < 46.0 { + // select ASCII + } + else if start_column > 45.0 && end_column < 63.0 { + // select hex + } + + + }) as Box); + + let on_editor_created = { + let text_model = Rc::clone(&props.memory_text_model); + + use_callback( + move |editor_link: CodeEditorLink, text_model| { + match editor_link.with_editor(|editor| { + let raw_editor = editor.as_ref(); + + debug!("Helo!"); + let cb_func = &cb.as_ref().unchecked_ref(); + + raw_editor.on_did_change_cursor_selection(cb_func); + + }) { + Some(()) => debug!("Hex Editor linked!"), + None => debug!("No editor :(") + }; + }, + text_model, + ) + }; html! { } } diff --git a/static/styles/main.css b/static/styles/main.css index baa3201c0..3b84be6b3 100644 --- a/static/styles/main.css +++ b/static/styles/main.css @@ -52,6 +52,10 @@ body { color: rgb(49, 212, 144) !important; font-weight: bold; } +.hexHighlight { + color: rgb(49, 212, 144) !important; + font-weight: bold; +} /****** Console ******/ .console { From f71ee344cbc5cb8bbc828f64188898de7da008d2 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 18 Jan 2024 15:34:23 -0500 Subject: [PATCH 009/355] Implement sending/receving from worker thread --- src/bin/main.rs | 46 +++++++++++++++++---- src/bin/worker.rs | 4 +- src/emulation_core.rs | 4 +- src/emulation_core/agent.rs | 6 +-- src/emulation_core/datapath_communicator.rs | 42 ++++++++++++++++--- src/lib.rs | 2 +- 6 files changed, 82 insertions(+), 22 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index dbea2550c..4971eacad 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,7 +1,3 @@ -use swim::emulation_core::datapath::Datapath; -use swim::emulation_core::mips::datapath::MipsDatapath; -use swim::emulation_core::mips::datapath::Stage; -use swim::emulation_core::agent::EmulationCoreAgent; use gloo::{dialogs::alert, file::FileList}; use js_sys::Object; use monaco::{ @@ -15,8 +11,13 @@ use monaco::{ }, yew::CodeEditor, }; -use swim::parser::parser_assembler_main::parser; use std::rc::Rc; +use swim::emulation_core::agent::EmulationCoreAgent; +use swim::emulation_core::datapath::Datapath; +use swim::emulation_core::datapath_communicator::DatapathCommunicator; +use swim::emulation_core::mips::datapath::MipsDatapath; +use swim::emulation_core::mips::datapath::Stage; +use swim::parser::parser_assembler_main::parser; use swim::ui::console::component::Console; use swim::ui::regview::component::Regview; use wasm_bindgen::{JsCast, JsValue}; @@ -24,16 +25,29 @@ use wasm_bindgen_futures::spawn_local; use web_sys::HtmlInputElement; use yew::prelude::*; use yew::{html, Html, Properties}; -use yew_hooks::prelude::*; use yew_agent::Spawnable; +use yew_hooks::prelude::*; // To load in the Fibonacci example, uncomment the CONTENT and fib_model lines // and comment the code, language, and text_model lines. IMPORTANT: // rename fib_model to text_model to have it work. const CONTENT: &str = include_str!("../../static/assembly_examples/fibonacci.asm"); +#[derive(Properties, Clone)] +struct AppProps { + communicator: &'static DatapathCommunicator, +} + +impl PartialEq for AppProps { + fn eq(&self, other: &Self) -> bool { + let self_ptr: *const Self = self; + let other_ptr: *const Self = other; + self_ptr == other_ptr + } +} + #[function_component(App)] -fn app() -> Html { +fn app(props: &AppProps) -> Html { // This contains the binary representation of "ori $s0, $zero, 12345", which // stores 12345 in register $s0. // let code = String::from("ori $s0, $zero, 12345\n"); @@ -78,8 +92,18 @@ fn app() -> Html { // the ability to access and change its contents be mutable. let datapath = use_mut_ref(MipsDatapath::default); + // Start listening for messages from the communicator + { + let trigger = use_force_update(); + let communicator = props.communicator; + use_effect(move || { + spawn_local(communicator.listen_for_updates(trigger)); + }); + } + // This is where code is assembled and loaded into the emulation core's memory. let on_assemble_clicked = { + props.communicator.send_test_message(); let text_model = Rc::clone(&text_model); let datapath = Rc::clone(&datapath); let parser_text_output = parser_text_output.clone(); @@ -534,6 +558,12 @@ pub fn on_upload_file_clicked() { } fn main() { + // Initialize and leak the communicator to ensure that the thread spawns immediately and the bridge to it lives + // for the remainder of the program. let bridge = EmulationCoreAgent::spawner().spawn("./worker.js"); - yew::Renderer::::new().render(); + let communicator = Box::new(DatapathCommunicator::new(bridge)); + yew::Renderer::::with_props(AppProps { + communicator: Box::leak(communicator), + }) + .render(); } diff --git a/src/bin/worker.rs b/src/bin/worker.rs index 5430906de..f02e1b997 100644 --- a/src/bin/worker.rs +++ b/src/bin/worker.rs @@ -1,6 +1,6 @@ -use yew_agent::Registrable; use swim::emulation_core::agent::EmulationCoreAgent; +use yew_agent::Registrable; fn main() { EmulationCoreAgent::registrar().register(); -} \ No newline at end of file +} diff --git a/src/emulation_core.rs b/src/emulation_core.rs index 0d8e00947..7fcb1c723 100644 --- a/src/emulation_core.rs +++ b/src/emulation_core.rs @@ -1,6 +1,6 @@ //! The emulation core for the project. +pub mod agent; pub mod datapath; +pub mod datapath_communicator; pub mod mips; -pub mod agent; -mod datapath_communicator; \ No newline at end of file diff --git a/src/emulation_core/agent.rs b/src/emulation_core/agent.rs index ef960e1af..eb89d7526 100644 --- a/src/emulation_core/agent.rs +++ b/src/emulation_core/agent.rs @@ -1,13 +1,13 @@ -use yew_agent::prelude::*; use futures::{SinkExt, StreamExt}; -use serde::{Deserialize, Serialize}; use gloo_console::log; +use yew_agent::prelude::*; #[reactor(EmulationCoreAgent)] pub async fn emulation_core_agent(mut scope: ReactorScope) { log!("Hello world!"); scope.send(1).await.unwrap(); loop { - let _msg = scope.next().await; + let msg = scope.next().await; + log!("Got message: ", msg); } } diff --git a/src/emulation_core/datapath_communicator.rs b/src/emulation_core/datapath_communicator.rs index ab085d8d1..b90a0d9eb 100644 --- a/src/emulation_core/datapath_communicator.rs +++ b/src/emulation_core/datapath_communicator.rs @@ -1,21 +1,51 @@ +use crate::emulation_core::agent::EmulationCoreAgent; use futures::stream::{SplitSink, SplitStream}; +use futures::FutureExt; +use futures::SinkExt; use futures::StreamExt; use gloo_console::log; +use gloo_console::warn; +use std::cell::RefCell; use yew::UseForceUpdateHandle; use yew_agent::reactor::ReactorBridge; -use crate::emulation_core::agent::EmulationCoreAgent; pub struct DatapathCommunicator { - writer: SplitSink, i32>, - reader: SplitStream>, + writer: RefCell, i32>>, + reader: RefCell>>, } impl DatapathCommunicator { - pub async fn listen_for_updates(&mut self, update_handle: UseForceUpdateHandle) { + pub fn new(bridge: ReactorBridge) -> DatapathCommunicator { + let (write, read) = bridge.split(); + DatapathCommunicator { + writer: RefCell::new(write), + reader: RefCell::new(read), + } + } + + #[allow(clippy::await_holding_refcell_ref)] + pub async fn listen_for_updates(&self, update_handle: UseForceUpdateHandle) { + let mut reader = match self.reader.try_borrow_mut() { + Ok(reader) => reader, + Err(_) => { + warn!("Warning: Attempted to listen for updates multiple times"); + return; + } + }; + loop { - let update = self.reader.next().await; + let update = reader.next().await; log!(format!("Got update {:?}", update)); update_handle.force_update(); } } -} \ No newline at end of file + + pub fn send_test_message(&self) { + let mut writer = self.writer.borrow_mut(); + writer + .send(1) + .now_or_never() + .expect("Send function did not immediately return, async logic needed.") + .expect("Sending test message error") + } +} diff --git a/src/lib.rs b/src/lib.rs index cad0e1f1a..52b5b61b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,4 +2,4 @@ pub mod emulation_core; pub mod parser; #[cfg(test)] pub mod tests; -pub mod ui; \ No newline at end of file +pub mod ui; From 7413da24dbb374dcc38c55f903f8c493ebe92847 Mon Sep 17 00:00:00 2001 From: Cay Date: Fri, 19 Jan 2024 13:18:20 -0500 Subject: [PATCH 010/355] Adds text segment viewer and updates interface styles --- src/bin/main.rs | 94 ++++++++++++++++++++--- src/ui.rs | 1 + src/ui/assembled_view/component.rs | 101 +++++++++++++++++++++++++ src/ui/assembled_view/mod.rs | 1 + src/ui/console/component.rs | 16 ++-- src/ui/hex_editor/component.rs | 2 +- src/ui/regview/component.rs | 75 ++++++++----------- static/styles/main.css | 115 +++++++++++++++++++++++++++-- static/styles/tabs.css | 54 +++++++++++--- 9 files changed, 379 insertions(+), 80 deletions(-) create mode 100644 src/ui/assembled_view/component.rs create mode 100644 src/ui/assembled_view/mod.rs diff --git a/src/bin/main.rs b/src/bin/main.rs index cb0a07784..d56dc280b 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -18,9 +18,11 @@ use monaco::{ yew::{CodeEditor, CodeEditorLink}, }; use swim::parser::parser_assembler_main::parser; +use swim::parser::parser_structs_and_enums::ProgramInfo; use std::rc::Rc; use swim::ui::console::component::Console; use swim::ui::regview::component::Regview; +use swim::ui::assembled_view::component::AssembledView; use swim::ui::hex_editor::component::generate_formatted_hex; use wasm_bindgen::{JsCast, JsValue}; use wasm_bindgen_futures::spawn_local; @@ -36,7 +38,7 @@ use yew_agent::Spawnable; // To load in the Fibonacci example, uncomment the CONTENT and fib_model lines // and comment the code, language, and text_model lines. IMPORTANT: // rename fib_model to text_model to have it work. -const CONTENT: &str = include_str!("../../static/assembly_examples/store_word.asm"); +const CONTENT: &str = include_str!("../../static/assembly_examples/fibonacci.asm"); #[function_component(App)] fn app() -> Html { @@ -79,6 +81,11 @@ fn app() -> Html { let memory_text_output = use_state_eq(String::new); let pc_limit = use_state(|| 0); + // Input strings from the code editor + let lines_content = use_mut_ref(Vec::::new); + + let program_info_ref = use_mut_ref(ProgramInfo::default); + let last_memory_text_model = use_mut_ref(|| TextModel::create(&memory_text_output, Some("ini"), None).unwrap()); let memory_text_model = use_mut_ref(|| TextModel::create(&memory_text_output, Some("ini"), None).unwrap()); @@ -125,19 +132,29 @@ fn app() -> Html { let on_editor_created = { let text_model = Rc::clone(&text_model); let curr_line = Rc::clone(&curr_line); + let lines_content = Rc::clone(&lines_content); use_callback( move |editor_link: CodeEditorLink, _text_model| { - // log::trace!("render {editor_link:?}"); let curr_line = curr_line.borrow_mut(); match editor_link.with_editor(|editor| { let raw_editor = editor.as_ref(); - // log!("We made it."); - // log!("Executed line: {}", *curr_line); + let model = raw_editor.get_model().unwrap(); + // store each line from the original code editor's contents for assembled view + let js_lines = model.get_lines_content(); + let mut string_lines = lines_content.borrow_mut(); + for js_string in js_lines.into_iter() { + let string_value = match js_string.as_string() { + Some(string) => string, + None => String::from("") + }; + string_lines.push(string_value); + + }; raw_editor.reveal_line_in_center(*curr_line, Some(ScrollType::Smooth)); }) { - Some(()) => debug!("Editor linked."), - None => debug!("No editor :(") + Some(()) => debug!("Editor linked!"), + None => debug!("No editor :<") }; }, text_model, @@ -157,6 +174,7 @@ fn app() -> Html { // Clone the value before moving it into the closure let last_memory_text_model = Rc::clone(&last_memory_text_model); let pc_limit = pc_limit.clone(); + let program_info_ref = Rc::clone(&program_info_ref); use_callback( @@ -166,6 +184,7 @@ fn app() -> Html { let memory_text_model = memory_text_model.borrow_mut(); // parses through the code to assemble the binary and retrieves programinfo for error marking and mouse hover let (program_info, assembled) = parser(text_model.get_value()); + *program_info_ref.borrow_mut() = program_info.clone(); pc_limit.set(assembled.len() * 4); parser_text_output.set(program_info.console_out_post_assembly); let last_memory_text_model = last_memory_text_model.borrow_mut(); @@ -674,8 +693,8 @@ fn app() -> Html {
// Editor -
- +
+
// Console @@ -700,7 +719,17 @@ fn new_object() -> JsValue { pub struct SwimEditorProps { pub text_model: TextModel, pub link: CodeEditorLink, - pub on_editor_created: Callback + pub on_editor_created: Callback, + pub lines_content: Rc>>, + pub program_info: ProgramInfo +} + +#[derive(Default, PartialEq)] +enum EditorTabState { + #[default] + Editor, + TextSegment, + DataSegment } fn get_options() -> IStandaloneEditorConstructionOptions { @@ -731,8 +760,53 @@ fn get_options() -> IStandaloneEditorConstructionOptions { #[function_component] pub fn SwimEditor(props: &SwimEditorProps) -> Html { + let active_tab = use_state_eq(EditorTabState::default); + let change_tab = { + let active_tab = active_tab.clone(); + Callback::from(move |event: MouseEvent| { + let target = event.target().unwrap().dyn_into::().unwrap(); + let tab_name = target + .get_attribute("label") + .unwrap_or(String::from("editor")); + + let new_tab: EditorTabState = match tab_name.as_str() { + "editor" => EditorTabState::Editor, + "text" => EditorTabState::TextSegment, + "data" => EditorTabState::DataSegment, + _ => EditorTabState::default(), + }; + + active_tab.set(new_tab); + }) + }; html! { - + <> + // Editor buttons +
+ if *active_tab == EditorTabState::Editor { + + } else { + + } + + if *active_tab == EditorTabState::TextSegment { + + } else { + + } + + if *active_tab == EditorTabState::DataSegment { + + } else { + + } +
+ if *active_tab == EditorTabState::Editor { + + } else if *active_tab == EditorTabState::TextSegment { + + } + } } diff --git a/src/ui.rs b/src/ui.rs index 4e363e9b6..fd4f689fb 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -4,3 +4,4 @@ pub mod console; pub mod hex_editor; pub mod regview; pub mod visual_datapath; +pub mod assembled_view; diff --git a/src/ui/assembled_view/component.rs b/src/ui/assembled_view/component.rs new file mode 100644 index 000000000..ee0df0b2a --- /dev/null +++ b/src/ui/assembled_view/component.rs @@ -0,0 +1,101 @@ +use std::cell::RefCell; +use std::rc::Rc; + +use monaco::api::TextModel; +use web_sys::HtmlInputElement; +use yew::{Properties, Html}; +use yew::prelude::*; +use wasm_bindgen::JsCast; +use log::debug; +use crate::parser::parser_structs_and_enums::ProgramInfo; + + +#[derive(PartialEq, Properties)] +pub struct AssembledProps { + pub text_model: TextModel, + pub program_info: ProgramInfo, + pub lines_content: Rc>> +} + +#[function_component] +pub fn AssembledView(props: &AssembledProps) -> Html { + let program_info = &props.program_info; + let lines_content = props.lines_content.borrow_mut().clone(); + + let on_check = Callback::from(move |args: (MouseEvent, i32)| { + let (e, address) = args; + let target = e.target(); + let input = target.unwrap().unchecked_into::(); + + if (input.checked()) { + debug!("Breakpoint set at {:08x}", address); + } + + }); + + let on_address_click = Callback::from(move |args: (MouseEvent, i32)| { + let (e, address) = args; + let target = e.target(); + let input = target.unwrap().unchecked_into::(); + + debug!("Go to address {:08x}", address); + + }); + + let on_assembled_click = Callback::from(move |args: (MouseEvent, i32)| { + let (e, line_number) = args; + let target = e.target(); + let input = target.unwrap().unchecked_into::(); + + debug!("Go to line number {:08x}", line_number); + + }); + + let mut address = -4; + html! { + + // | breakpoint checkbox | address | instruction in binary | instruction in hex | updated string | source string + + + + + + + + + { + program_info.instructions.iter().enumerate().map(|(index, instruction)| { + let recreated_string = instruction.recreate_string(); + let on_check = Callback::clone(&on_check); + let on_address_click = Callback::clone(&on_address_click); + let on_assembled_click = Callback::clone(&on_assembled_click); + address += 4; + html!{ + + + + + + + + + + } + }).collect::() + } +
{"Bkpt"}{"Address"}{"Binary"}{"Hex"}{"Assembled"}{"Source"}
+ +
+
+ {format!("0x{:08x}", address as u64)} + + {format!("0b{:032b}", instruction.binary)} + + {format!("0x{:08x}", instruction.binary)} + + {recreated_string} + + {format!("{}: {:?}", instruction.line_number, lines_content.get(instruction.line_number).unwrap_or(&String::from("")))} +
+ } +} \ No newline at end of file diff --git a/src/ui/assembled_view/mod.rs b/src/ui/assembled_view/mod.rs new file mode 100644 index 000000000..519c53d92 --- /dev/null +++ b/src/ui/assembled_view/mod.rs @@ -0,0 +1 @@ +pub mod component; \ No newline at end of file diff --git a/src/ui/console/component.rs b/src/ui/console/component.rs index 29a87947e..bd646303c 100644 --- a/src/ui/console/component.rs +++ b/src/ui/console/component.rs @@ -105,27 +105,27 @@ pub fn console(props: &Consoleprops) -> Html {
if *active_tab == TabState::Console { - + } else { - + } if *active_tab == TabState::Memory { - + } else { - + } if *active_tab == TabState::Datapath { - + } else { - + } if *active_tab == TabState::HexEditor { - + } else { - + }
diff --git a/src/ui/hex_editor/component.rs b/src/ui/hex_editor/component.rs index c0397d41e..78512f296 100644 --- a/src/ui/hex_editor/component.rs +++ b/src/ui/hex_editor/component.rs @@ -88,7 +88,7 @@ pub fn hex_editor(props: &HexEditorProps) -> Html { }) { Some(()) => debug!("Hex Editor linked!"), - None => debug!("No editor :(") + None => debug!("No editor :<") }; }, text_model, diff --git a/src/ui/regview/component.rs b/src/ui/regview/component.rs index a6eba2e77..a42f7b778 100644 --- a/src/ui/regview/component.rs +++ b/src/ui/regview/component.rs @@ -178,11 +178,9 @@ pub fn regview(props: &Regviewprops) -> Html { let pc_limit = props.pc_limit; let change_view = { let active_view = active_view.clone(); - Callback::from(move |event: MouseEvent| { - let target = event.target().unwrap().dyn_into::().unwrap(); - let mode = target - .get_attribute("label") - .unwrap_or(String::from("regview")); + Callback::from(move |event: Event| { + let target = event.target().unwrap().unchecked_into::(); + let mode = target.value(); let new_mode = match mode.as_str() { "bin" => UnitState::Bin, @@ -270,49 +268,38 @@ pub fn regview(props: &Regviewprops) -> Html { //log!("This is ", *switch_flag); html! { -
-
- if *active_view == UnitState::Dec { - - } else { - - } - - if *active_view == UnitState::Bin { - - } else { - - } - - if *active_view == UnitState::Hex { - - } else { - - } - if !*switch_flag{ - if *active_view == UnitState::Float { - +
+
+
+ if *switch_flag { + } else { - + } - if *active_view == UnitState::Double { - + if !(*switch_flag){ + } else { - + } - } -
-
- if *switch_flag { - - } else { - - } - if !(*switch_flag){ - - } else { - - } +
+
diff --git a/static/styles/main.css b/static/styles/main.css index 3b84be6b3..4894cc174 100644 --- a/static/styles/main.css +++ b/static/styles/main.css @@ -42,10 +42,17 @@ body { } /****** Editor ******/ +.code { + display: flex; + flex-direction: column; + flex-grow: 1; + min-height: 4em; + margin-top: 8px; +} .editor { max-height: 1px; max-width: 1px; - min-height: 100%; + min-height: 96%; min-width: 100%; } .myInlineDecoration { @@ -57,6 +64,64 @@ body { font-weight: bold; } +/****** Assembled View ******/ +.text_segment { + height: 96%; + background-color: #1e1e1e; + color: #ddd; + + .address { + color:#5F894D; + cursor: pointer; + + &:hover { + color:#A4BB99; + } + } + + .assembled-string { + color: #006591; + cursor: pointer; + + &:hover { + color: #0178ab; + } + } +} + +.bkpt { + cursor: pointer; + height: 100%; + position: relative; + + input[type=checkbox] { + position: absolute; + top: 0; + left: 0; + opacity: 0; + cursor: pointer; + width: 100%; + height: 100%; + } + .circle { + top: 0; + left: 0; + height: 12px; + width: 12px; + border-radius: 50%; + margin: auto; + background-color: transparent; + } + + &:hover input ~ .circle { + background-color: #006591; + } + + input:checked ~ .circle { + background-color: #006591; + } +} + /****** Console ******/ .console { border: 3px groove #ccc; @@ -75,7 +140,7 @@ body { .hex-wrapper { border: 3px groove #ccc; - background: #012456; + background: #1E1E1E; color: #ccc; word-break: break-all; min-height: max(20%, 8em); @@ -88,7 +153,7 @@ body { .datapath-wrapper { flex-grow: 1.4; - border: 2px solid black; + /* border: 2px solid black; */ overflow: auto; width: 100%; flex-basis: 50%; @@ -104,29 +169,65 @@ body { } /****** Register View ******/ +.regview-menu { + display: flex; + flex-direction: row; + justify-content: space-between; + + select { + background-color: #474343; + color: #ddd; + display: flex; + align-items: center; + flex-direction: row; + } + + .unit-state { + text-align: right; + } +} .table-wrapper { - border: 1px solid black; + /* border: 1px solid black; */ overflow-y: auto; } thead { background-color: #006591; - color: #fff; +} +th { + background-color: #303030; } th, td { - border: 1px solid black; + /* border: 1px solid black; */ padding: 2px 16px 2px 16px; } +th:not(:last-child), td:not(:last-child) { + border-right: 1px solid black; +} + table { border-collapse: collapse; border-spacing: 0; display: block; overflow-y: auto; + color: #fff; } tr:nth-child(even) { - background-color: #ccc; + background-color: #1e1e1e; + input { + + background-color: #1e1e1e; + } +} +tr:nth-child(odd) +{ + background-color: #101010; + input { + + background-color: #101010; + } } td:nth-child(2) { diff --git a/static/styles/tabs.css b/static/styles/tabs.css index 8c1be472f..37cf1a09a 100644 --- a/static/styles/tabs.css +++ b/static/styles/tabs.css @@ -1,21 +1,30 @@ +.bar { + border-bottom: 3px solid gray; +} + .tabs { display: inline-block; - margin: 0 auto; + /* margin: 0 auto; */ +} +.tabs .tab { + border-radius: 5px 5px 0 0; } .tabs .tab:first-child { - border-radius: 300px 0 0 300px; + /* border-radius: 300px 0 0 300px; */ } .tabs .tab:last-child { - border-radius: 0 300px 300px 0; + /* border-radius: 0 300px 300px 0; */ } .tabs .tab:only-child { border-radius: 300px; } .tab { overflow: hidden; - background-color: rgb(255, 255, 255); + /* background-color: rgb(255, 255, 255); */ + background-color: #383838; padding: 2px 16px 2px 16px; - color: black; + /* color: black; */ + color: white; text-align: center; display: inline-block; cursor: pointer; @@ -27,16 +36,41 @@ } .tab:focus, .tab:active { - background-color: #2e2b2b !important; - color: white !important; + /* background-color: #2e2b2b !important; + color: white !important; */ + background-color: gray; } .tab::after { background-color: #2e2b2b; } -.pressed { - background-color: #2e2b2b ; +.tab.pressed { + /* background-color: #2e2b2b ; */ + background-color: #666666; padding: 2px 16px 2px 16px; - color: white; + /* color: white; */ text-align: center; display: inline-block; } +.bottom-tab { + overflow: hidden; + padding: 10px 16px 2px 16px; + color: rgb(198, 198, 198); + text-align: center; + display: inline-block; + cursor: pointer; + width: 114px; + + + &.pressed { + border-top: 5px solid #CCCCCC; + color: white; + font-weight: bold; + } +} + +.bottom-tab:focus, +.bottom-tab:hover, +.bottom-tab:active { + color: rgb(244, 244, 244); + transition: 0.1s; +} \ No newline at end of file From cdc25139e1aeb18b90eb7cbeb3355e39b42bdd27 Mon Sep 17 00:00:00 2001 From: Cay Date: Fri, 19 Jan 2024 16:18:59 -0500 Subject: [PATCH 011/355] Add data segment viewer --- src/bin/main.rs | 19 ++++-- src/parser/parser_structs_and_enums.rs | 20 ++++++ src/ui/assembled_view/component.rs | 91 ++++++++++++++++++++++++-- src/ui/console/component.rs | 11 +--- src/ui/hex_editor/component.rs | 19 ++---- static/assembly_examples/data.asm | 12 ++++ static/styles/main.css | 2 +- static/styles/tabs.css | 1 - 8 files changed, 141 insertions(+), 34 deletions(-) create mode 100644 static/assembly_examples/data.asm diff --git a/src/bin/main.rs b/src/bin/main.rs index d56dc280b..b49bba7e0 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -22,7 +22,7 @@ use swim::parser::parser_structs_and_enums::ProgramInfo; use std::rc::Rc; use swim::ui::console::component::Console; use swim::ui::regview::component::Regview; -use swim::ui::assembled_view::component::AssembledView; +use swim::ui::assembled_view::component::{TextSegment, DataSegment}; use swim::ui::hex_editor::component::generate_formatted_hex; use wasm_bindgen::{JsCast, JsValue}; use wasm_bindgen_futures::spawn_local; @@ -63,6 +63,7 @@ fn app() -> Html { let executed_line = js_sys::Array::new(); let not_highlighted = js_sys::Array::new(); let curr_line = Rc::new(RefCell::new(0.0)); + let memory_curr_line = Rc::new(RefCell::new(0.0)); // Setting up the options/parameters which // will highlight the previously executed line. @@ -85,6 +86,7 @@ fn app() -> Html { let lines_content = use_mut_ref(Vec::::new); let program_info_ref = use_mut_ref(ProgramInfo::default); + let binary_ref = use_mut_ref(Vec::::new); let last_memory_text_model = use_mut_ref(|| TextModel::create(&memory_text_output, Some("ini"), None).unwrap()); @@ -175,7 +177,7 @@ fn app() -> Html { let last_memory_text_model = Rc::clone(&last_memory_text_model); let pc_limit = pc_limit.clone(); let program_info_ref = Rc::clone(&program_info_ref); - + let binary_ref = Rc::clone(&binary_ref); use_callback( move |_, text_model| { @@ -185,6 +187,7 @@ fn app() -> Html { // parses through the code to assemble the binary and retrieves programinfo for error marking and mouse hover let (program_info, assembled) = parser(text_model.get_value()); *program_info_ref.borrow_mut() = program_info.clone(); + *binary_ref.borrow_mut() = assembled.clone(); pc_limit.set(assembled.len() * 4); parser_text_output.set(program_info.console_out_post_assembly); let last_memory_text_model = last_memory_text_model.borrow_mut(); @@ -694,11 +697,11 @@ fn app() -> Html { // Editor
- +
// Console - + // Right column @@ -721,7 +724,9 @@ pub struct SwimEditorProps { pub link: CodeEditorLink, pub on_editor_created: Callback, pub lines_content: Rc>>, - pub program_info: ProgramInfo + pub program_info: ProgramInfo, + pub binary: Vec, + pub memory_curr_line: Rc> } #[derive(Default, PartialEq)] @@ -804,7 +809,9 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html { if *active_tab == EditorTabState::Editor { } else if *active_tab == EditorTabState::TextSegment { - + + } else if *active_tab == EditorTabState::DataSegment { + } } diff --git a/src/parser/parser_structs_and_enums.rs b/src/parser/parser_structs_and_enums.rs index 163f264e4..97f07195b 100644 --- a/src/parser/parser_structs_and_enums.rs +++ b/src/parser/parser_structs_and_enums.rs @@ -145,6 +145,26 @@ pub struct Data { pub data_entries: Vec, } +impl Data { + ///Takes the operator, operands, and label(optional) associated with an instruction and recreates the string version + pub fn recreate_string(&self) -> String { + let mut recreated_string = "".to_string(); + recreated_string.push_str(&format!( + "{}: ", + self.label.clone().token_name + )); + recreated_string.push_str(&self.data_type.token_name.to_string()); + + for token in &self.data_entries { + recreated_string.push_str(&format!(" {},", token.token_name.clone())); + } + //pop the extra comma + recreated_string.pop(); + + recreated_string + } +} + #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct LabelInstance { pub token_line: usize, diff --git a/src/ui/assembled_view/component.rs b/src/ui/assembled_view/component.rs index ee0df0b2a..61596a460 100644 --- a/src/ui/assembled_view/component.rs +++ b/src/ui/assembled_view/component.rs @@ -11,16 +11,24 @@ use crate::parser::parser_structs_and_enums::ProgramInfo; #[derive(PartialEq, Properties)] -pub struct AssembledProps { - pub text_model: TextModel, +pub struct TextSegmentProps { pub program_info: ProgramInfo, - pub lines_content: Rc>> + pub lines_content: Rc>>, + pub memory_curr_line: Rc> +} +#[derive(PartialEq, Properties)] +pub struct DataSegmentProps { + pub program_info: ProgramInfo, + pub binary: Vec, + pub lines_content: Rc>>, + pub memory_curr_line: Rc> } #[function_component] -pub fn AssembledView(props: &AssembledProps) -> Html { +pub fn TextSegment(props: &TextSegmentProps) -> Html { let program_info = &props.program_info; let lines_content = props.lines_content.borrow_mut().clone(); + let memory_curr_line = props.memory_curr_line.borrow_mut(); let on_check = Callback::from(move |args: (MouseEvent, i32)| { let (e, address) = args; @@ -39,6 +47,8 @@ pub fn AssembledView(props: &AssembledProps) -> Html { let input = target.unwrap().unchecked_into::(); debug!("Go to address {:08x}", address); + debug!("Go to line {:?}", (address / 4) as f64); + // *memory_curr_line = (address / 4) as f64; }); @@ -53,7 +63,7 @@ pub fn AssembledView(props: &AssembledProps) -> Html { let mut address = -4; html! { -
+
// | breakpoint checkbox | address | instruction in binary | instruction in hex | updated string | source string @@ -98,4 +108,75 @@ pub fn AssembledView(props: &AssembledProps) -> Html { }
{"Bkpt"}
} +} + +#[function_component] +pub fn DataSegment(props: &DataSegmentProps) -> Html { + let program_info = &props.program_info; + let binary = &props.binary; + let lines_content = props.lines_content.borrow_mut().clone(); + let memory_curr_line = props.memory_curr_line.borrow_mut(); + + let on_address_click = Callback::from(move |args: (MouseEvent, usize)| { + let (e, address) = args; + let target = e.target(); + let input = target.unwrap().unchecked_into::(); + + debug!("Go to address {:08x}", address); + debug!("Go to line {:?}", (address / 4) as f64); + // *memory_curr_line = (address / 4) as f64; + + }); + + let on_assembled_click = Callback::from(move |args: (MouseEvent, usize)| { + let (e, line_number) = args; + let target = e.target(); + let input = target.unwrap().unchecked_into::(); + + debug!("Go to line number {:08x}", line_number); + + }); + + html! { + + // | address | data in hex | source string + + + + + + + { + if program_info.instructions.len() > 0 { + let mut address = program_info.instructions.len() * 4 - 4; + program_info.data.iter().enumerate().map(|(index, data)| { + let recreated_string = data.recreate_string(); + let on_address_click = Callback::clone(&on_address_click); + let on_assembled_click = Callback::clone(&on_assembled_click); + address += 4; + html!{ + + + + + + + + } + }).collect::() + } + else { + html! {<>} + } + } +
{"Address"}{"Hex"}{"Assembled"}{"Source"}
+ {format!("0x{:08x}", address as u64)} + + {format!("0x{:08x}", binary[data.line_number])} + + {recreated_string} + + {format!("{}: {:?}", data.line_number, lines_content.get(data.line_number).unwrap_or(&String::from("")))} +
+ } } \ No newline at end of file diff --git a/src/ui/console/component.rs b/src/ui/console/component.rs index bd646303c..96c7b5d40 100644 --- a/src/ui/console/component.rs +++ b/src/ui/console/component.rs @@ -19,6 +19,7 @@ pub struct Consoleprops { pub datapath: MipsDatapath, pub parsermsg: String, pub memory_text_model: Rc>, + pub memory_curr_line: Rc> } #[derive(Default, PartialEq)] @@ -26,7 +27,6 @@ enum TabState { #[default] Console, Datapath, - Memory, HexEditor } @@ -46,7 +46,6 @@ pub fn console(props: &Consoleprops) -> Html { let new_tab = match tab_name.as_str() { "console" => TabState::Console, "datapath" => TabState::Datapath, - "memory" => TabState::Memory, "hex_editor" => TabState::HexEditor, _ => TabState::default(), }; @@ -99,7 +98,7 @@ pub fn console(props: &Consoleprops) -> Html {
} else if *active_tab == TabState::HexEditor {
- +
}
@@ -110,12 +109,6 @@ pub fn console(props: &Consoleprops) -> Html { } - if *active_tab == TabState::Memory { - - } else { - - } - if *active_tab == TabState::Datapath { } else { diff --git a/src/ui/hex_editor/component.rs b/src/ui/hex_editor/component.rs index 78512f296..d401b5cb2 100644 --- a/src/ui/hex_editor/component.rs +++ b/src/ui/hex_editor/component.rs @@ -11,32 +11,24 @@ use monaco::{ api::TextModel, sys:: editor::{ - IEditorMinimapOptions, IEditorScrollbarOptions, IStandaloneEditorConstructionOptions, ISuggestOptions + IEditorMinimapOptions, IEditorScrollbarOptions, IStandaloneEditorConstructionOptions, ISuggestOptions, ScrollType }, yew::{CodeEditor, CodeEditorLink}, }; #[derive(PartialEq, Properties)] pub struct HexEditorProps { - pub memory_text_model: Rc> + pub memory_text_model: Rc>, + pub curr_line: Rc> } #[function_component(HexEditor)] pub fn hex_editor(props: &HexEditorProps) -> Html { let editor_link = CodeEditorLink::new(); let text_model = Rc::clone(&props.memory_text_model); - let executed_line = js_sys::Array::new(); + let curr_line = Rc::clone(&props.curr_line); let not_highlighted = js_sys::Array::new(); let mut mutated = false; - use_effect_with_deps( - move |_| { - - let memory_text_model = text_model.borrow_mut(); - - }, - executed_line, - ); - // create a JavaScript closure let cb = Closure::wrap(Box::new(move |event: monaco::sys::editor::ICursorSelectionChangedEvent| { let highlight_decor = monaco::sys::editor::IModelDecorationOptions::default(); @@ -75,9 +67,11 @@ pub fn hex_editor(props: &HexEditorProps) -> Html { let on_editor_created = { let text_model = Rc::clone(&props.memory_text_model); + let curr_line = Rc::clone(&curr_line); use_callback( move |editor_link: CodeEditorLink, text_model| { + let curr_line = curr_line.borrow_mut(); match editor_link.with_editor(|editor| { let raw_editor = editor.as_ref(); @@ -85,6 +79,7 @@ pub fn hex_editor(props: &HexEditorProps) -> Html { let cb_func = &cb.as_ref().unchecked_ref(); raw_editor.on_did_change_cursor_selection(cb_func); + // raw_editor.reveal_line_in_center(*curr_line, Some(ScrollType::Smooth)) }) { Some(()) => debug!("Hex Editor linked!"), diff --git a/static/assembly_examples/data.asm b/static/assembly_examples/data.asm new file mode 100644 index 000000000..c89613710 --- /dev/null +++ b/static/assembly_examples/data.asm @@ -0,0 +1,12 @@ +.text +addi $t0, $zero, 300 +syscall +.data +a_secret: .ascii "hi" +importantQuestion: .asciiz "What is system software?" +numbers: .byte 0x64, 100, 'a', 'b' +half: .half 1000 +buffer: .space 8 +word: .word 12345678 +float: .float 1.20 +double: .double 1.22222 diff --git a/static/styles/main.css b/static/styles/main.css index 4894cc174..63e38c40d 100644 --- a/static/styles/main.css +++ b/static/styles/main.css @@ -65,7 +65,7 @@ body { } /****** Assembled View ******/ -.text_segment { +.memory_segment { height: 96%; background-color: #1e1e1e; color: #ddd; diff --git a/static/styles/tabs.css b/static/styles/tabs.css index 37cf1a09a..d1e35f645 100644 --- a/static/styles/tabs.css +++ b/static/styles/tabs.css @@ -72,5 +72,4 @@ .bottom-tab:hover, .bottom-tab:active { color: rgb(244, 244, 244); - transition: 0.1s; } \ No newline at end of file From 005fca5a8c5a21366561a62ae433051165f31a7c Mon Sep 17 00:00:00 2001 From: Cay Date: Fri, 19 Jan 2024 16:39:46 -0500 Subject: [PATCH 012/355] Highlights executed line in text segment viewer --- src/bin/main.rs | 7 ++++--- src/ui/assembled_view/component.rs | 17 +++++++++++------ static/styles/main.css | 4 ++++ 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index b49bba7e0..98dbfd5a4 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -697,7 +697,7 @@ fn app() -> Html { // Editor
- +
// Console @@ -726,7 +726,8 @@ pub struct SwimEditorProps { pub lines_content: Rc>>, pub program_info: ProgramInfo, pub binary: Vec, - pub memory_curr_line: Rc> + pub memory_curr_line: Rc>, + pub pc: u64 } #[derive(Default, PartialEq)] @@ -809,7 +810,7 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html { if *active_tab == EditorTabState::Editor { } else if *active_tab == EditorTabState::TextSegment { - + } else if *active_tab == EditorTabState::DataSegment { } diff --git a/src/ui/assembled_view/component.rs b/src/ui/assembled_view/component.rs index 61596a460..4a2409455 100644 --- a/src/ui/assembled_view/component.rs +++ b/src/ui/assembled_view/component.rs @@ -14,7 +14,8 @@ use crate::parser::parser_structs_and_enums::ProgramInfo; pub struct TextSegmentProps { pub program_info: ProgramInfo, pub lines_content: Rc>>, - pub memory_curr_line: Rc> + pub memory_curr_line: Rc>, + pub pc: u64 } #[derive(PartialEq, Properties)] pub struct DataSegmentProps { @@ -30,7 +31,7 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html { let lines_content = props.lines_content.borrow_mut().clone(); let memory_curr_line = props.memory_curr_line.borrow_mut(); - let on_check = Callback::from(move |args: (MouseEvent, i32)| { + let on_check = Callback::from(move |args: (MouseEvent, i64)| { let (e, address) = args; let target = e.target(); let input = target.unwrap().unchecked_into::(); @@ -41,7 +42,7 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html { }); - let on_address_click = Callback::from(move |args: (MouseEvent, i32)| { + let on_address_click = Callback::from(move |args: (MouseEvent, i64)| { let (e, address) = args; let target = e.target(); let input = target.unwrap().unchecked_into::(); @@ -52,7 +53,7 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html { }); - let on_assembled_click = Callback::from(move |args: (MouseEvent, i32)| { + let on_assembled_click = Callback::from(move |args: (MouseEvent, i64)| { let (e, line_number) = args; let target = e.target(); let input = target.unwrap().unchecked_into::(); @@ -80,9 +81,13 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html { let on_address_click = Callback::clone(&on_address_click); let on_assembled_click = Callback::clone(&on_assembled_click); address += 4; + let mut conditional_class = ""; + if props.pc as i64 == address { + conditional_class = "executing"; + } html!{ - +
@@ -147,7 +152,7 @@ pub fn DataSegment(props: &DataSegmentProps) -> Html { {"Source"} { - if program_info.instructions.len() > 0 { + if program_info.instructions.len() > 0 && binary.len() > 0 { let mut address = program_info.instructions.len() * 4 - 4; program_info.data.iter().enumerate().map(|(index, data)| { let recreated_string = data.recreate_string(); diff --git a/static/styles/main.css b/static/styles/main.css index 63e38c40d..b4dea1afb 100644 --- a/static/styles/main.css +++ b/static/styles/main.css @@ -79,6 +79,10 @@ body { } } + .executing { + color:rgb(49, 212, 144); + } + .assembled-string { color: #006591; cursor: pointer; From c243534e111ee64f4f4056322ab453a6dbb4970a Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Fri, 19 Jan 2024 16:52:09 -0500 Subject: [PATCH 013/355] Add documentation --- src/{emulation_core => }/agent.rs | 6 ++++++ .../datapath_communicator.rs | 13 ++++++++++++- src/bin/main.rs | 9 +++++---- src/bin/worker.rs | 2 +- src/emulation_core.rs | 2 -- src/lib.rs | 1 + 6 files changed, 25 insertions(+), 8 deletions(-) rename src/{emulation_core => }/agent.rs (54%) rename src/{emulation_core => agent}/datapath_communicator.rs (67%) diff --git a/src/emulation_core/agent.rs b/src/agent.rs similarity index 54% rename from src/emulation_core/agent.rs rename to src/agent.rs index eb89d7526..5a674cec3 100644 --- a/src/emulation_core/agent.rs +++ b/src/agent.rs @@ -1,7 +1,13 @@ +//! The agent responsible for running the emulator core on the worker thread and communication functionalities. + use futures::{SinkExt, StreamExt}; use gloo_console::log; use yew_agent::prelude::*; +pub mod datapath_communicator; + +/// The main logic for the emulation core agent. All code within this function runs on a worker thread as opposed to +/// the UI thread. #[reactor(EmulationCoreAgent)] pub async fn emulation_core_agent(mut scope: ReactorScope) { log!("Hello world!"); diff --git a/src/emulation_core/datapath_communicator.rs b/src/agent/datapath_communicator.rs similarity index 67% rename from src/emulation_core/datapath_communicator.rs rename to src/agent/datapath_communicator.rs index b90a0d9eb..abd87b247 100644 --- a/src/emulation_core/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -1,4 +1,4 @@ -use crate::emulation_core::agent::EmulationCoreAgent; +use crate::agent::EmulationCoreAgent; use futures::stream::{SplitSink, SplitStream}; use futures::FutureExt; use futures::SinkExt; @@ -9,12 +9,18 @@ use std::cell::RefCell; use yew::UseForceUpdateHandle; use yew_agent::reactor::ReactorBridge; +/// This struct provides an abstraction over all communication with the worker thread. Any commands to the worker +/// thread should be sent by calling a function on this struct. +/// +/// The DatapathCommunicator will also handle receiving information about the state of the emulation core and maintain +/// internal state that can be displayed by the UI. pub struct DatapathCommunicator { writer: RefCell, i32>>, reader: RefCell>>, } impl DatapathCommunicator { + /// Initialize the DatapathCommunicator using a bridge. pub fn new(bridge: ReactorBridge) -> DatapathCommunicator { let (write, read) = bridge.split(); DatapathCommunicator { @@ -23,6 +29,9 @@ impl DatapathCommunicator { } } + /// Listen for updates from the worker thread and update internal state accordingly. This function should be called + /// from the main app component. After updating internal state, the component this was called from will be force + /// updated. #[allow(clippy::await_holding_refcell_ref)] pub async fn listen_for_updates(&self, update_handle: UseForceUpdateHandle) { let mut reader = match self.reader.try_borrow_mut() { @@ -40,10 +49,12 @@ impl DatapathCommunicator { } } + /// Sends a test message to the worker thread. pub fn send_test_message(&self) { let mut writer = self.writer.borrow_mut(); writer .send(1) + // The .now_or_never() .expect("Send function did not immediately return, async logic needed.") .expect("Sending test message error") diff --git a/src/bin/main.rs b/src/bin/main.rs index 4971eacad..2c572e226 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -12,9 +12,9 @@ use monaco::{ yew::CodeEditor, }; use std::rc::Rc; -use swim::emulation_core::agent::EmulationCoreAgent; +use swim::agent::EmulationCoreAgent; +use swim::agent::datapath_communicator::DatapathCommunicator; use swim::emulation_core::datapath::Datapath; -use swim::emulation_core::datapath_communicator::DatapathCommunicator; use swim::emulation_core::mips::datapath::MipsDatapath; use swim::emulation_core::mips::datapath::Stage; use swim::parser::parser_assembler_main::parser; @@ -92,7 +92,8 @@ fn app(props: &AppProps) -> Html { // the ability to access and change its contents be mutable. let datapath = use_mut_ref(MipsDatapath::default); - // Start listening for messages from the communicator + // Start listening for messages from the communicator. This effectively links the worker thread to the main thread + // and will force updates whenever its internal state changes. { let trigger = use_force_update(); let communicator = props.communicator; @@ -103,7 +104,7 @@ fn app(props: &AppProps) -> Html { // This is where code is assembled and loaded into the emulation core's memory. let on_assemble_clicked = { - props.communicator.send_test_message(); + props.communicator.send_test_message(); // Test message, remove later. let text_model = Rc::clone(&text_model); let datapath = Rc::clone(&datapath); let parser_text_output = parser_text_output.clone(); diff --git a/src/bin/worker.rs b/src/bin/worker.rs index f02e1b997..587377ae1 100644 --- a/src/bin/worker.rs +++ b/src/bin/worker.rs @@ -1,4 +1,4 @@ -use swim::emulation_core::agent::EmulationCoreAgent; +use swim::agent::EmulationCoreAgent; use yew_agent::Registrable; fn main() { diff --git a/src/emulation_core.rs b/src/emulation_core.rs index 7fcb1c723..e62a37920 100644 --- a/src/emulation_core.rs +++ b/src/emulation_core.rs @@ -1,6 +1,4 @@ //! The emulation core for the project. -pub mod agent; pub mod datapath; -pub mod datapath_communicator; pub mod mips; diff --git a/src/lib.rs b/src/lib.rs index 52b5b61b7..1f34be2c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,3 +3,4 @@ pub mod parser; #[cfg(test)] pub mod tests; pub mod ui; +pub mod agent; From fe72999725fe9ae56c45bff352b71bed2ca4d3ff Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Fri, 19 Jan 2024 17:44:52 -0500 Subject: [PATCH 014/355] Fix update polling loop being called multiple times --- src/agent.rs | 6 +++++- src/agent/datapath_communicator.rs | 13 +++++++++++++ src/bin/main.rs | 21 ++++++++------------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index 5a674cec3..f74dda20b 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -11,9 +11,13 @@ pub mod datapath_communicator; #[reactor(EmulationCoreAgent)] pub async fn emulation_core_agent(mut scope: ReactorScope) { log!("Hello world!"); - scope.send(1).await.unwrap(); + let mut num = 1; + scope.send(num).await.unwrap(); loop { let msg = scope.next().await; log!("Got message: ", msg); + num += 1; + scope.send(num).await.unwrap(); + log!("Sent."); } } diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index abd87b247..49de5f3d9 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -19,6 +19,15 @@ pub struct DatapathCommunicator { reader: RefCell>>, } +// Check references for equality by memory address. +impl PartialEq for &'static DatapathCommunicator { + fn eq(&self, other: &Self) -> bool { + let self_ptr: *const DatapathCommunicator = *self; + let other_ptr: *const DatapathCommunicator = *other; + self_ptr == other_ptr + } +} + impl DatapathCommunicator { /// Initialize the DatapathCommunicator using a bridge. pub fn new(bridge: ReactorBridge) -> DatapathCommunicator { @@ -43,8 +52,12 @@ impl DatapathCommunicator { }; loop { + log!("Waiting..."); let update = reader.next().await; log!(format!("Got update {:?}", update)); + if let None = update { + return; + } update_handle.force_update(); } } diff --git a/src/bin/main.rs b/src/bin/main.rs index 2c572e226..a9961bc48 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,5 +1,6 @@ use gloo::{dialogs::alert, file::FileList}; use js_sys::Object; +use gloo_console::log; use monaco::{ api::TextModel, sys::{ @@ -33,19 +34,11 @@ use yew_hooks::prelude::*; // rename fib_model to text_model to have it work. const CONTENT: &str = include_str!("../../static/assembly_examples/fibonacci.asm"); -#[derive(Properties, Clone)] +#[derive(Properties, Clone, PartialEq)] struct AppProps { communicator: &'static DatapathCommunicator, } -impl PartialEq for AppProps { - fn eq(&self, other: &Self) -> bool { - let self_ptr: *const Self = self; - let other_ptr: *const Self = other; - self_ptr == other_ptr - } -} - #[function_component(App)] fn app(props: &AppProps) -> Html { // This contains the binary representation of "ori $s0, $zero, 12345", which @@ -96,15 +89,14 @@ fn app(props: &AppProps) -> Html { // and will force updates whenever its internal state changes. { let trigger = use_force_update(); - let communicator = props.communicator; - use_effect(move || { + use_effect_with_deps(move |communicator| { spawn_local(communicator.listen_for_updates(trigger)); - }); + }, props.communicator); } // This is where code is assembled and loaded into the emulation core's memory. let on_assemble_clicked = { - props.communicator.send_test_message(); // Test message, remove later. + let communicator = props.communicator; let text_model = Rc::clone(&text_model); let datapath = Rc::clone(&datapath); let parser_text_output = parser_text_output.clone(); @@ -115,6 +107,7 @@ fn app(props: &AppProps) -> Html { use_callback( move |_, text_model| { + communicator.send_test_message(); // Test message, remove later. let mut datapath = datapath.borrow_mut(); let text_model = text_model.borrow_mut(); @@ -182,6 +175,8 @@ fn app(props: &AppProps) -> Html { ) }; + log!("Re-rendered!"); + // This is where the code will get executed. If you execute further // than when the code ends, the program crashes. This is remedied via the // syscall instruction, which will halt the datapath. As you execute the From e3a5ab139de2ea38641f6bfc2ae2ca15b0586fae Mon Sep 17 00:00:00 2001 From: Cay Date: Fri, 19 Jan 2024 17:46:20 -0500 Subject: [PATCH 015/355] blep --- src/agent/datapath_communicator.rs | 4 ++-- src/bin/main.rs | 6 +++--- src/ui/assembled_view/component.rs | 7 +------ src/ui/regview/component.rs | 7 +++++-- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index abd87b247..a2f640790 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -50,10 +50,10 @@ impl DatapathCommunicator { } /// Sends a test message to the worker thread. - pub fn send_test_message(&self) { + pub fn send_test_message(&self, num: i64) { let mut writer = self.writer.borrow_mut(); writer - .send(1) + .send(num as i32) // The .now_or_never() .expect("Send function did not immediately return, async logic needed.") diff --git a/src/bin/main.rs b/src/bin/main.rs index 1bb8aab17..338779e61 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -188,7 +188,7 @@ fn app(props: &AppProps) -> Html { // This is where code is assembled and loaded into the emulation core's memory. let on_assemble_clicked = { - props.communicator.send_test_message(); // Test message, remove later. + // props.communicator.send_test_message(1); // Test message, remove later. let text_model = Rc::clone(&text_model); let memory_text_model = Rc::clone(&memory_text_model); let datapath = Rc::clone(&datapath); @@ -834,9 +834,9 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html { if *active_tab == EditorTabState::Editor { } else if *active_tab == EditorTabState::TextSegment { - + } else if *active_tab == EditorTabState::DataSegment { - + } } diff --git a/src/ui/assembled_view/component.rs b/src/ui/assembled_view/component.rs index 4a2409455..15759fa85 100644 --- a/src/ui/assembled_view/component.rs +++ b/src/ui/assembled_view/component.rs @@ -14,7 +14,6 @@ use crate::parser::parser_structs_and_enums::ProgramInfo; pub struct TextSegmentProps { pub program_info: ProgramInfo, pub lines_content: Rc>>, - pub memory_curr_line: Rc>, pub pc: u64 } #[derive(PartialEq, Properties)] @@ -22,14 +21,12 @@ pub struct DataSegmentProps { pub program_info: ProgramInfo, pub binary: Vec, pub lines_content: Rc>>, - pub memory_curr_line: Rc> } #[function_component] pub fn TextSegment(props: &TextSegmentProps) -> Html { let program_info = &props.program_info; let lines_content = props.lines_content.borrow_mut().clone(); - let memory_curr_line = props.memory_curr_line.borrow_mut(); let on_check = Callback::from(move |args: (MouseEvent, i64)| { let (e, address) = args; @@ -49,7 +46,7 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html { debug!("Go to address {:08x}", address); debug!("Go to line {:?}", (address / 4) as f64); - // *memory_curr_line = (address / 4) as f64; + // memory_curr_line.set((address / 4) as f64); }); @@ -120,7 +117,6 @@ pub fn DataSegment(props: &DataSegmentProps) -> Html { let program_info = &props.program_info; let binary = &props.binary; let lines_content = props.lines_content.borrow_mut().clone(); - let memory_curr_line = props.memory_curr_line.borrow_mut(); let on_address_click = Callback::from(move |args: (MouseEvent, usize)| { let (e, address) = args; @@ -129,7 +125,6 @@ pub fn DataSegment(props: &DataSegmentProps) -> Html { debug!("Go to address {:08x}", address); debug!("Go to line {:?}", (address / 4) as f64); - // *memory_curr_line = (address / 4) as f64; }); diff --git a/src/ui/regview/component.rs b/src/ui/regview/component.rs index a42f7b778..b34c2e447 100644 --- a/src/ui/regview/component.rs +++ b/src/ui/regview/component.rs @@ -1,3 +1,4 @@ +use crate::agent::datapath_communicator::DatapathCommunicator; use crate::emulation_core::mips::datapath::MipsDatapath; use crate::emulation_core::mips::memory::CAPACITY_BYTES; use crate::emulation_core::mips::registers::{GpRegisterType, GpRegisters}; @@ -16,13 +17,14 @@ pub struct Regviewprops { pub gp: GpRegisters, pub fp: [u64; 32], pub datapath: Rc>, - pub pc_limit: usize + pub pc_limit: usize, + // pub communicator: &'static DatapathCommunicator } #[derive(PartialEq, Properties)] pub struct Regrowprops { pub gp: GpRegisters, pub fp: [u64; 32], - pub on_input: Callback<(InputEvent, GpRegisterType)>, + pub on_input: Callback<(InputEvent, GpRegisterType)> } #[derive(PartialEq, Properties)] pub struct Viewswitch { @@ -246,6 +248,7 @@ pub fn regview(props: &Regviewprops) -> Html { } datapath.registers.pc = val as u64; + // props.communicator.send_test_message(val); } // check if pc is more than memory capacity // or if it's not word aligned From 11809c601341213e5d15269409bb488f04619a52 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Fri, 19 Jan 2024 18:14:02 -0500 Subject: [PATCH 016/355] Remove unnecessary lifetime parameter --- src/agent/datapath_communicator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index 49de5f3d9..aca3d1e3b 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -20,7 +20,7 @@ pub struct DatapathCommunicator { } // Check references for equality by memory address. -impl PartialEq for &'static DatapathCommunicator { +impl PartialEq for &DatapathCommunicator { fn eq(&self, other: &Self) -> bool { let self_ptr: *const DatapathCommunicator = *self; let other_ptr: *const DatapathCommunicator = *other; From 29c96def75f91caf120e7d64625afb096cf261ce Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Fri, 26 Jan 2024 17:47:42 -0500 Subject: [PATCH 017/355] Fix formatting and Clippy warnings --- src/agent/datapath_communicator.rs | 2 +- src/bin/main.rs | 16 ++++++++++------ src/lib.rs | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index aca3d1e3b..bdd839e53 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -55,7 +55,7 @@ impl DatapathCommunicator { log!("Waiting..."); let update = reader.next().await; log!(format!("Got update {:?}", update)); - if let None = update { + if update.is_none() { return; } update_handle.force_update(); diff --git a/src/bin/main.rs b/src/bin/main.rs index a9961bc48..e0fbc285b 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,6 +1,6 @@ use gloo::{dialogs::alert, file::FileList}; -use js_sys::Object; use gloo_console::log; +use js_sys::Object; use monaco::{ api::TextModel, sys::{ @@ -13,8 +13,8 @@ use monaco::{ yew::CodeEditor, }; use std::rc::Rc; -use swim::agent::EmulationCoreAgent; use swim::agent::datapath_communicator::DatapathCommunicator; +use swim::agent::EmulationCoreAgent; use swim::emulation_core::datapath::Datapath; use swim::emulation_core::mips::datapath::MipsDatapath; use swim::emulation_core::mips::datapath::Stage; @@ -89,9 +89,12 @@ fn app(props: &AppProps) -> Html { // and will force updates whenever its internal state changes. { let trigger = use_force_update(); - use_effect_with_deps(move |communicator| { - spawn_local(communicator.listen_for_updates(trigger)); - }, props.communicator); + use_effect_with_deps( + move |communicator| { + spawn_local(communicator.listen_for_updates(trigger)); + }, + props.communicator, + ); } // This is where code is assembled and loaded into the emulation core's memory. @@ -555,7 +558,8 @@ pub fn on_upload_file_clicked() { fn main() { // Initialize and leak the communicator to ensure that the thread spawns immediately and the bridge to it lives - // for the remainder of the program. + // for the remainder of the program. We can use the communicator exclusively through immutable references for the + // rest of the program. let bridge = EmulationCoreAgent::spawner().spawn("./worker.js"); let communicator = Box::new(DatapathCommunicator::new(bridge)); yew::Renderer::::with_props(AppProps { diff --git a/src/lib.rs b/src/lib.rs index 1f34be2c9..825d617f2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ +pub mod agent; pub mod emulation_core; pub mod parser; #[cfg(test)] pub mod tests; pub mod ui; -pub mod agent; From 90c1f8b82e40814eae05bcd1dbc4d48150d9a8f8 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Mon, 29 Jan 2024 16:51:00 -0500 Subject: [PATCH 018/355] Add new functions for generic datapath --- src/emulation_core/datapath.rs | 35 +++++++++++++++++++++++++++++ src/emulation_core/mips/datapath.rs | 14 ++++++++++++ 2 files changed, 49 insertions(+) diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index b3d1c8deb..0484ffc4a 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -27,6 +27,11 @@ pub trait Datapath { /// or its own interface at will. type MemoryType; + /// This enum describes all possible stages in the datapath. This is + /// used primarily for the visual datapath view. Must be convertable + /// into a string for highlighting purposes. + type StageEnum: Into; + /// Execute a single instruction based on the current state of the /// datapath. Should the datapath support stages, if the datapath is /// midway through a stage, the current instruction will be finished @@ -45,15 +50,45 @@ pub trait Datapath { /// registers should be listed within [`Self::RegisterEnum`]. fn get_register_by_enum(&self, register: Self::RegisterEnum) -> Self::RegisterData; + /// Sets the data in the register indicated by the provided enum. + fn set_register_by_enum(&self, _register: Self::RegisterEnum, _data: Self::RegisterData) { + todo!() + } + + /// Loads the instructions from the provided array into an emulation core's + /// memory. This will also clear the memory of the emulation core and reset + /// the core's program counter. + fn load_instructions(&mut self, instructions: &[Self::MemoryType]) { + self.reset(); + self.set_memory(0, instructions); + } + /// Retrieve all memory as-is. fn get_memory(&self) -> &Self::MemoryType; + fn set_memory(&mut self, _ptr: usize, _data: &[Self::MemoryType]) { + todo!() + } + /// Returns if the datapath is in a "halted" or "stopped" state. This may /// be true in the case where an error had occurred previously. fn is_halted(&self) -> bool; /// Restore the datapath to its default state. fn reset(&mut self); + + // Information retrieval + + /// Get the program counter from an emulation core, regardless of what + /// it's called. + fn get_pc(&self) -> Self::RegisterData { + todo!() + } + + /// Gets the current stage the emulator core is in. + fn get_stage(&self) -> Self::StageEnum { + todo!() + } } /// A datapath that supports a visual diagram component. diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index 16ac9c9d0..072ec2fb7 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -185,6 +185,18 @@ impl Stage { } } +impl From for String { + fn from(val: Stage) -> String { + String::from(match val { + Stage::InstructionFetch => "writeback", + Stage::InstructionDecode => "instruction_fetch", + Stage::Execute => "instruction_decode", + Stage::Memory => "execute", + Stage::WriteBack => "memory", + }) + } +} + impl Default for MipsDatapath { fn default() -> Self { let mut datapath = MipsDatapath { @@ -212,6 +224,8 @@ impl Datapath for MipsDatapath { type RegisterEnum = super::registers::GpRegisterType; type MemoryType = Memory; + type StageEnum = Stage; + fn execute_instruction(&mut self) { loop { // Stop early if the datapath has halted. From 164854ebbf7201117d71ebd96c22a15e533645e8 Mon Sep 17 00:00:00 2001 From: Geetis <59862178+Geetis@users.noreply.github.com> Date: Mon, 29 Jan 2024 18:46:55 -0500 Subject: [PATCH 019/355] Initial parser work, almost all RV32I instructions --- src/main.rs | 5 +- src/parser/assembling.rs | 361 ++++++- src/parser/parser_assembler_main.rs | 1139 ++++++++++++++++++++++- src/parser/parser_structs_and_enums.rs | 306 +++++- static/assembly_examples/riscv_test.asm | 4 + 5 files changed, 1753 insertions(+), 62 deletions(-) create mode 100644 static/assembly_examples/riscv_test.asm diff --git a/src/main.rs b/src/main.rs index a59835a88..3f34cccaa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -31,10 +31,13 @@ use yew::prelude::*; use yew::{html, Html, Properties}; use yew_hooks::prelude::*; +//use gloo_console::log; + // To load in the Fibonacci example, uncomment the CONTENT and fib_model lines // and comment the code, language, and text_model lines. IMPORTANT: // rename fib_model to text_model to have it work. -const CONTENT: &str = include_str!("../static/assembly_examples/fibonacci.asm"); +// const CONTENT: &str = include_str!("../static/assembly_examples/fibonacci.asm"); +const CONTENT: &str = include_str!("../static/assembly_examples/riscv_test.asm"); #[function_component(App)] fn app() -> Html { diff --git a/src/parser/assembling.rs b/src/parser/assembling.rs index 38f7d3c1d..3ecef308d 100644 --- a/src/parser/assembling.rs +++ b/src/parser/assembling.rs @@ -6,7 +6,7 @@ use crate::parser::parser_structs_and_enums::ErrorType::{ NonIntImmediate, UnrecognizedDataType, UnrecognizedFPRegister, UnrecognizedGPRegister, }; use crate::parser::parser_structs_and_enums::OperandType::{ - Immediate, LabelAbsolute, LabelRelative, MemoryAddress, RegisterFP, RegisterGP, + Immediate, UpperImmediate, LabelAbsolute, LabelRelative, MemoryAddress, RegisterFP, RegisterGP, ShiftAmount }; use crate::parser::parser_structs_and_enums::RegisterType::{FloatingPoint, GeneralPurpose}; use crate::parser::parser_structs_and_enums::TokenType::{ @@ -17,6 +17,10 @@ use crate::parser::parser_structs_and_enums::{ }; use std::collections::HashMap; +use super::parser_structs_and_enums::{RISCV_GP_REGISTERS, RISCV_FP_REGISTERS}; + +use gloo_console::log; + ///This function takes an instruction whose operands it is supposed to read, the order of expected operand types and then ///the order these operands should be concatenated onto the binary representation of the string ///the function returns the instruction it was given with any errors and the binary of the operands added on. @@ -87,6 +91,10 @@ pub fn read_operands( instruction.errors.push(immediate_results.1.unwrap()); } } + UpperImmediate => + { + // Don't need to handle for MIPS + } MemoryAddress => { instruction.operands[i].token_type = TokenType::MemoryAddress; @@ -152,7 +160,7 @@ pub fn read_operands( instruction.errors.push(label_relative_results.1.unwrap()); } } - OperandType::ShiftAmount => { + ShiftAmount => { instruction.operands[i].token_type = TokenType::Immediate; bit_lengths.push(5); @@ -181,6 +189,193 @@ pub fn read_operands( instruction } +pub fn read_operands_riscv( + instruction: &mut Instruction, + expected_operands: Vec, + concat_order: Vec, + labels_option: Option>, + funct3: Option +) -> &mut Instruction { + //if the number of operands in the instruction does not match the expected number, there is an error + if instruction.operands.len() != expected_operands.len() { + instruction.errors.push(Error { + error_name: IncorrectNumberOfOperands, + token_causing_error: instruction.operator.token_name.clone(), + start_end_columns: instruction.operator.start_end_columns, + message: "".to_string(), + }); + return instruction; + } + + let labels = if let Some(..) = labels_option { + labels_option.unwrap() + } else { + HashMap::new() + }; + + //operands aren't represented in the binary in the order they're read so the vec allows us to concatenate them in the proper order after they're all read. + let mut binary_representation: Vec = Vec::new(); + let mut bit_lengths: Vec = Vec::new(); + //goes through once for each expected operand + for (i, operand_type) in expected_operands.iter().enumerate() { + //break if there are no more operands to read. Should only occur if IncorrectNumberOfOperands occurs above + if i >= instruction.operands.len() { + break; + }; + + //match case calls the proper functions based on the expected operand type. The data returned from these functions is always + //the binary of the read operand and the option for any errors encountered while reading the operand. If there were no errors, + //the binary is pushed to the string representations vec. Otherwise, the errors are pushed to the instruction.errors vec. + match operand_type { + RegisterGP => { + log!("RegisterGP"); + instruction.operands[i].token_type = TokenType::RegisterGP; + bit_lengths.push(5); + + let register_results = read_register_riscv( + &instruction.operands[i].token_name, + instruction.operands[i].start_end_columns, + GeneralPurpose, + ); + + log!("Register Results: ", format!("{:?}", register_results)); + + // Vector holding all register arguments + binary_representation.push(register_results.0 as u32); + if register_results.1.is_some() { + instruction.errors.push(register_results.1.unwrap()); + } + } + Immediate => { + instruction.operands[i].token_type = TokenType::Immediate; + bit_lengths.push(12); // 12 bits to represent immediates + + let immediate_results = read_immediate( + &instruction.operands[i].token_name, + instruction.operands[i].start_end_columns, + 12, + ); + + binary_representation.push(immediate_results.0); + if immediate_results.1.is_some() { + instruction.errors.push(immediate_results.1.unwrap()); + } + } + UpperImmediate => // Can be used to represent offsets for J-type instructions + { + log!("Upper Immediate"); + instruction.operands[i].token_type = TokenType::Immediate; + bit_lengths.push(20); // 20 bits to represent upper immediates + + let immediate_results = read_immediate( + &instruction.operands[i].token_name, + instruction.operands[i].start_end_columns, + 20, + ); + + binary_representation.push(immediate_results.0); + if immediate_results.1.is_some() { + instruction.errors.push(immediate_results.1.unwrap()); + } + } + MemoryAddress => { + instruction.operands[i].token_type = TokenType::MemoryAddress; + + bit_lengths.push(12); + bit_lengths.push(5); + //memory address works a bit differently because it really amounts to two operands: the offset and base + //meaning there are two values to push and the possibility of errors on both operands + let memory_results = read_memory_address_riscv( + &instruction.operands[i].token_name, + instruction.operands[i].start_end_columns, + ); + + binary_representation.push(memory_results.0); + binary_representation.push(memory_results.1); + if memory_results.2.is_some() { + for error in memory_results.2.unwrap() { + instruction.errors.push(error); + } + } + } + RegisterFP => { + instruction.operands[i].token_type = TokenType::RegisterFP; + + bit_lengths.push(5); + let register_results = read_register( + &instruction.operands[i].token_name, + instruction.operands[i].start_end_columns, + FloatingPoint, + ); + + binary_representation.push(register_results.0 as u32); + if register_results.1.is_some() { + instruction.errors.push(register_results.1.unwrap()); + } + } + LabelAbsolute => { + instruction.operands[i].token_type = TokenType::LabelOperand; + + bit_lengths.push(26); + let label_absolute_results = read_label_absolute( + &instruction.operands[i].token_name, + instruction.operands[i].start_end_columns, + labels.clone(), + ); + + binary_representation.push(label_absolute_results.0); + if label_absolute_results.1.is_some() { + instruction.errors.push(label_absolute_results.1.unwrap()); + } + } + LabelRelative => { + instruction.operands[i].token_type = TokenType::LabelOperand; + + bit_lengths.push(16); + let label_relative_results = read_label_relative( + &instruction.operands[i].token_name, + instruction.operands[i].start_end_columns, + instruction.instruction_number, + labels.clone(), + ); + binary_representation.push(label_relative_results.0); + if label_relative_results.1.is_some() { + instruction.errors.push(label_relative_results.1.unwrap()); + } + } + ShiftAmount => { + instruction.operands[i].token_type = TokenType::Immediate; + bit_lengths.push(7); + + let immediate_results = read_immediate( + &instruction.operands[i].token_name, + instruction.operands[i].start_end_columns, + 7, + ); + + binary_representation.push(immediate_results.0); + if immediate_results.1.is_some() { + instruction.errors.push(immediate_results.1.unwrap()); + } + } + } + } + //once all operands are read, we can append them onto the instruction + for (index, element) in concat_order.iter().rev().enumerate() { + instruction.binary = append_binary( + instruction.binary, + binary_representation[element - 1], + bit_lengths[element - 1], + ); + if index == 1 && funct3.is_some() // Set funct3 value before the final argument + { + instruction.binary = append_binary(instruction.binary, funct3.unwrap_or(0), 3) // Shift amount may need to be adjusted using function argument + } + } + + instruction +} + ///Returns distance to a labeled instruction relative to the instruction after the current instruction. /// The value represents instruction numbers NOT bytes. pub fn read_label_relative( @@ -300,6 +495,78 @@ pub fn read_memory_address( (immediate_results.0, register_results.0 as u32, None) } +///Takes in a memory address and token number and returns the binary for the offset value, base register value, and any errors. +/// If the string given matches a label, that address is returned instead +pub fn read_memory_address_riscv( + orig_string: &str, + start_end_columns: (usize, usize), +) -> (u32, u32, Option>) { + //the indices of the open and close parentheses are checked. + //If either are missing or they are in the wrong order, an error is returned + let open_index = orig_string.find('('); + let close_index = orig_string.find(')'); + if close_index.is_none() || open_index.is_none() || close_index < open_index { + return ( + 0, + 0, + Some(vec![Error { + error_name: InvalidMemorySyntax, + token_causing_error: orig_string.to_string(), + start_end_columns, + message: "".to_string(), + }]), + ); + } + + //splits the string at the index of the open parenthesis to isolate the base and offset + let (offset_str, base_str) = orig_string.split_at(open_index.unwrap()); + + let mut base: Vec = base_str.chars().collect(); + + //returns an error if there are any characters after the close parenthesis + if base[base.len() - 1] != ')' { + return ( + 0, + 0, + Some(vec![Error { + error_name: InvalidMemorySyntax, + token_causing_error: orig_string.to_string(), + start_end_columns, + message: "".to_string(), + }]), + ); + } + + //removes the open and close parentheses characters and then turns it into a string + base = base[1..base.len() - 1].to_owned(); + let mut cleaned_base: String = base.into_iter().collect(); + cleaned_base = cleaned_base.to_string(); + + //offset is an immediate while base is a register so the read functions for those operands + //will confirm they are properly formatted + let immediate_results = read_immediate(offset_str, start_end_columns, 16); + let register_results = read_register_riscv(&cleaned_base, start_end_columns, GeneralPurpose); + + log!("Immediate: ", format!("{:?}", immediate_results)); + log!("Register: ", format!("{:?}", register_results)); + + //any errors found in the read_immediate or read_register functions are collected into a vec + //if there were any errors, those are returned + let mut return_errors: Vec = Vec::new(); + if immediate_results.1.is_some() { + return_errors.push(immediate_results.1.unwrap()) + } + if register_results.1.is_some() { + return_errors.push(register_results.1.unwrap()); + } + if !return_errors.is_empty() { + return (0, 0, Some(return_errors)); + } + + //if the function reaches here and hasn't already returned, there aren't any errors + (immediate_results.0, register_results.0 as u32, None) +} + ///read_register takes the string of the register name, the token number the register is from the corresponding instruction ///and the expected register type. It calls the corresponding functions holding the match cases for the different register types. pub fn read_register( @@ -312,7 +579,7 @@ pub fn read_register( let general_result = match_gp_register(register); if let Some(..) = general_result { (general_result.unwrap(), None) - } else if match_fp_register(register).is_some() { + } else if match_fp_register(register).is_some() { // Creates Error if supplied a fp register for gp ( 0, Some(Error { @@ -362,6 +629,68 @@ pub fn read_register( } } +///read_register takes the string of the register name, the token number the register is from the corresponding instruction +///and the expected register type. It calls the corresponding functions holding the match cases for the different register types. +pub fn read_register_riscv( + register: &str, + start_end_columns: (usize, usize), + register_type: RegisterType, +) -> (u8, Option) { + if register_type == GeneralPurpose { + //this section is for matching general purpose registers + let general_result = match_gp_register_riscv(register); + if let Some(..) = general_result { + (general_result.unwrap(), None) + } else if match_fp_register_riscv(register).is_some() { // Creates Error if supplied a fp register for gp + ( + 0, + Some(Error { + error_name: IncorrectRegisterTypeFP, + token_causing_error: register.to_string(), + start_end_columns, + message: "".to_string(), + }), + ) + } else { + ( + 0, + Some(Error { + error_name: UnrecognizedGPRegister, + token_causing_error: register.to_string(), + start_end_columns, + message: "".to_string(), + }), + ) + } + } else { + //this section is for matching floating point registers + let floating_result = match_fp_register_riscv(register); + if let Some(..) = floating_result { + (floating_result.unwrap(), None) + } else if match_gp_register(register).is_some() { + ( + 0, + Some(Error { + error_name: IncorrectRegisterTypeGP, + token_causing_error: register.to_string(), + start_end_columns, + message: "".to_string(), + }), + ) + } else { + ( + 0, + Some(Error { + error_name: UnrecognizedFPRegister, + token_causing_error: register.to_string(), + start_end_columns, + message: "".to_string(), + }), + ) + } + } +} + ///This function takes a register string as an argument and returns the string of the binary of the matching ///general register or none if there is not one that matches. pub fn match_gp_register(given_string: &str) -> Option { @@ -375,6 +704,19 @@ pub fn match_gp_register(given_string: &str) -> Option { None } +///This function takes a register string as an argument and returns the string of the binary of the matching +///general register or none if there is not one that matches. +pub fn match_gp_register_riscv(given_string: &str) -> Option { + for register in RISCV_GP_REGISTERS { + for name in register.names { + if &given_string.to_lowercase().as_str() == name { + return Some(register.binary); + } + } + } + None +} + ///This function takes a register string as an argument and returns the string of the binary of the matching ///floating point register or none if there is not one that matches. pub fn match_fp_register(given_string: &str) -> Option { @@ -386,6 +728,19 @@ pub fn match_fp_register(given_string: &str) -> Option { None } +///This function takes a register string as an argument and returns the string of the binary of the matching +///floating point register or none if there is not one that matches. +pub fn match_fp_register_riscv(given_string: &str) -> Option { + for register in RISCV_FP_REGISTERS { + for name in register.names { + if &given_string.to_lowercase().as_str() == name { + return Some(register.binary); + } + } + } + None +} + ///This function takes a string representation of an immediate value and the number of bits available to represent it /// and attempts to translate it to an actual integer. If the value cannot be cast to int or is too big to be represented /// by the available bits, an error is returned. diff --git a/src/parser/parser_assembler_main.rs b/src/parser/parser_assembler_main.rs index 482468b89..0b6db0a39 100644 --- a/src/parser/parser_assembler_main.rs +++ b/src/parser/parser_assembler_main.rs @@ -1,4 +1,4 @@ -use crate::parser::assembling::{assemble_data_binary, read_operands}; +use crate::parser::assembling::{assemble_data_binary, read_operands, read_operands_riscv}; use crate::parser::parser_structs_and_enums::ErrorType::*; use crate::parser::parser_structs_and_enums::OperandType::*; use crate::parser::parser_structs_and_enums::ProgramInfo; @@ -9,64 +9,132 @@ use crate::parser::pseudo_instruction_parsing::{ }; use std::collections::HashMap; +use gloo_console::log; + ///Parser is the starting function of the parser / assembler process. It takes a string representation of a MIPS /// program and builds the binary of the instructions while cataloging any errors that are found. pub fn parser(file_string: String) -> (ProgramInfo, Vec) { - let mut program_info = ProgramInfo { - monaco_line_info: tokenize_program(file_string), - ..Default::default() - }; - (program_info.instructions, program_info.data) = - separate_data_and_text(&mut program_info.monaco_line_info); - - expand_pseudo_instructions_and_assign_instruction_numbers( - &mut program_info.instructions, - &program_info.data, - &mut program_info.monaco_line_info, - ); - - let vec_of_data = assemble_data_binary(&mut program_info.data); - - let labels: HashMap = - create_label_map(&mut program_info.instructions, &mut program_info.data); - - complete_lw_sw_pseudo_instructions( - &mut program_info.instructions, - &labels, - &mut program_info.monaco_line_info, - ); - - read_instructions( - &mut program_info.instructions, - &labels, - &mut program_info.monaco_line_info, - ); - - program_info.console_out_post_assembly = suggest_error_corrections( - &mut program_info.instructions, - &mut program_info.data, - &labels, - &mut program_info.monaco_line_info, - ); - - let binary = create_binary_vec(program_info.instructions.clone(), vec_of_data); - - for entry in &program_info.monaco_line_info { - program_info - .updated_monaco_string - .push_str(&format!("{}\n", entry.updated_monaco_string)); - } + let arch = Architecture::RISCV; // Force RISC-V for testing purposes + + if arch == Architecture::MIPS + { + let mut program_info = ProgramInfo { + monaco_line_info: tokenize_program(file_string), + ..Default::default() + }; + + (program_info.instructions, program_info.data) = + separate_data_and_text(&mut program_info.monaco_line_info); + + expand_pseudo_instructions_and_assign_instruction_numbers( + &mut program_info.instructions, + &program_info.data, + &mut program_info.monaco_line_info, + ); + + let vec_of_data = assemble_data_binary(&mut program_info.data); + + let labels: HashMap = + create_label_map(&mut program_info.instructions, &mut program_info.data); + + complete_lw_sw_pseudo_instructions( + &mut program_info.instructions, + &labels, + &mut program_info.monaco_line_info, + ); + + read_instructions( + &mut program_info.instructions, + &labels, + &mut program_info.monaco_line_info, + ); + + program_info.console_out_post_assembly = suggest_error_corrections( + &mut program_info.instructions, + &mut program_info.data, + &labels, + &mut program_info.monaco_line_info, + ); + + let binary = create_binary_vec(program_info.instructions.clone(), vec_of_data); + + for entry in &program_info.monaco_line_info { + program_info + .updated_monaco_string + .push_str(&format!("{}\n", entry.updated_monaco_string)); + } - for instruction in program_info.instructions.clone() { - program_info - .address_to_line_number - .push(instruction.line_number); + for instruction in program_info.instructions.clone() { + program_info + .address_to_line_number + .push(instruction.line_number); + } + + program_info.pc_starting_point = determine_pc_starting_point(labels); + + (program_info.clone(), binary) } + else + { + let mut program_info = ProgramInfo { + monaco_line_info: tokenize_program(file_string), + ..Default::default() + }; + + (program_info.instructions, program_info.data) = + separate_data_and_text(&mut program_info.monaco_line_info); + + // Implement a RISC-V version + /*expand_pseudo_instructions_and_assign_instruction_numbers( + &mut program_info.instructions, + &program_info.data, + &mut program_info.monaco_line_info, + );*/ + + let vec_of_data = assemble_data_binary(&mut program_info.data); + + let labels: HashMap = + create_label_map(&mut program_info.instructions, &mut program_info.data); + + // Implement a RISC-V version + /*complete_lw_sw_pseudo_instructions( + &mut program_info.instructions, + &labels, + &mut program_info.monaco_line_info, + );*/ + + read_instructions_riscv( + &mut program_info.instructions, + &labels, + &mut program_info.monaco_line_info, + ); + + program_info.console_out_post_assembly = suggest_error_corrections( + &mut program_info.instructions, + &mut program_info.data, + &labels, + &mut program_info.monaco_line_info, + ); + + let binary = create_binary_vec(program_info.instructions.clone(), vec_of_data); + + for entry in &program_info.monaco_line_info { + program_info + .updated_monaco_string + .push_str(&format!("{}\n", entry.updated_monaco_string)); + } - program_info.pc_starting_point = determine_pc_starting_point(labels); + for instruction in program_info.instructions.clone() { + program_info + .address_to_line_number + .push(instruction.line_number); + } + + program_info.pc_starting_point = determine_pc_starting_point(labels); - (program_info.clone(), binary) + (program_info.clone(), binary) + } } ///Takes the vector of instructions and assembles the binary for them. @@ -1477,9 +1545,978 @@ pub fn read_instructions( } } } + //print_instruction_contents(instruction.clone()); } } +pub fn read_instructions_riscv( + instruction_list: &mut [Instruction], + _labels: &HashMap, + monaco_line_info: &mut [MonacoLineInfo], +) +{ + for mut instruction in &mut instruction_list.iter_mut() + { + match &*instruction.operator.token_name.to_lowercase() + { + "add" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000000, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b000) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0110011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "add rd, rs1, rs2".to_string(), + description: "Adds the registers rs1 and rs2 and stores the result in rd.\n\nArithmetic overflow is ignored and the result is simply the low XLEN bits of the result.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "sub" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0100000, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b000) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0110011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "sub rd, rs1, rs2".to_string(), + description: "Subs the register rs2 from rs1 and stores the result in rd.\n\nArithmetic overflow is ignored and the result is simply the low XLEN bits of the result.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "sll" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000000, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b001) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0110011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "sll rd, rs1, rs2".to_string(), + description: "Performs logical left shift on the value in register rs1 by the shift amount held in the lower 5 bits of register rs2.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "slt" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000000, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b010) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0110011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "slt rd, rs1, rs2".to_string(), + description: "Place the value 1 in register rd if register rs1 is less than register rs2 when both are treated as signed numbers, else 0 is written to rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "sltu" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000000, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b011) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0110011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "sltu rd, rs1, rs2".to_string(), + description: "Place the value 1 in register rd if register rs1 is less than register rs2 when both are treated as unsigned numbers, else 0 is written to rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "xor" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000000, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b100) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0110011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "xor rd, rs1, rs2".to_string(), + description: "Performs bitwise XOR on registers rs1 and rs2 and place the result in rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "srl" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000000, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b101) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0110011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "srl rd, rs1, rs2".to_string(), + description: "Logical right shift on the value in register rs1 by the shift amount held in the lower 5 bits of register rs2.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "sra" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0100000, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b101) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0110011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "sra rd, rs1, rs2".to_string(), + description: "Performs arithmetic right shift on the value in register rs1 by the shift amount held in the lower 5 bits of register rs2.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "or" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000000, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b110) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0110011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "or rd, rs1, rs2".to_string(), + description: "Performs bitwise OR on registers rs1 and rs2 and place the result in rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "and" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000000, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b111) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0110011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "and rd, rs1, rs2".to_string(), + description: "Performs bitwise AND on registers rs1 and rs2 and place the result in rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "addi" => // This instruction requires the 12-bit immediate to be sign extended before moving to the emulator's register + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, Immediate], + vec![1, 2, 3], + None, + Some(0) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "addi rd, rs1, imm".to_string(), + description: "Adds the sign-extended 12-bit immediate to register rs1.\n\nArithmetic overflow is ignored and the result is simply the low XLEN bits of the result.\n\naddi rd, rs1, 0 is used to implement the MV rd, rs1 assembler pseudo-instruction.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "slti" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, Immediate], + vec![1, 2, 3], + None, + Some(0b010) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "slti rd, rs1, imm".to_string(), + description: "Place the value 1 in register rd if register rs1 is less than the signextended immediate when both are treated as signed numbers, else 0 is written to rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "sltiu" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, Immediate], + vec![1, 2, 3], + None, + Some(0b011) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "sltiu rd, rs1, imm".to_string(), + description: "Place the value 1 in register rd if register rs1 is less than the immediate when both are treated as unsigned numbers, else 0 is written to rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "xori" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, Immediate], + vec![1, 2, 3], + None, + Some(0b100) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "xori rd, rs1, imm".to_string(), + description: "Performs bitwise XOR on register rs1 and the sign-extended 12-bit immediate and place the result in rd.\n\nNote, “xori rd, rs1, -1” performs a bitwise logical inversion of register rs1(assembler pseudo-instruction NOT rd, rs)".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "ori" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, Immediate], + vec![1, 2, 3], + None, + Some(0b110) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "ori rd, rs1, imm".to_string(), + description: "Performs bitwise OR on register rs1 and the sign-extended 12-bit immediate and place the result in rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "andi" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, Immediate], + vec![1, 2, 3], + None, + Some(0b111) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "andi rd, rs1, imm".to_string(), + description: "Performs bitwise AND on register rs1 and the sign-extended 12-bit immediate and place the result in rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "slli" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b00000, 5); // Check if the next 2 bits are needed + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, ShiftAmount], + vec![1, 2, 3], + None, + Some(0b001) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "slli rd, rs1, shamt".to_string(), + description: "Performs logical left shift on the value in register rs1 by the shift amount held in the lower 5 bits of the immediate.\n\nIn RV64, bit-25 is used to shamt[5].".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "srli" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b00000, 5); // Check if the next 2 bits are needed + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, ShiftAmount], + vec![1, 2, 3], + None, + Some(0b101) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "srli rd, rs1, shamt".to_string(), + description: "Performs logical right shift on the value in register rs1 by the shift amount held in the lower 5 bits of the immediate.\n\nIn RV64, bit-25 is used to shamt[5].".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "srai" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b01000, 5); // Check if the next 2 bits are needed + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, ShiftAmount], + vec![1, 2, 3], + None, + Some(0b101) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "srai rd, rs1, shamt".to_string(), + description: "Performs arithmetic right shift on the value in register rs1 by the shift amount held in the lower 5 bits of the immediate.\n\nIn RV64, bit-25 is used to shamt[5].".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "lb" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, MemoryAddress], + vec![1, 3, 2], + None, + Some(0b000) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0000011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "lb rd, offset(rs1)".to_string(), + description: "Loads a 8-bit value from memory and sign-extends this to XLEN bits before storing it in register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "lh" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, MemoryAddress], + vec![1, 3, 2], + None, + Some(0b001) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0000011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "lh rd, offset(rs1)".to_string(), + description: "Loads a 16-bit value from memory and sign-extends this to XLEN bits before storing it in register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "lw" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, MemoryAddress], + vec![1, 3, 2], + None, + Some(0b010) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0000011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "lw rd, offset(rs1)".to_string(), + description: "Loads a 32-bit value from memory and sign-extends this to XLEN bits before storing it in register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "lbu" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, MemoryAddress], + vec![1, 3, 2], + None, + Some(0b100) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0000011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "lbu rd, offset(rs1)".to_string(), + description: "Loads a 8-bit value from memory and zero-extends this to XLEN bits before storing it in register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "lhu" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, MemoryAddress], + vec![1, 3, 2], + None, + Some(0b101) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0000011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "lhu rd, offset(rs1)".to_string(), + description: "Loads a 16-bit value from memory and zero-extends this to XLEN bits before storing it in register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "sb" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, MemoryAddress], + vec![1, 3, 2], + None, + Some(0b000) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0100011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Encoded as I-type, but needs reordering for S-type + instruction.binary = immediate_to_stored(instruction.binary); + log!("3. Reordered: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "sb rs2, offset(rs1)".to_string(), + description: "Store 8-bit, values from the low bits of register rs2 to memory.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "sh" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, MemoryAddress], + vec![1, 3, 2], + None, + Some(0b001) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0100011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Encoded as I-type, but needs reordering for S-type + instruction.binary = immediate_to_stored(instruction.binary); + log!("3. Reordered: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "sh rs2, offset(rs1)".to_string(), + description: "Store 16-bit, values from the low bits of register rs2 to memory.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "sw" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, MemoryAddress], + vec![1, 3, 2], + None, + Some(0b010) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0100011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Encoded as I-type, but needs reordering for S-type + instruction.binary = immediate_to_stored(instruction.binary); + log!("3. Reordered: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "sw rs2, offset(rs1)".to_string(), + description: "Store 32-bit, values from the low bits of register rs2 to memory.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "jal" => + { + log!("jal instruction"); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, UpperImmediate], + vec![1, 2], + None, + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1101111, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Reorder immediate + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "jal rd, offset".to_string(), + description: "Jump to address and place return address in rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "lui" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, UpperImmediate], + vec![1, 2], + None, + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0110111, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "lui rd, imm".to_string(), + description: "Build 32-bit constants and uses the U-type format. LUI places the U-immediate value in the top 20 bits of the destination register rd, filling in the lowest 12 bits with zeros.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "auipc" => + { + log!("auipc instruction"); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, UpperImmediate], + vec![1, 2], + None, + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0010111, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "auipc rd, imm".to_string(), + description: "Build pc-relative addresses and uses the U-type format.\n\nAUIPC forms a 32-bit offset from the 20-bit U-immediate, filling in the lowest 12 bits with zeros, adds this offset to the pc, then places the result in register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + _ => + { + if UNSUPPORTED_INSTRUCTIONS.contains(&&*instruction.operator.token_name) { + instruction.errors.push(Error { + error_name: UnsupportedInstruction, + token_causing_error: instruction.operator.token_name.to_string(), + start_end_columns: instruction.operator.start_end_columns, + message: "\n\n".to_string(), + }) + } else { + instruction.errors.push(Error { + error_name: UnrecognizedInstruction, + token_causing_error: instruction.operator.token_name.clone(), + start_end_columns: instruction.operator.start_end_columns, + message: "\n\n".to_string(), + }); + } + } + } + } +} + +// Reorder store instruction to the correct format +fn immediate_to_stored(mut bin: u32) -> u32 +{ + // Extract bits 24-20 from the first segment + let lower_imm = (bin >> 20) & 0b11111; + + // Extract bits 11-7 from the second segment + let rs2 = (bin >> 7) & 0b11111; + + log!("Bits to move (24-20): ", format!("{:05b}", lower_imm)); + log!("Bits to move (11-7): ", format!("{:05b}", rs2)); + + // Clear bits 24-20 and 11-7 + bin &= !((0b11111 << 20) | (0b11111 << 6)); + + log!("Cleared bits: ", format!("{:032b}", bin)); + + // Move bits 24-20 to positions 11-7 + let moved_imm = lower_imm << 7; + + // Move bits 11-7 to positions 24-20 + let moved_rs2 = rs2 << 20; + + + // Combine the manipulated bits + bin |= moved_imm | moved_rs2; + + bin +} + + ///This function takes two numbers and inserts the binary of the second at a given index in the binary of the first. ///All binary values at and past the insertion index of the original string will be moved to the end of the resultant string. ///Since binary is sign extended on the left to 32 bits, insertion index must be the index from the end of the string. diff --git a/src/parser/parser_structs_and_enums.rs b/src/parser/parser_structs_and_enums.rs index 163f264e4..efd05e8d4 100644 --- a/src/parser/parser_structs_and_enums.rs +++ b/src/parser/parser_structs_and_enums.rs @@ -3,6 +3,8 @@ use std::fmt; use std::fmt::Formatter; use std::string::ToString; +use gloo_console::log; + #[derive(Clone, Debug, Default, Eq, PartialEq)] ///Wrapper for all information gathered in the Parser/Assembler about the written program. pub struct ProgramInfo { @@ -15,6 +17,13 @@ pub struct ProgramInfo { pub pc_starting_point: usize, } +#[derive(Clone, Debug, Default, Eq, PartialEq)] +pub enum Architecture { + #[default] + MIPS, + RISCV +} + #[derive(Clone, Debug, Default, Eq, PartialEq)] ///This struct holds all the information we gather in the parser & assembler about a single line the user wrote pub struct MonacoLineInfo { @@ -228,6 +237,7 @@ pub enum OperandType { RegisterGP, RegisterFP, Immediate, + UpperImmediate, MemoryAddress, LabelAbsolute, LabelRelative, @@ -235,15 +245,18 @@ pub enum OperandType { } pub const SUPPORTED_INSTRUCTIONS: [&str; 64] = [ + // MIPS Instructions "add", "add.d", "add.s", "addi", "addiu", "addu", "and", "andi", "aui", "b", "bc1f", "bc1t", "beq", "bne", "c.eq.d", "c.eq.s", "c.le.d", "c.le.s", "c.lt.d", "c.lt.s", "c.nge.d", "c.nge.s", "c.ngt.d", "c.ngt.s", "dadd", "daddi", "daddiu", "daddu", "dahi", "dati", "ddiv", "ddivu", "div", "div.d", "div.s", "dmfc1", "dmtc1", "dmul", "dmulu", "dsub", "dsubu", "j", "jal", "jalr", "jr", "lui", "lw", "lwc1", "mfc1", "mtc1", "mul", "mul.d", "mul.s", "nop", "or", "ori", "sll", "slt", "sltu", "sub", "sub.d", "sub.s", "sw", "swc1", + // RISC-V Instructions ]; pub const UNSUPPORTED_INSTRUCTIONS: [&str; 408] = [ + // MIPS Instructions "abs.d", "abs.ps", "abs.s", @@ -652,6 +665,8 @@ pub const UNSUPPORTED_INSTRUCTIONS: [&str; 408] = [ "wrpgpr", "xor", "xori", + // RISC-V Instructions + ]; ///Contains every general purpose register's binary value and the various names they are recognized as. Any reference to gp registers throughout the parser/assembler should reference this array @@ -927,6 +942,281 @@ pub struct FPRegister<'a> { pub binary: u8, } +pub struct GPRegisterRiscv<'a> { + pub names: &'a [&'a str], + pub binary: u8, +} + +///Contains every general purpose register's binary value and the various names they are recognized as. Any reference to gp registers throughout the parser/assembler should reference this array +pub const RISCV_GP_REGISTERS: &[GPRegisterRiscv; 32] = &[ + GPRegisterRiscv { + names: &["x0", "zero"], + binary: 0b00000, + }, + GPRegisterRiscv { + names: &["x1", "ra"], + binary: 0b00001, + }, + GPRegisterRiscv { + names: &["x2", "sp"], + binary: 0b00010, + }, + GPRegisterRiscv { + names: &["x3", "gp"], + binary: 0b00011, + }, + GPRegisterRiscv { + names: &["x4", "tp"], + binary: 0b00100, + }, + GPRegisterRiscv { + names: &["x5", "t0"], + binary: 0b00101, + }, + GPRegisterRiscv { + names: &["x6", "t1"], + binary: 0b00110, + }, + GPRegisterRiscv { + names: &["x7", "t2"], + binary: 0b00111, + }, + GPRegisterRiscv { + names: &["x8", "s0", "fp"], + binary: 0b01000, + }, + GPRegisterRiscv { + names: &["x9", "s1"], + binary: 0b01001, + }, + GPRegisterRiscv { + names: &["x10", "a0"], + binary: 0b01010, + }, + GPRegisterRiscv { + names: &["x11", "a1"], + binary: 0b01011, + }, + GPRegisterRiscv { + names: &["x12", "a2"], + binary: 0b01100, + }, + GPRegisterRiscv { + names: &["x13", "a3"], + binary: 0b01101, + }, + GPRegisterRiscv { + names: &["x14", "a4"], + binary: 0b01110, + }, + GPRegisterRiscv { + names: &["x15", "a5"], + binary: 0b01111, + }, + GPRegisterRiscv { + names: &["x16", "a6"], + binary: 0b10000, + }, + GPRegisterRiscv { + names: &["x17", "a7"], + binary: 0b10001, + }, + GPRegisterRiscv { + names: &["x18", "s2"], + binary: 0b10010, + }, + GPRegisterRiscv { + names: &["x19", "s3"], + binary: 0b10011, + }, + GPRegisterRiscv { + names: &["x20", "s4"], + binary: 0b10100, + }, + GPRegisterRiscv { + names: &["x21", "s5"], + binary: 0b10101, + }, + GPRegisterRiscv { + names: &["x22", "s6"], + binary: 0b10110, + }, + GPRegisterRiscv { + names: &["x23", "s7"], + binary: 0b10111, + }, + GPRegisterRiscv { + names: &["x24", "s8"], + binary: 0b11000, + }, + GPRegisterRiscv { + names: &["x25", "s9"], + binary: 0b11001, + }, + GPRegisterRiscv { + names: &["x26", "s10"], + binary: 0b11010, + }, + GPRegisterRiscv { + names: &["x27", "s11"], + binary: 0b11011, + }, + GPRegisterRiscv { + names: &["x28", "t3"], + binary: 0b11100, + }, + GPRegisterRiscv { + names: &["x29", "t4"], + binary: 0b11101, + }, + GPRegisterRiscv { + names: &["x30", "t5"], + binary: 0b11110, + }, + GPRegisterRiscv { + names: &["x31", "t6"], + binary: 0b11111, + }, +]; + + +pub struct FPRegisterRiscv<'a> { + pub names: &'a [&'a str], + pub binary: u8, +} + +///Contains every floating point register name and binary value. Any reference to fp registers throughout the parser/assembler should reference this array +pub const RISCV_FP_REGISTERS: &[FPRegisterRiscv; 32] = &[ + FPRegisterRiscv { + names: &["f0", "ft0"], + binary: 0b00000, + }, + FPRegisterRiscv { + names: &["f1", "ft1"], + binary: 0b00001, + }, + FPRegisterRiscv { + names: &["f2", "ft2"], + binary: 0b00010, + }, + FPRegisterRiscv { + names: &["f3", "ft3"], + binary: 0b00011, + }, + FPRegisterRiscv { + names: &["f4", "ft4"], + binary: 0b00100, + }, + FPRegisterRiscv { + names: &["f5", "ft5"], + binary: 0b00101, + }, + FPRegisterRiscv { + names: &["f6", "ft6"], + binary: 0b00110, + }, + FPRegisterRiscv { + names: &["f7", "ft7"], + binary: 0b00111, + }, + FPRegisterRiscv { + names: &["f8", "fs0"], + binary: 0b01000, + }, + FPRegisterRiscv { + names: &["f9", "fs1"], + binary: 0b01001, + }, + FPRegisterRiscv { + names: &["f10", "fa0"], + binary: 0b01010, + }, + FPRegisterRiscv { + names: &["f11", "fa1"], + binary: 0b01011, + }, + FPRegisterRiscv { + names: &["f12", "fa2"], + binary: 0b01100, + }, + FPRegisterRiscv { + names: &["f13", "fa3"], + binary: 0b01101, + }, + FPRegisterRiscv { + names: &["f14", "fa4"], + binary: 0b01110, + }, + FPRegisterRiscv { + names: &["f15", "fa5"], + binary: 0b01111, + }, + FPRegisterRiscv { + names: &["f16", "fa6"], + binary: 0b10000, + }, + FPRegisterRiscv { + names: &["f17", "fa7"], + binary: 0b10001, + }, + FPRegisterRiscv { + names: &["f18", "fs2"], + binary: 0b10010, + }, + FPRegisterRiscv { + names: &["f19", "fs3"], + binary: 0b10011, + }, + FPRegisterRiscv { + names: &["f20", "fs4"], + binary: 0b10100, + }, + FPRegisterRiscv { + names: &["f21", "fs5"], + binary: 0b10101, + }, + FPRegisterRiscv { + names: &["f22", "fs6"], + binary: 0b10110, + }, + FPRegisterRiscv { + names: &["f23", "fs7"], + binary: 0b10111, + }, + FPRegisterRiscv { + names: &["f24", "fs8"], + binary: 0b11000, + }, + FPRegisterRiscv { + names: &["f25", "fs9"], + binary: 0b11001, + }, + FPRegisterRiscv { + names: &["f26", "fs10"], + binary: 0b11010, + }, + FPRegisterRiscv { + names: &["f27", "fs11"], + binary: 0b11011, + }, + FPRegisterRiscv { + names: &["f28", "ft8"], + binary: 0b11100, + }, + FPRegisterRiscv { + names: &["f29", "ft9"], + binary: 0b11101, + }, + FPRegisterRiscv { + names: &["f30", "ft10"], + binary: 0b11110, + }, + FPRegisterRiscv { + names: &["f31", "ft11"], + binary: 0b11111, + }, +]; + //This enum is just for the read_register_function to determine which register type it should expect #[derive(Eq, PartialEq)] pub enum RegisterType { @@ -949,19 +1239,21 @@ pub fn print_vec_of_data(data: Vec) { } pub fn print_instruction_contents(instruction: Instruction) { - println!("Operator: {}", instruction.operator.token_name); - print!("Operands: "); + log!("Operator: ", instruction.operator.token_name); + log!("Operands: "); for operand in instruction.operands { - print!("{} ", operand.token_name); + log!(operand.token_name); } - println!(); + log!(""); for label in instruction.labels { - println!("Label: {}", label.token.token_name); + log!("Label: ", label.token.token_name); } - print!("Errors: "); + log!("Errors: "); for error in instruction.errors { - print!("{:?} ", error.error_name); + log!(error.error_name.to_string()); } + + log!("Binary ", instruction.binary); } pub fn print_data_contents(data: Data) { diff --git a/static/assembly_examples/riscv_test.asm b/static/assembly_examples/riscv_test.asm new file mode 100644 index 000000000..f49f2a7bb --- /dev/null +++ b/static/assembly_examples/riscv_test.asm @@ -0,0 +1,4 @@ +# Currently there is a problem with using tabs to space out instructions +main: + jal x1, 50 + ret \ No newline at end of file From 01a9f714bff8824bd36e652302abe69e1dbf33bf Mon Sep 17 00:00:00 2001 From: rharding8 Date: Mon, 29 Jan 2024 19:25:18 -0500 Subject: [PATCH 020/355] Pushing the in-progress (Unfinished, not working) RISC-V core to a new branch. SWIM will still work even with these unfinished since the RISC-V core is being kept out of the module rs file until it's more complete and can be tested. --- src/emulation_core/riscv/constants.rs | 140 +++ src/emulation_core/riscv/control_signals.rs | 552 +++++++++++ src/emulation_core/riscv/coprocessor.rs | 619 ++++++++++++ src/emulation_core/riscv/datapath.rs | 949 +++++++++++++++++++ src/emulation_core/riscv/datapath_signals.rs | 55 ++ src/emulation_core/riscv/instruction.rs | 167 ++++ src/emulation_core/riscv/line_info.rs | 334 +++++++ src/emulation_core/riscv/memory.rs | 145 +++ src/emulation_core/riscv/registers.rs | 221 +++++ 9 files changed, 3182 insertions(+) create mode 100644 src/emulation_core/riscv/constants.rs create mode 100644 src/emulation_core/riscv/control_signals.rs create mode 100644 src/emulation_core/riscv/coprocessor.rs create mode 100644 src/emulation_core/riscv/datapath.rs create mode 100644 src/emulation_core/riscv/datapath_signals.rs create mode 100644 src/emulation_core/riscv/instruction.rs create mode 100644 src/emulation_core/riscv/line_info.rs create mode 100644 src/emulation_core/riscv/memory.rs create mode 100644 src/emulation_core/riscv/registers.rs diff --git a/src/emulation_core/riscv/constants.rs b/src/emulation_core/riscv/constants.rs new file mode 100644 index 000000000..29c107f4a --- /dev/null +++ b/src/emulation_core/riscv/constants.rs @@ -0,0 +1,140 @@ +use super::control_signals::RegWidth; + +pub const FUNCT_SYSCALL: u8 = 0b001100; + +pub const FUNCT_SLL: u8 = 0b000000; +pub const FUNCT_ADD: u8 = 0b100000; +pub const FUNCT_ADDU: u8 = 0b100001; +pub const FUNCT_SUB: u8 = 0b100010; +pub const FUNCT_AND: u8 = 0b100100; +pub const FUNCT_OR: u8 = 0b100101; +pub const FUNCT_SLT: u8 = 0b101010; +pub const FUNCT_SLTU: u8 = 0b101011; + +pub const FUNCT_DADD: u8 = 0b101100; +pub const FUNCT_DADDU: u8 = 0b101101; +pub const FUNCT_DSUB: u8 = 0b101110; +pub const FUNCT_DSUBU: u8 = 0b101111; + +pub const FUNCT_JALR: u8 = 0b001001; +pub const FUNCT_JR: u8 = FUNCT_JALR; + +/// Used for `MUL` and `MUH`. +pub const FUNCT_SOP30: u8 = 0b011000; + +/// Used for `MULU` and `MUHU`. +pub const FUNCT_SOP31: u8 = 0b011001; + +/// Used for `DIV` and `MOD`. +pub const FUNCT_SOP32: u8 = 0b011010; + +/// Used for `DIVU` and `MODU`. +pub const FUNCT_SOP33: u8 = 0b011011; + +/// Used for `DMUL` and `DMUH`. +pub const FUNCT_SOP34: u8 = 0b011100; + +/// Used for `DMULU` and `DMUHU`. +pub const FUNCT_SOP35: u8 = 0b011101; + +/// Used for `DDIV` and `DMOD`. +pub const FUNCT_SOP36: u8 = 0b011110; + +/// Used for `DDIVU` and `DMODU`. +pub const FUNCT_SOP37: u8 = 0b011111; + +/// Used for R-type instructions. +pub const OPCODE_OP: u8 = 0b0110011; + +/// Used for I-type instructions. +pub const OPCODE_IMM: u8 = 0b0010011; +// JALR +pub const OPCODE_JALR: u8 = 0b1100111; +// LOAD +pub const OPCODE_LOAD: u8 = 0b0000011; +// Maybe MISC-MEM? +pub const OPCODE_MISC_MEM: u8 = 0b0001111; +// SYSTEM +pub const OPCODE_SYSTEM: u8 = 0b1110011; + +/// Used for S-type instructions. +pub const OPCODE_STORE: u8 = 0b0100011; + +/// Used for B-type instructions. +pub const OPCODE_BRANCH: u8 = 0b1100011; + +/// Used for U-type instructions. +// LUI +pub const OPCODE_LUI: u8 = 0b0110111; +// AUIPC +pub const OPCODE_AUIPC: u8 = 0b0010111; + +/// Used for J-type instructions. +pub const OPCODE_JAL: u8 = 0b1101111; + + +// "ENC" is short for encoding. There is no formal name for this field +// in the MIPS64 specification, other than the "shamt"/"sa" field that it +// replaces, so this was chosen as the mnemonic for this project. +pub const ENC_MUL: u8 = 0b00010; +pub const ENC_MULU: u8 = 0b00010; +pub const ENC_DIV: u8 = 0b00010; +pub const ENC_DIVU: u8 = 0b00010; +pub const ENC_DMUL: u8 = 0b00010; +pub const ENC_DMULU: u8 = 0b00010; +pub const ENC_DDIV: u8 = 0b00010; +pub const ENC_DDIVU: u8 = 0b00010; + +// "RMSUB" is short for register immediate subcode. There is no formal name +// for this field in the MIPS64 specification, other than the "rt" field that +// it replaces, so this was chosen as a mnemonic for this project. +pub const RMSUB_DAHI: u8 = 0b00110; +pub const RMSUB_DATI: u8 = 0b11110; + +pub const FUNCTION_ADD: u8 = 0b000000; +pub const FUNCTION_SUB: u8 = 0b000001; +pub const FUNCTION_MUL: u8 = 0b000010; +pub const FUNCTION_DIV: u8 = 0b000011; + +// All floating-point c.cond.fmt instructions begin the +// function field with 11. +pub const FUNCTION_C_EQ: u8 = 0b110010; +pub const FUNCTION_C_LT: u8 = 0b111100; +pub const FUNCTION_C_NGE: u8 = 0b111101; +pub const FUNCTION_C_LE: u8 = 0b111110; +pub const FUNCTION_C_NGT: u8 = 0b111111; + +// "SUB" is short for operation subcode. Bits 25..21 of some instructions. +/// Floating-point branch conditional. +pub const SUB_BC: u8 = 0b01000; +/// Move word from floating point. +pub const SUB_MF: u8 = 0b00000; +/// Move word to floating point. +pub const SUB_MT: u8 = 0b00100; +/// Doubleword move from floating point. +pub const SUB_DMF: u8 = 0b00001; +/// Doubleword move to floating point. +pub const SUB_DMT: u8 = 0b00101; + +pub const FMT_SINGLE: u8 = 16; +pub const FMT_DOUBLE: u8 = 17; + +/// Return the register width associated to an instruction +/// with the given `funct` code. +/// +/// Returns [`None`] if the `funct` code is not supported. +pub fn reg_width_by_funct(funct: u8) -> Option { + match funct { + // `syscall` does not have a register width associated with it, + // but is set for the purposes of a default signal value. + FUNCT_SYSCALL => Some(RegWidth::DoubleWord), + FUNCT_ADD | FUNCT_ADDU | FUNCT_SUB | FUNCT_SLL => Some(RegWidth::Word), + FUNCT_AND | FUNCT_OR | FUNCT_SLT | FUNCT_SLTU => Some(RegWidth::DoubleWord), + FUNCT_DADD | FUNCT_DSUB => Some(RegWidth::DoubleWord), + FUNCT_DADDU | FUNCT_DSUBU => Some(RegWidth::DoubleWord), + FUNCT_JALR => Some(RegWidth::DoubleWord), + FUNCT_SOP30 | FUNCT_SOP31 | FUNCT_SOP32 | FUNCT_SOP33 => Some(RegWidth::Word), + FUNCT_SOP34 | FUNCT_SOP35 | FUNCT_SOP36 | FUNCT_SOP37 => Some(RegWidth::DoubleWord), + _ => None, + } +} diff --git a/src/emulation_core/riscv/control_signals.rs b/src/emulation_core/riscv/control_signals.rs new file mode 100644 index 000000000..414b1dd7c --- /dev/null +++ b/src/emulation_core/riscv/control_signals.rs @@ -0,0 +1,552 @@ +//! Internal datapath control signals. + +/// Full collection of control signals. +#[derive(Clone, Default, PartialEq)] +pub struct ControlSignals { + pub alu_control: AluControl, + pub alu_op: AluOp, + pub alu_src: AluSrc, + pub branch: Branch, + pub branch_type: BranchType, + pub imm_shift: ImmShift, + pub jump: Jump, + pub mem_read: MemRead, + pub mem_to_reg: MemToReg, + pub mem_write: MemWrite, + pub mem_write_src: MemWriteSrc, + pub reg_dst: RegDst, + pub reg_width: RegWidth, + pub reg_write: RegWrite, +} + +/// The output of the ALU control unit that directly controls the ALU. +/// +/// This is not to be confused with the [`AluOp`] signal. ALUControl is +/// a function of both [`AluOp`] and the `funct` field of an R-type +/// instruction. While this is a separate control signal, the +/// [`RegWidth`] control signal additionally acts as the leading bit of +/// ALUControl. The leading bit of the signal determines the size of +/// the input and output data within the datapath. See [`RegWidth`] for +/// more details. +#[derive(Clone, Default, PartialEq)] +pub enum AluControl { + /// `_0000` (0) - Perform an addition. (Also used in cases where the ALU result does not matter.) + #[default] + Addition, + + /// `_0001` (1) - Perform a subtraction. Will not set any underflow signal on underflow. + Subtraction, + + /// `_0010` (2) - Perform a "set on less than" operation. + SetOnLessThanSigned, + + /// `_0011` (3) - Perform a "set on less than unsigned" operation. + SetOnLessThanUnsigned, + + /// `_0100` (4) - Perform a bitwise "AND" operation. + And, + + /// `_0101` (5) - Perform a bitwise "OR" operation. + Or, + + /// `_0110` (6) - Left shift the sign-extended immediate value 16 bits. + LeftShift16, + + /// `_0111` (7) - Perform a bitwise "Xor" operation. + Xor, + + /// `_1000` (8) - Perform signed multiplication. + MultiplicationSigned, + + /// `_1001` (9) - Perform unsigned multiplication. + MultiplicationUnsigned, + + /// `_1010` (10) - Perform signed integer division. (Returns the integer quotient.) + DivisionSigned, + + /// `_1011` (11) - Perform unsigned integer division. (Returns the integer quotient.) + DivisionUnsigned, + + /// `_1100` (12) - Perform a shift left logical operation by `shamt` bits. + ShiftLeftLogical(u32), + + /// `_1101` (13) - Perform a shift right logical operation by `shamt` bits. + ShiftRightLogical(u32), + + /// `_1110` (14) - Perform a shift right arithmetic operation by `shamt` bits. + ShiftRightArithmetic(u32), +} + +/// This determines the operation sent to the ALU control unit. +/// +/// This is on a higher abstraction than the output of this control +/// unit, which more specifically determines what operation the ALU +/// will perform. +#[derive(Clone, Default, PartialEq)] +pub enum AluOp { + /// `0000` (0) - Perform an addition. (Also used in cases where the ALU result does not matter.) + #[default] + Addition = 0, + + /// `0001` (1) - Perform a subtraction. Will not set any underflow signal on underflow. + Subtraction = 1, + + /// `0010` (2) - Perform a "set on less than" operation. + SetOnLessThanSigned = 2, + + /// `0011` (3) - Perform a "set on less than unsigned" operation. + SetOnLessThanUnsigned = 3, + + /// `0100` (4) - Perform a binary "AND" operation. + And = 4, + + /// `0101` (5) - Perform a binary "OR" operation. + Or = 5, + + /// `0110` (6) - Left shift the sign-extended immediate value 16 bits. + LeftShift16 = 6, + + /// `0111` (7) - This is an R-type instruction and the operation + /// should instead refer to the `funct` field in the instruction. + /// + /// (Note: For the `mul` and `div` instructions, the operation of + /// the ALU may additionally be determined by bits 10-6 of the + /// instruction (same bits as the `shamt` field), as the `funct` + /// field alone does not provide the full description of those + /// instructions.) + UseFunctField = 7, +} + +/// Determines the second source of the ALU. +/// +/// The first input is always the data read from the register `rs1` (or +/// called `base` in some contexts.) +#[derive(Clone, Default, PartialEq)] +pub enum AluSrc { + /// Use the data from the from the second source register `rs2`. + #[default] + ReadRegister2 = 0, + + /// Use the sign-extended 16-bit immediate field in the instruction. This may be left-shifted by some amount given by the [`ImmShift`] control signal. + SignExtendedImmediate = 1, + + /// Use the zero-extended 16-bit immediate field in the instruction. + ZeroExtendedImmediate = 2, +} + +/// Determines if the datapath should consider branching. +/// +/// Exact choice of branching or not branching relies on the result from the ALU. +/// This can be overridden by the [`Jump`] signal. +#[derive(Clone, Default, PartialEq)] +pub enum Branch { + /// Do not consider branching. + #[default] + NoBranch = 0, + + /// Consider branching. + YesBranch = 1, +} + +/// Determines, given [`Branch`] is set, whether to branch when the [`AluZ`](super::datapath_signals::AluZ) signal is set, +/// or when [`AluZ`](super::datapath_signals::AluZ) is not set. +/// +/// In effect, this decides whether or not to invert the [`AluZ`](super::datapath_signals::AluZ) signal, which is +/// used between the `beq` and `bne` instructions. +#[derive(Clone, Default, PartialEq)] +pub enum BranchType { + /// Branch based on [`AluZ`](super::datapath_signals::AluZ). (Used in `beq`.) + #[default] + OnEqual = 0, + + /// Branch based on the inverse of [`AluZ`](super::datapath_signals::AluZ). (Used in `bne`.) + OnNotEqual = 1, + + /// Branch based on being less than [`AluZ`](super::datapath_signals::AluZ). (Used in `blt`) + OnLessThan = 2, + + OnGreaterEqual = 3, + OnLessThanUnsigned = 4, + OnGreaterEqualUnsigned = 5, +} + +/// Determines the amount of bits to left-shift the immediate value before being passed to the ALU. +#[derive(Clone, Default, PartialEq)] +pub enum ImmShift { + #[default] + Shift0 = 0, + Shift16 = 1, + Shift32 = 2, + Shift48 = 3, +} + +/// Determines if the datapath should jump. This is an unconditional branch. +/// +/// The [`Branch`] signal may be overridden depending on the value of this signal. +#[derive(Clone, Default, PartialEq)] +pub enum Jump { + /// Do not jump. Defer to the [`Branch`] signal. + #[default] + NoJump = 0, + + /// Jump by using the address specified in the instruction's lower bits. + YesJump = 1, + + /// Jump by using the address specified in the contents of register `rs`. + /// This is used in `jr` and `jalr` instructions. + YesJumpJalr = 2, +} + +/// Determines if memory should be read. +/// +/// This should not be set in combination with [`MemWrite`]. +#[derive(Clone, Default, PartialEq)] +pub enum MemRead { + #[default] + NoRead = 0, + YesRead = 1, +} + +/// Determines, given [`RegWrite`] is set, what the source of a +/// register's new data will be. +/// +/// The decision can be completely overridden by the floating point +/// unit's [`DataWrite`](floating_point::DataWrite) control signal. +/// +/// This control signal also applies to what data is sent to the +/// floating-point unit to be stored in its registers. +#[derive(Clone, Default, PartialEq)] +pub enum MemToReg { + #[default] + UseAlu = 0, + UseMemory = 1, + UsePcPlusFour = 2, + UseImmediate = 3, +} + +/// Determines if memory should be written to. +/// +/// This should not be set in combination with the [`MemRead`] control signal. +#[derive(Clone, Default, PartialEq)] +pub enum MemWrite { + #[default] + NoWrite = 0, + YesWrite = 1, +} + +/// Determines, given that [`MemWrite`] is set, the source of the data +/// will be written to memory. +/// +/// Compared to the general-purpose datapath introduced by Hennessy and +/// Patterson, this is a new control signal created to incorporate the +/// floating-point unit. +#[derive(Clone, Default, PartialEq)] +pub enum MemWriteSrc { + /// Source the write data from the main processing unit. Specifically, this means the data read from the register `rt` from a given instruction. + #[default] + PrimaryUnit = 0, + + /// Source the write data from the floating-point unit. Specifically, this means the data read from the register `ft` from a given instruction. + FloatingPointUnit = 1, +} + +/// Determines, given that [`RegWrite`] is set, which destination +/// register to write to, which largely depends on the instruction format. +#[derive(Clone, Default, PartialEq)] +pub enum RegDst { + /// Use register `rs1`. + Reg1 = 0, + + /// Use register `rs2`. + Reg2 = 1, + + /// Use register `rd`. + #[default] + Reg3 = 2, + + /// Write to general-purpose register 31 ($ra). This is the return address + /// used in `jal` instructions. + ReturnRegister = 3, +} + +/// Determines the amount of data to be sent or recieved from registers +/// and the ALU. While all buses carrying information are 64 bits wide, +/// some bits of the bus may be ignored in the case of this control +/// signal. +#[derive(Clone, Default, PartialEq)] +pub enum RegWidth { + /// Use words (32 bits). + Word = 0, + + /// Use doublewords (64 bits). + #[default] + DoubleWord = 1, + + /// Use bytes (8 bits). + Byte = 2, + + /// Use halfwords (16 bits). + HalfWord = 3, + + /// Use unsigned bytes (8 bits). + ByteUnsigned = 4, + + /// Use unsigned halfwords (16 bits). + HalfWordUnsigned = 5, +} + +/// Determines if the register file should be written to. +#[derive(Clone, Default, Eq, PartialEq)] +pub enum RegWrite { + #[default] + NoWrite = 0, + YesWrite = 1, +} + +pub mod floating_point { + use super::super::constants::*; + + #[derive(Clone, Default, PartialEq)] + pub struct FpuControlSignals { + pub cc: Cc, + pub cc_write: CcWrite, + pub data_src: DataSrc, + pub data_write: DataWrite, + pub fpu_alu_op: FpuAluOp, + pub fpu_branch: FpuBranch, + pub fpu_mem_to_reg: FpuMemToReg, + pub fpu_reg_dst: FpuRegDst, + pub fpu_reg_width: FpuRegWidth, + pub fpu_reg_write: FpuRegWrite, + pub fpu_take_branch: FpuTakeBranch, + } + + /// Determines, given that [`CcWrite`] is set, which condition code register + /// should be written to or read from for a given operation. + /// + /// For the sake of this project, it will usually be assumed that this will + /// be 0, however the functionality is available to be extended. + #[derive(Clone, Default, PartialEq)] + pub enum Cc { + /// Use condition code register 0. Default in most operations. Can be + /// additionally used in the case where the condition code register is + /// irrelevant to the current instruction. + #[default] + Cc0 = 0, + } + + /// Determines if the condition code register file should be written to. + #[derive(Clone, Default, PartialEq)] + pub enum CcWrite { + #[default] + NoWrite = 0, + YesWrite = 1, + } + + /// Determines the source of the `Data` register in the floating-point unit. + /// + /// This is a special intermediary register that facilitates passing data between + /// the main processing unit and the floating-point unit. + #[derive(Clone, Default, PartialEq)] + pub enum DataSrc { + /// Use data from the main processing unit. Specifically, the data from register + /// `rt` from a given instruction. This value can additionally be used in the cases + /// where this register is not written to. + MainProcessorUnit = 0, + + /// Use data from the floating-point unit. Specifically, the data from register `fs` + /// from a given instruction. + #[default] + FloatingPointUnit = 1, + } + + /// Determines whether to write to the `Data` register in the floating-point unit. + /// + /// This acts as a toggle for the source of data to the main processing unit register + /// file. Additionally, it acts as a toggle for a source to the floating-point unit + /// register file (this could be overridden by the [`FpuMemToReg`] control signal). + /// For the latter two functions, it is imperative to unset the [`RegWrite`](super::RegWrite) and + /// [`FpuRegWrite`] control signals in cases where registers should not be modified + /// with unintended data. + #[derive(Clone, Default, PartialEq)] + pub enum DataWrite { + /// - Do not write to the data register. + /// - Source data to write to the main processing unit register file from the main + /// processing unit. This implies either the ALU result or the data read from memory + /// - Source data to write to the floating-point register file from the floating-point + /// ALU. + #[default] + NoWrite = 0, + + /// - Write to the data register. + /// - Source data to write to the main processing unit register file from the + /// floating-point unit. Specifically, this is the data stored in the `Data` register + /// in the FPU, likely from register `fs` from a given instruction. This data source + /// overrides the decision given by the [`MemToReg`](super::MemToReg) control signal. + /// - Source data to write to the floating-point register file from the `Data` register + /// in the FPU, likely from register `rt` from a given instruction. + YesWrite = 1, + } + + /// This doubly determines the operations sent to the floating-point ALU and the + /// floating-point comparator. + /// + /// Only one of these units are effectively utilized in any given instruction. + /// + /// The fifth bit of the control signal represents either a single-precision + /// floating-point operation (0), or a double-precision floating-point operation (1). + /// This fifth bit is determined by [`FpuRegWidth`]. + /// + /// *Implementation note:* The bits set for the comparator are intended to match + /// the bits used in the `cond` field of a `c.cond.fmt` instruction. + #[derive(Clone, Debug, Default, PartialEq)] + pub enum FpuAluOp { + #[default] + /// `_0000` (0): + /// - ALU: Perform an addition. + Addition = 0, + + /// `_0001` (1): + /// - ALU: Perform a subtraction. + Subtraction = 1, + + /// `_0010` (2): + /// - ALU: Perform a multiplication. + /// - Comparator: Set if equal. + MultiplicationOrEqual = 2, + + /// `_0011` (3): + /// - ALU: Perform a division. + Division = 3, + + /// `_0100` (4): + /// - ALU: Perform an "AND" operation. + And = 4, + + /// `_0101` (5): + /// - ALU: Perform an "OR" operation. + Or = 5, + + /// `_1100` (12): + /// - Comparator: Set if less than. + Slt = 12, + + /// `_1101` (13): + /// - Comparator: Set if not greater than or equal. + Snge = 13, + + /// `_1110` (14): + /// - Comparator: Set if less than or equal. + Sle = 14, + + /// `_1111` (15): + /// - Comparator: Set if not greater than. + Sngt = 15, + } + + impl FpuAluOp { + /// Get the corresponding control signal given a function code. + pub fn from_function(function: u8) -> Result { + match function { + FUNCTION_C_EQ => Ok(Self::MultiplicationOrEqual), + FUNCTION_C_LT => Ok(Self::Slt), + FUNCTION_C_NGE => Ok(Self::Snge), + FUNCTION_C_LE => Ok(Self::Sle), + FUNCTION_C_NGT => Ok(Self::Sngt), + _ => Err(format!("Unsupported function code `{function}`")), + } + } + } + + /// Determines if the floating-point unit should consider branching, based on the + /// contents of the condition code register. + /// + /// This directly overrides any branch decisions decided by the main processing unit. + /// The [`Branch`](super::Branch) control signal should not be set in addition to this signal. + #[derive(Clone, Default, PartialEq)] + pub enum FpuBranch { + /// Do not consider branching. + #[default] + NoBranch = 0, + + /// Consider branching. + YesBranch = 1, + } + + /// Determines, given that [`FpuRegWrite`] is set, what the source of a floating-point + /// register's new data will be. + /// + /// This decision, if set, overrides the decision from the [`DataWrite`] control signal. + #[derive(Clone, Default, PartialEq)] + pub enum FpuMemToReg { + /// Do not use data from memory. Use the result of the [`DataWrite`] control signal. + #[default] + UseDataWrite = 0, + + /// Use data from memory. + UseMemory = 1, + } + + /// Determines, given that [`FpuRegWrite`] is set, which destination register to write + /// to, which largely depends on the instruction format. + #[derive(Clone, Default, PartialEq)] + pub enum FpuRegDst { + /// Use register `ft`. + Reg1 = 0, + + /// Use register `fs`. + Reg2 = 1, + + /// Use register `fd`. + #[default] + Reg3 = 2, + } + + /// Determines the amount of data to be sent or received from registers and the ALU. + /// + /// While all buses carrying information are 64-bits wide, some bits of the bus may be + /// ignored in the case of this control signal. + #[derive(Clone, Default, PartialEq)] + pub enum FpuRegWidth { + /// Use words (32 bits). Equivalent to a single-precision floating-point value. + Word = 0, + + /// Use doublewords (64 bits). Equivalent to a double-precision floating-point value. + #[default] + DoubleWord = 1, + } + + impl FpuRegWidth { + /// Get the corresponding [`FpuRegWidth`] control signal based on + /// the `fmt` field in an instruction. + pub fn from_fmt(fmt: u8) -> Result { + match fmt { + FMT_SINGLE => Ok(Self::Word), + FMT_DOUBLE => Ok(Self::DoubleWord), + _ => Err(format!("`{fmt}` is an invalid fmt value")), + } + } + } + + /// Determines if the floating-point register file should be written to. + #[derive(Clone, Default, PartialEq)] + pub enum FpuRegWrite { + /// Do not write to the floating-point register file. + #[default] + NoWrite = 0, + + /// Write to the floating-point register file. + YesWrite = 1, + } + + /// After checking the [`FpuBranch`] and condition code, this signal determines whether + /// to follow through with a branch. + /// + /// This signal is what is sent to the main processor. + #[derive(Clone, Default, PartialEq)] + pub enum FpuTakeBranch { + #[default] + NoBranch = 0, + YesBranch = 1, + } +} diff --git a/src/emulation_core/riscv/coprocessor.rs b/src/emulation_core/riscv/coprocessor.rs new file mode 100644 index 000000000..c0c40fe85 --- /dev/null +++ b/src/emulation_core/riscv/coprocessor.rs @@ -0,0 +1,619 @@ +//! Implementation of a MIPS64 floating-point coprocessor. + +use super::constants::*; +use super::control_signals::floating_point::*; +use super::instruction::Instruction; + +/// An implementation of a floating-point coprocessor for the MIPS64 ISA. +/// +/// Different from the main processor, much of the functionality of the coprocessor +/// is controlled remotely using its available API calls. +#[derive(Clone, Default, PartialEq)] +pub struct MipsFpCoprocessor { + instruction: Instruction, + pub signals: FpuControlSignals, + pub state: FpuState, + pub is_halted: bool, + + pub fpr: [u64; 32], + pub condition_code: u64, + pub data: u64, +} + +#[derive(Clone, Default, PartialEq)] +pub struct FpuState { + pub instruction: u32, + pub op: u32, + pub fmt: u32, + pub fs: u32, + pub ft: u32, + pub fd: u32, + pub function: u32, + pub branch_flag: bool, + + /// The line that comes out of the condition code register file. Should contain + /// 1 for true or 0 for false. + pub condition_code_bit: u8, + /// The inversion of `condition_code_bit`. + pub condition_code_bit_inverted: u8, + /// The result of the multiplexer with `condition_code_bit` and `condition_code_bit_inverted`. + pub condition_code_mux: u8, + + pub data_from_main_processor: u64, + pub data_writeback: u64, + pub destination: usize, + pub fp_register_data_from_main_processor: u64, + pub read_data_1: u64, + pub read_data_2: u64, + pub register_write_data: u64, + pub register_write_mux_to_mux: u64, + pub sign_extend_data: u64, + + /// Data line that goes from `Read Data 2` to the multiplexer in the main processor + /// controlled by [`MemWriteSrc`](super::control_signals::MemWriteSrc). + /// This variable in a way in just a copy of read_data_2 + pub fp_register_to_memory: u64, + + pub alu_result: u64, + pub comparator_result: u64, +} + +impl MipsFpCoprocessor { + // ========================== Stages ========================== + pub fn stage_instruction_decode(&mut self) { + self.instruction_decode(); + self.set_control_signals(); + self.read_registers(); + } + + pub fn stage_execute(&mut self) { + self.alu(); + self.comparator(); + self.write_condition_code(); + self.write_fp_register_to_memory(); + self.set_condition_code_line(); + } + + pub fn stage_memory(&mut self) { + self.write_data(); + self.set_data_writeback(); + self.set_fpu_branch(); + } + + pub fn stage_writeback(&mut self) { + self.register_write(); + } + + // ===================== General Functions ===================== + /// Handle an otherwise irrecoverable error within the datapath. + pub fn error(&mut self, _message: &str) { + self.is_halted = true; + } + + // =================== API For Main Processor =================== + /// Set the internally-stored copy of the current instruction. This effectively + /// operates in lieu of any "instruction fetch" functionality since the coprocessor + /// does not fetch instructions. + pub fn set_instruction(&mut self, instruction_bits: u32) { + self.state.instruction = instruction_bits; + if let Ok(instruction) = Instruction::try_from(self.state.instruction) { + self.instruction = instruction; + } + } + + /// Sets the data line between the main processor and the `Data` register. This + /// is then used if deciding data from the main processor should go into the `Data` + /// register. + pub fn set_data_from_main_processor(&mut self, data: u64) { + self.state.data_from_main_processor = data; + } + + /// Gets the contents of the data line between the `Data` register and the multiplexer + /// in the main processor controlled by the [`DataWrite`] control signal. + pub fn get_data_writeback(&mut self) -> u64 { + self.state.data_writeback + } + + /// Sets the data line between the multiplexer controlled by [`MemToReg`](super::control_signals::MemToReg) + /// in the main processor and the multiplexer controlled by [`FpuMemToReg`] in the + /// floating-point coprocessor. + pub fn set_fp_register_data_from_main_processor(&mut self, data: u64) { + self.state.fp_register_data_from_main_processor = data; + } + + /// Gets the contents of the data line that goes from `Read Data 2` to the multiplexer + /// in the main processor controlled by [`MemWriteSrc`](super::control_signals::MemWriteSrc). + pub fn get_fp_register_to_memory(&mut self) -> u64 { + self.state.fp_register_to_memory + } + + // ================== Instruction Decode (ID) ================== + /// Decode an instruction into its individual fields. + fn instruction_decode(&mut self) { + // Set the data lines based on the contents of the instruction. + // Some lines will hold uninitialized values as a result. + match self.instruction { + Instruction::FpuRType(r) => { + self.state.op = r.op as u32; + self.state.fmt = r.fmt as u32; + self.state.fs = r.fs as u32; + self.state.ft = r.ft as u32; + self.state.fd = r.fd as u32; + self.state.function = r.function as u32; + } + Instruction::FpuIType(i) => { + self.state.ft = i.ft as u32; + } + Instruction::FpuRegImmType(i) => { + self.state.op = i.op as u32; + self.state.fmt = 0; // Not applicable + self.state.fs = i.fs as u32; + self.state.ft = 0; // Not applicable + self.state.fd = 0; // Not applicable + } + Instruction::FpuCompareType(c) => { + self.state.op = c.op as u32; + self.state.fmt = c.fmt as u32; + self.state.ft = c.ft as u32; + self.state.fs = c.fs as u32; + self.state.function = c.function as u32; + } + Instruction::FpuBranchType(b) => { + self.state.op = b.op as u32; + self.state.fmt = b.bcc1 as u32; + self.state.branch_flag = b.tf == 1; + } + // These types do not use the floating-point unit so they can be ignored. + Instruction::RType(_) + | Instruction::IType(_) + | Instruction::JType(_) + | Instruction::SyscallType(_) => (), + } + } + + /// Set the control signals of the processor based on the instruction opcode and function + /// control signals. + fn set_control_signals(&mut self) { + match self.instruction { + Instruction::FpuRType(r) => { + match r.op { + OPCODE_COP1 => match r.function { + FUNCTION_ADD => { + self.signals.cc = Cc::Cc0; + self.signals.cc_write = CcWrite::NoWrite; + self.signals.data_src = DataSrc::FloatingPointUnit; + self.signals.data_write = DataWrite::NoWrite; + self.signals.fpu_alu_op = FpuAluOp::Addition; + self.signals.fpu_branch = FpuBranch::NoBranch; + self.signals.fpu_mem_to_reg = FpuMemToReg::UseDataWrite; + self.signals.fpu_reg_dst = FpuRegDst::Reg3; + self.signals.fpu_reg_width = match FpuRegWidth::from_fmt(r.fmt) { + Ok(width) => width, + Err(message) => { + self.error(&message); + FpuRegWidth::default() + } + }; + self.signals.fpu_reg_write = FpuRegWrite::YesWrite; + } + FUNCTION_SUB => { + self.signals.cc = Cc::Cc0; + self.signals.cc_write = CcWrite::NoWrite; + self.signals.data_src = DataSrc::FloatingPointUnit; + self.signals.data_write = DataWrite::NoWrite; + self.signals.fpu_alu_op = FpuAluOp::Subtraction; + self.signals.fpu_branch = FpuBranch::NoBranch; + self.signals.fpu_mem_to_reg = FpuMemToReg::UseDataWrite; + self.signals.fpu_reg_dst = FpuRegDst::Reg3; + self.signals.fpu_reg_width = match FpuRegWidth::from_fmt(r.fmt) { + Ok(width) => width, + Err(message) => { + self.error(&message); + FpuRegWidth::default() + } + }; + self.signals.fpu_reg_write = FpuRegWrite::YesWrite; + } + FUNCTION_MUL => { + self.signals.cc = Cc::Cc0; + self.signals.cc_write = CcWrite::NoWrite; + self.signals.data_src = DataSrc::FloatingPointUnit; + self.signals.data_write = DataWrite::NoWrite; + self.signals.fpu_alu_op = FpuAluOp::MultiplicationOrEqual; + self.signals.fpu_branch = FpuBranch::NoBranch; + self.signals.fpu_mem_to_reg = FpuMemToReg::UseDataWrite; + self.signals.fpu_reg_dst = FpuRegDst::Reg3; + self.signals.fpu_reg_width = match FpuRegWidth::from_fmt(r.fmt) { + Ok(width) => width, + Err(message) => { + self.error(&message); + FpuRegWidth::default() + } + }; + self.signals.fpu_reg_write = FpuRegWrite::YesWrite; + } + FUNCTION_DIV => { + self.signals.cc = Cc::Cc0; + self.signals.cc_write = CcWrite::NoWrite; + self.signals.data_src = DataSrc::FloatingPointUnit; + self.signals.data_write = DataWrite::NoWrite; + self.signals.fpu_alu_op = FpuAluOp::Division; + self.signals.fpu_branch = FpuBranch::NoBranch; + self.signals.fpu_mem_to_reg = FpuMemToReg::UseDataWrite; + self.signals.fpu_reg_dst = FpuRegDst::Reg3; + self.signals.fpu_reg_width = match FpuRegWidth::from_fmt(r.fmt) { + Ok(width) => width, + Err(message) => { + self.error(&message); + FpuRegWidth::default() + } + }; + self.signals.fpu_reg_write = FpuRegWrite::YesWrite; + } + // Unrecognized format code. Perform no operation. + _ => self.error(&format!( + "COP1 instruction with function code `{}`", + r.function + )), + }, + // Unrecognized opcode. Perform no operation. + _ => self.error(&format!( + "Unsupported opcode `{}` for FPU R-type instruction", + r.op + )), + } + } + Instruction::FpuIType(i) => match i.op { + OPCODE_SWC1 => { + self.signals = FpuControlSignals { + cc_write: CcWrite::NoWrite, + data_write: DataWrite::NoWrite, + fpu_branch: FpuBranch::NoBranch, + fpu_reg_width: FpuRegWidth::Word, + fpu_reg_write: FpuRegWrite::NoWrite, + ..Default::default() + } + } + OPCODE_LWC1 => { + self.signals = FpuControlSignals { + cc_write: CcWrite::NoWrite, + data_write: DataWrite::NoWrite, + fpu_branch: FpuBranch::NoBranch, + fpu_mem_to_reg: FpuMemToReg::UseMemory, + fpu_reg_dst: FpuRegDst::Reg1, + fpu_reg_width: FpuRegWidth::Word, + fpu_reg_write: FpuRegWrite::YesWrite, + ..Default::default() + } + } + _ => self.error(&format!( + "Unsupported opcode `{}` for FPU I-type instruction", + i.op + )), + }, + Instruction::FpuRegImmType(i) => match i.sub { + SUB_MT => { + self.signals = FpuControlSignals { + cc_write: CcWrite::NoWrite, + data_src: DataSrc::MainProcessorUnit, + data_write: DataWrite::YesWrite, + fpu_branch: FpuBranch::NoBranch, + fpu_mem_to_reg: FpuMemToReg::UseDataWrite, + fpu_reg_dst: FpuRegDst::Reg2, + fpu_reg_width: FpuRegWidth::Word, + fpu_reg_write: FpuRegWrite::YesWrite, + ..Default::default() + } + } + SUB_DMT => { + self.signals = FpuControlSignals { + cc_write: CcWrite::NoWrite, + data_src: DataSrc::MainProcessorUnit, + data_write: DataWrite::YesWrite, + fpu_branch: FpuBranch::NoBranch, + fpu_mem_to_reg: FpuMemToReg::UseDataWrite, + fpu_reg_dst: FpuRegDst::Reg2, + fpu_reg_width: FpuRegWidth::DoubleWord, + fpu_reg_write: FpuRegWrite::YesWrite, + ..Default::default() + } + } + SUB_MF => { + self.signals = FpuControlSignals { + cc_write: CcWrite::NoWrite, + data_src: DataSrc::FloatingPointUnit, + data_write: DataWrite::YesWrite, + fpu_branch: FpuBranch::NoBranch, + fpu_reg_width: FpuRegWidth::Word, + fpu_reg_write: FpuRegWrite::NoWrite, + ..Default::default() + } + } + SUB_DMF => { + self.signals = FpuControlSignals { + cc_write: CcWrite::NoWrite, + data_src: DataSrc::FloatingPointUnit, + data_write: DataWrite::YesWrite, + fpu_branch: FpuBranch::NoBranch, + fpu_reg_width: FpuRegWidth::DoubleWord, + fpu_reg_write: FpuRegWrite::NoWrite, + ..Default::default() + } + } + _ => self.error(&format!( + "Unsupported sub code `{}` for FPU register-immediate instruction", + i.sub + )), + }, + Instruction::FpuCompareType(c) => { + self.signals = FpuControlSignals { + // All floating-point branch instructions are forced to use the same + // one condition code register, regardless of the CC field in the + // instruction. It should be noted that this differs from the + // real-world MIPS specification. + cc: Cc::Cc0, + cc_write: CcWrite::YesWrite, + data_write: DataWrite::NoWrite, + fpu_alu_op: match FpuAluOp::from_function(c.function) { + Ok(op) => op, + Err(message) => { + self.error(&message); + FpuAluOp::default() + } + }, + fpu_branch: FpuBranch::NoBranch, + fpu_reg_width: match FpuRegWidth::from_fmt(c.fmt) { + Ok(width) => width, + Err(message) => { + self.error(&message); + FpuRegWidth::default() + } + }, + fpu_reg_write: FpuRegWrite::NoWrite, + ..Default::default() + } + } + Instruction::FpuBranchType(_) => { + self.signals = FpuControlSignals { + // All floating-point branch instructions are forced to use the same + // one condition code register, regardless of the CC field in the + // instruction. It should be noted that this differs from the + // real-world MIPS specification. + cc: Cc::Cc0, + fpu_branch: FpuBranch::YesBranch, + ..Default::default() + } + } + // These types do not use the floating-point unit so they can be ignored. + Instruction::RType(_) + | Instruction::IType(_) + | Instruction::JType(_) + | Instruction::SyscallType(_) => self.signals = FpuControlSignals::default(), + } + } + + /// Read the registers as specified from the instruction and pass + /// the data into the datapath. + fn read_registers(&mut self) { + let reg1 = self.state.fs as usize; + let reg2 = self.state.ft as usize; + + self.state.read_data_1 = self.fpr[reg1]; + self.state.read_data_2 = self.fpr[reg2]; + + // Truncate the variable data if a 32-bit word is requested. + if let FpuRegWidth::Word = self.signals.fpu_reg_width { + self.state.read_data_1 = self.fpr[reg1] as u32 as u64; + self.state.read_data_2 = self.fpr[reg2] as u32 as u64; + } + } + + // ======================= Execute (EX) ======================= + /// Perform an ALU operation. + fn alu(&mut self) { + let input1 = self.state.read_data_1; + let input2 = self.state.read_data_2; + + let mut input1_f32 = 0f32; + let mut input2_f32 = 0f32; + let mut input1_f64 = 0f64; + let mut input2_f64 = 0f64; + + // Truncate the inputs if 32-bit operations are expected. + if let FpuRegWidth::Word = self.signals.fpu_reg_width { + input1_f32 = f32::from_bits(input1 as u32); + input2_f32 = f32::from_bits(input2 as u32); + } else { + input1_f64 = f64::from_bits(input1); + input2_f64 = f64::from_bits(input2); + } + + self.state.alu_result = match self.signals.fpu_alu_op { + FpuAluOp::Addition => match self.signals.fpu_reg_width { + FpuRegWidth::Word => f32::to_bits(input1_f32 + input2_f32) as u64, + FpuRegWidth::DoubleWord => f64::to_bits(input1_f64 + input2_f64), + }, + FpuAluOp::Subtraction => match self.signals.fpu_reg_width { + FpuRegWidth::Word => f32::to_bits(input1_f32 - input2_f32) as u64, + FpuRegWidth::DoubleWord => f64::to_bits(input1_f64 - input2_f64), + }, + FpuAluOp::MultiplicationOrEqual => match self.signals.fpu_reg_width { + FpuRegWidth::Word => f32::to_bits(input1_f32 * input2_f32) as u64, + FpuRegWidth::DoubleWord => f64::to_bits(input1_f64 * input2_f64), + }, + FpuAluOp::Division => match self.signals.fpu_reg_width { + FpuRegWidth::Word => { + if input2_f32 == 0f32 { + f32::to_bits(0f32) as u64 + } else { + f32::to_bits(input1_f32 / input2_f32) as u64 + } + } + FpuRegWidth::DoubleWord => { + if input2_f64 == 0.0 { + f64::to_bits(0.0) + } else { + f64::to_bits(input1_f64 / input2_f64) + } + } + }, + // No operation. + FpuAluOp::Slt | FpuAluOp::Snge | FpuAluOp::Sle | FpuAluOp::Sngt => 0, + _ => { + self.error(&format!( + "Unsupported operation in FPU `{:?}`", + self.signals.fpu_alu_op + )); + 0 + } + }; + } + + /// Perform a comparison. + fn comparator(&mut self) { + let input1 = self.state.read_data_1; + let input2 = self.state.read_data_2; + + let input1_f32 = f32::from_bits(input1 as u32); + let input2_f32 = f32::from_bits(input2 as u32); + let input1_f64 = f64::from_bits(input1); + let input2_f64 = f64::from_bits(input2); + + self.state.comparator_result = match self.signals.fpu_alu_op { + FpuAluOp::MultiplicationOrEqual => match self.signals.fpu_reg_width { + FpuRegWidth::Word => (input1_f32 == input2_f32) as u64, + FpuRegWidth::DoubleWord => (input1_f64 == input2_f64) as u64, + }, + FpuAluOp::Slt => match self.signals.fpu_reg_width { + FpuRegWidth::Word => (input1_f32 < input2_f32) as u64, + FpuRegWidth::DoubleWord => (input1_f64 < input2_f64) as u64, + }, + FpuAluOp::Sle => match self.signals.fpu_reg_width { + FpuRegWidth::Word => (input1_f32 <= input2_f32) as u64, + FpuRegWidth::DoubleWord => (input1_f64 <= input2_f64) as u64, + }, + FpuAluOp::Sngt => match self.signals.fpu_reg_width { + FpuRegWidth::Word => !input1_f32.gt(&input2_f32) as u64, + FpuRegWidth::DoubleWord => !input1_f64.gt(&input2_f64) as u64, + }, + FpuAluOp::Snge => match self.signals.fpu_reg_width { + FpuRegWidth::Word => !input1_f32.ge(&input2_f32) as u64, + FpuRegWidth::DoubleWord => !input1_f64.ge(&input2_f64) as u64, + }, + FpuAluOp::Addition | FpuAluOp::Subtraction | FpuAluOp::Division => 0, // No operation + _ => { + self.error(&format!( + "Unsupported operation in comparator `{:?}`", + self.signals.fpu_alu_op + )); + 0 + } + } + } + + /// Write to the `Data` register. This register is used to transfer data between + /// the main processor and the coprocessor. + fn write_data(&mut self) { + if let DataWrite::NoWrite = self.signals.data_write { + return; + } + + self.data = match self.signals.data_src { + DataSrc::FloatingPointUnit => self.state.read_data_1, + DataSrc::MainProcessorUnit => self.state.data_from_main_processor, + }; + } + + /// Set the condition code (CC) register based on the result from the comparator. + fn write_condition_code(&mut self) { + if let CcWrite::YesWrite = self.signals.cc_write { + self.condition_code = self.state.comparator_result; + } + } + + /// Set the data line that goes from `Read Data 2` to the multiplexer in the main processor + /// controlled by [`MemWriteSrc`](super::control_signals::MemWriteSrc). + fn write_fp_register_to_memory(&mut self) { + self.state.fp_register_to_memory = self.state.read_data_2; + } + + // ======================= Memory (MEM) ======================= + /// Set the data line that goes out of the condition code register file. + fn set_condition_code_line(&mut self) { + // The MIPS architecture supports more than one condition code, but SWIM + // manually uses only one. This stubs the possible use of more than one + // for future development. + let selected_register_data = match self.signals.cc { + Cc::Cc0 => self.condition_code, + }; + + // This only considers one bit of the selected condition code register. + self.state.condition_code_bit = match selected_register_data % 2 { + 0 => 0, + _ => 1, + }; + } + + /// Set the data line between the multiplexer after the `Data` register and the + /// multiplexer in the main processor controlled by the [`DataWrite`] control signal. + fn set_data_writeback(&mut self) { + self.state.sign_extend_data = self.data as i32 as i64 as u64; + self.state.data_writeback = match self.signals.fpu_reg_width { + FpuRegWidth::Word => self.state.sign_extend_data, + FpuRegWidth::DoubleWord => self.data, + } + } + + /// Simulate the logic between `self.state.condition_code_bit` and the FPU branch + /// AND gate. + fn set_fpu_branch(&mut self) { + // Invert the condition code. (In this case, instead of using a bitwise NOT, this + // will invert only the last digit and leave the rest as 0.) + self.state.condition_code_bit_inverted = match self.state.condition_code_bit % 2 { + 0 => 1, + _ => 0, + }; + + // Run the multiplexer. + self.state.condition_code_mux = match self.state.branch_flag { + // 0 - Use inverted condition code. + false => self.state.condition_code_bit_inverted, + // 1 - Use condition code value as-is. + true => self.state.condition_code_bit, + }; + + // Set the result of the AND gate. + self.signals.fpu_take_branch = if self.signals.fpu_branch == FpuBranch::YesBranch + && self.state.condition_code_mux == 1 + { + FpuTakeBranch::YesBranch + } else { + FpuTakeBranch::NoBranch + }; + } + + // ====================== Writeback (WB) ====================== + /// Write data to the floating-point register file. + fn register_write(&mut self) { + if let FpuRegWrite::NoWrite = self.signals.fpu_reg_write { + return; + } + + self.state.destination = match self.signals.fpu_reg_dst { + FpuRegDst::Reg1 => self.state.ft as usize, + FpuRegDst::Reg2 => self.state.fs as usize, + FpuRegDst::Reg3 => self.state.fd as usize, + }; + + self.state.register_write_mux_to_mux = match self.signals.data_write { + DataWrite::NoWrite => self.state.alu_result, + DataWrite::YesWrite => self.data, + }; + self.state.register_write_data = match self.signals.fpu_mem_to_reg { + FpuMemToReg::UseDataWrite => self.state.register_write_mux_to_mux, + FpuMemToReg::UseMemory => self.state.fp_register_data_from_main_processor, + }; + + self.fpr[self.state.destination] = self.state.register_write_data; + } +} diff --git a/src/emulation_core/riscv/datapath.rs b/src/emulation_core/riscv/datapath.rs new file mode 100644 index 000000000..3cc24e159 --- /dev/null +++ b/src/emulation_core/riscv/datapath.rs @@ -0,0 +1,949 @@ +//! Implementation of a MIPS64 datapath. +//! +//! It is assumed that while moving through stages, only one +//! instruction will be active any any given point in time. Due to this, +//! we consider the datapath to be a "pseudo-single-cycle datapath." +//! +//! For the most part, this datapath is an implementation of MIPS64 Version 6. +//! (See below for exceptions.) +//! +//! # Differences Compared to MIPS64 Version 6 +//! +//! It should be noted that this datapath chooses to diverge from the MIPS64 +//! version 6 specification for the sake of simplicity in a few places: +//! +//! - There is no exception handling, including that for integer overflow. (See +//! [`MipsDatapath::alu()`] and the following bullet.) +//! - The `add`, `addi`, `dadd`, `daddi`, `sub`, and `dsub` instructions do not +//! follow the proper MIPS specification in terms of integer overflow/wraparound. +//! That is, if there is integer wraparound, the general-purpose register should +//! not be written to. In our implementation, the general-purpose register is +//! written to regardless. +//! - 32-bit instructions are treated exclusively with 32 bits, and the upper 32 +//! bits stored in a register are completely ignored in any of these cases. For +//! example, before an `add` instruction, it should be checked whether it is a +//! sign-extended 32-bit value stored in a 64-bit register. Instead, the upper +//! 32 bits are ignored when being used for 32-bit instructions. +//! - Instead of implementing the `cmp.condn.fmt` instructions, this datapath implements +//! the `c.cond.fmt` instructions from MIPS64 version 5. +//! - Unlike MIPS specification, SWIM only uses 1 condition code register (`cc`), rather +//! than offering 8 condition code registers. The datapath will assume that the `cc` +//! field in a floating-point comparison or floating-point branch instruction is 0. +//! - This datapath implements the `addi` instruction as it exists in MIPS64 version 5. +//! This instruction was deprecated in MIPS64 version 6 to allow for the `beqzalc`, +//! `bnezalc`, `beqc`, and `bovc` instructions. +//! - This datapath implements `daddi` as it exists in MIPS64 version 5. This instruction +//! was deprecated in MIPS64 version 6. +//! - Unlike the MIPS64 version 6 specification for the `jal` and `jalr` instructions, +//! `PC + 4` is stored in `GPR[31]`, *not* `PC + 8`, as there is no implementation of +//! branch delay slots. +//! +//! # Notes on `is_halted` +//! +//! - The datapath starts with the `is_halted` flag set. +//! - [`MipsDatapath::initialize()`] should be used to un-set `is_halted`. +//! - The `syscall` instruction simply performs a no-operation instruction, except for +//! setting the boolean flag `is_halted`. +//! - Invalid instructions will cause the datapath to set the `is_halted` flag. + +use super::super::datapath::Datapath; +use super::constants::*; +use super::control_signals::{floating_point::*, *}; +use super::datapath_signals::*; +use super::instruction::*; +use super::{coprocessor::MipsFpCoprocessor, memory::Memory, registers::GpRegisters}; + +/// An implementation of a datapath for the MIPS64 ISA. +#[derive(Clone, PartialEq)] +pub struct RiscDatapath { + pub registers: GpRegisters, + pub memory: Memory, + pub coprocessor: MipsFpCoprocessor, + + pub instruction: Instruction, + pub signals: ControlSignals, + pub datapath_signals: DatapathSignals, + pub state: DatapathState, + + /// The currently-active stage in the datapath. + pub current_stage: Stage, + + /// Boolean value that states whether the datapath has halted. + /// + /// This is set in the event of any `syscall` instruction. To unset this, + /// [`Self::initialize()`] should be used. + is_halted: bool, +} + +/// A collection of all the data lines and wires in the datapath. +#[derive(Clone, Default, PartialEq)] +pub struct DatapathState { + /// *Data line.* The currently loaded instruction. Initialized after the + /// Instruction Fetch stage. + pub instruction: u32, + pub rs1: u32, + pub rs2: u32, + pub rd: u32, + pub shamt: u32, + pub funct3: u32, + pub funct7: u32, + pub imm: u32, + pub imm1: u32, + pub imm2: u32, + + /// *Data line.* The first input of the ALU. + pub alu_input1: u64, + + /// *Data line.* The second input of the ALU. + pub alu_input2: u64, + + /// *Data line.* The final result as provided by the ALU. + /// Initialized after the Execute stage. + pub alu_result: u64, + + /// *Data line.* The data after the `MemToReg` multiplexer, but + /// before the `DataWrite` multiplexer in the main processor. + pub data_result: u64, + + // *Data line.* This line carries the idenfication number for the + // register register-write will write to. + pub write_register_destination: usize, + + /// *Jump address line.* This line carries the concatenation of + /// the high 36 bits of the PC, and `lower_26_shifted_left_by_2`. + pub jump_address: u64, + + /// *Jump 26 bit line.* The lower 26 bits of the instruction reserved + /// for the location used by a J-type instruction. + pub lower_26: u32, + + /// *Lower 26 << 2 line.* This line carries the lower 28 bits of the + /// jump address. + pub lower_26_shifted_left_by_2: u32, + + /// *Data line.* Determines the next value of the PC, given that the + /// current instruction is not a jump. + pub mem_mux1_to_mem_mux2: u64, + + /// *Data line.* The data retrieved from memory. Initialized after + /// the Memory stage. + pub memory_data: u64, + + /// *New PC line.* In the WB stage, this line is written to the PC. + pub new_pc: u64, + + /// *Data line.* Contains PC + 4. + pub pc_plus_4: u64, + + /// *Data line.* Data read from the register file based on the `rs1` + /// field of the instruction. Initialized after the Instruction + /// Decode stage. + pub read_data_1: u64, + + /// *Data line.* Data read from the register file based on the `rd` + /// field of the instruction. Initialized after the Instruction + /// Decode stage. + pub read_data_2: u64, + + /// *Data line.* The data after the `DataWrite` multiplexer in the main + /// processor and the main processor register file. + pub register_write_data: u64, + + /// *Data line.* New PC value used if branching is set for an instruction. + pub relative_pc_branch: u64, + + /// *Data line.* The instruction's immediate value sign-extended to + /// 64 bits. Initialized after the Instruction Decode stage. + pub sign_extend: u64, + + /// *Data line.* The `sign_extend` line, shifted left by two bits. + pub sign_extend_shift_left_by_2: u64, + + /// *Data line.* The data that will be written to memory. + pub write_data: u64, +} + +/// The possible stages the datapath could be in during execution. +#[derive(Clone, Copy, Default, Eq, PartialEq)] +pub enum Stage { + #[default] + InstructionFetch, + InstructionDecode, + Execute, + Memory, + WriteBack, +} + +impl Stage { + /// Given a stage, return the next consecutive stage. If the last + /// stage is given, return the first stage. + fn get_next_stage(current_stage: Stage) -> Stage { + match current_stage { + Stage::InstructionFetch => Stage::InstructionDecode, + Stage::InstructionDecode => Stage::Execute, + Stage::Execute => Stage::Memory, + Stage::Memory => Stage::WriteBack, + Stage::WriteBack => Stage::InstructionFetch, + } + } +} + +impl Default for RiscDatapath { + fn default() -> Self { + let mut datapath = RiscDatapath { + registers: GpRegisters::default(), + memory: Memory::default(), + coprocessor: MipsFpCoprocessor::default(), + instruction: Instruction::default(), + signals: ControlSignals::default(), + datapath_signals: DatapathSignals::default(), + state: DatapathState::default(), + current_stage: Stage::default(), + is_halted: true, + }; + + // Set the stack pointer ($sp) to initially start at the end + // of memory. + datapath.registers.gpr[29] = super::memory::CAPACITY_BYTES as u64; + + datapath + } +} + +impl Datapath for RiscDatapath { + type RegisterData = u64; + type RegisterEnum = super::registers::GpRegisterType; + type MemoryType = Memory; + + fn execute_instruction(&mut self) { + loop { + // Stop early if the datapath has halted. + if self.is_halted { + break; + } + + self.execute_stage(); + + // This instruction is finished when the datapath has returned + // to the IF stage. + if self.current_stage == Stage::InstructionFetch { + break; + } + } + } + + fn execute_stage(&mut self) { + // If the datapath is halted, do nothing. + if self.is_halted { + return; + } + + match self.current_stage { + Stage::InstructionFetch => self.stage_instruction_fetch(), + Stage::InstructionDecode => self.stage_instruction_decode(), + Stage::Execute => self.stage_execute(), + Stage::Memory => self.stage_memory(), + Stage::WriteBack => self.stage_writeback(), + } + + // If the FPU has halted, reflect this in the main unit. + if self.coprocessor.is_halted { + self.is_halted = true; + } + + self.current_stage = Stage::get_next_stage(self.current_stage); + } + + fn get_register_by_enum(&self, register: Self::RegisterEnum) -> u64 { + self.registers[register] + } + + fn get_memory(&self) -> &Self::MemoryType { + &self.memory + } + + fn is_halted(&self) -> bool { + self.is_halted + } + + fn reset(&mut self) { + std::mem::take(self); + } +} + +impl RiscDatapath { + // ===================== General Functions ===================== + /// Reset the datapath, load instructions into memory, and un-sets the `is_halted` + /// flag. If the process fails, an [`Err`] is returned. + pub fn initialize(&mut self, instructions: Vec) -> Result<(), String> { + self.reset(); + self.load_instructions(instructions)?; + self.is_halted = false; + + Ok(()) + } + + /// Load a vector of 32-bit instructions into memory. If the process fails, + /// from a lack of space or otherwise, an [`Err`] is returned. + fn load_instructions(&mut self, instructions: Vec) -> Result<(), String> { + for (i, data) in instructions.iter().enumerate() { + self.memory.store_word((i as u64) * 4, *data)? + } + + Ok(()) + } + + /// Handle an otherwise irrecoverable error within the datapath. + pub fn error(&mut self, _message: &str) { + self.is_halted = true; + } + + // ========================== Stages ========================== + /// Stage 1 of 5: Instruction Fetch (IF) + /// + /// Fetch the current instruction based on the given PC and load it + /// into the datapath. + fn stage_instruction_fetch(&mut self) { + self.instruction_fetch(); + + // Upper part of datapath, PC calculation + self.pc_plus_4(); + + self.coprocessor.set_instruction(self.state.instruction); + } + + /// Stage 2 of 5: Instruction Decode (ID) + /// + /// Parse the instruction, set control signals, and read registers. + /// + /// If the instruction is determined to be a `syscall`, immediately + /// finish the instruction and set the `is_halted` flag. + fn stage_instruction_decode(&mut self) { + self.instruction_decode(); + self.set_immediate(); + self.sign_extend(); + self.set_control_signals(); + self.read_registers(); + + // Upper part of datapath, PC calculation + self.shift_lower_26_left_by_2(); + self.construct_jump_address(); + + self.coprocessor.stage_instruction_decode(); + self.coprocessor + .set_data_from_main_processor(self.state.read_data_2); + + /* Finish this instruction out of the datapath and halt if this is a syscall. + if let Instruction::SyscallType(_) = self.instruction { + self.is_halted = true; + }*/ + } + + /// Stage 3 of 5: Execute (EX) + /// + /// Execute the current instruction with some arithmetic operation. + fn stage_execute(&mut self) { + self.alu(); + self.calc_relative_pc_branch(); + self.calc_cpu_branch_signal(); + self.coprocessor.stage_execute(); + } + + /// Stage 4 of 5: Memory (MEM) + /// + /// Read or write to memory. + fn stage_memory(&mut self) { + if let MemRead::YesRead = self.signals.mem_read { + self.memory_read(); + } + + if let MemWrite::YesWrite = self.signals.mem_write { + self.memory_write(); + } + + // Determine what data will be sent to the registers: either + // the result from the ALU, or data retrieved from memory. + self.state.data_result = match self.signals.mem_to_reg { + MemToReg::UseAlu => self.state.alu_result, + MemToReg::UseMemory => self.state.memory_data, + MemToReg::UsePcPlusFour => self.state.pc_plus_4, + }; + + self.coprocessor.stage_memory(); + + // PC calculation stuff from upper part of datapath + self.calc_general_branch_signal(); + self.pick_pc_plus_4_or_relative_branch_addr_mux1(); + self.set_new_pc_mux2(); + } + + /// Stage 5 of 5: Writeback (WB) + /// + /// Write the result of the instruction's operation to a register, + /// if desired. Additionally, set the PC for the next instruction. + fn stage_writeback(&mut self) { + self.coprocessor + .set_fp_register_data_from_main_processor(self.state.data_result); + self.register_write(); + self.set_pc(); + self.coprocessor.stage_writeback(); + } + + // ================== Instruction Fetch (IF) ================== + /// Load the raw binary instruction from memory and into the + /// datapath. If there is an error with loading the word, assume + /// the instruction to be bitwise zero and error. + fn instruction_fetch(&mut self) { + self.state.instruction = match self.memory.load_word(self.registers.pc) { + Ok(data) => data, + Err(e) => { + self.error(e.as_str()); + 0 + } + } + } + + fn pc_plus_4(&mut self) { + self.state.pc_plus_4 = self.registers.pc + 4; + } + + // ================== Instruction Decode (ID) ================== + /// Decode an instruction into its individual fields. + fn instruction_decode(&mut self) { + match Instruction::try_from(self.state.instruction) { + Ok(instruction) => self.instruction = instruction, + Err(message) => { + self.error(&message); + return; + } + } + + // Set the data lines based on the contents of the instruction. + // Some lines will hold uninitialized values as a result. + match self.instruction { + Instruction::RType(r) => { + self.state.rs1 = r.rs1 as u32; + self.state.rs2 = r.rs2 as u32; + self.state.rd = r.rd as u32; + self.state.shamt = r.rs2 as u32; + self.state.funct3 = r.funct3 as u32; + self.state.funct7 = r.funct7 as u32; + } + Instruction::IType(i) => { + self.state.rs1 = i.rs1 as u32; + self.state.funct3 = i.funct3 as u32; + self.state.rd = 0; // Placeholder + self.state.imm = i.imm as u32; + self.state.shamt = (i.imm & 0x001f) as u32; + } + Instruction::SType(s) => { + self.state.rs2 = s.rs2 as u32; + self.state.rs1 = s.rs1 as u32; + self.state.funct3 = s.funct3 as u32; + self.state.imm1 = s.imm1 as u32; + self.state.imm2 = s.imm2 as u32; + } + Instruction::BType(b) => { + self.state.rs2 = b.rs2 as u32; + self.state.rs1 = b.rs1 as u32; + self.state.funct3 = b.funct3 as u32; + self.state.imm1 = b.imm1 as u32; + self.state.imm2 = b.imm2 as u32; + } + Instruction::UType(u) => { + self.state.imm = u.imm as u32; + self.state.rd = u.rd as u32; + } + Instruction::JType(j) => { + self.state.imm = j.imm as u32; + self.state.rd = j.rd as u32; + } + Instruction::R4Type(r) => { + self.state.rd = r.rd as u32; + } + } + } + + /// Extend the sign of a 16-bit value to the other 48 bits of a + /// 64-bit value. + fn sign_extend(&mut self) { + // self.state.sign_extend = ((self.state.imm as i16) as i64) as u64; + self.state.sign_extend = self.state.imm as i32 as i64 as u64; + } + + fn set_immediate(&mut self) { + let mut signed_imm = 0x0000 as u32; + if self.state.instruction >> 31 == 1 { + signed_imm = 0xffff as u32; + } + + signed_imm = match self.instruction { + Instruction::RType(r) => { + signed_imm + } + Instruction::IType(i) => { + (signed_imm << 12) | self.state.imm + } + Instruction::SType(s) => { + ((signed_imm << 7) | self.state.imm1) << 5 | self.state.imm2 + } + Instruction::BType(b) => { + ((((signed_imm << 1) | (self.state.imm2 & 0x01)) << 6) | (self.state.imm1 & 0x3f)) << 5 | (self.state.imm2 & 0x1e) + } + Instruction::UType(u) => { + ((signed_imm << 20) | self.state.imm) << 12 + } + Instruction::JType(j) => { + (((((signed_imm << 8) | (self.state.imm & 0xff)) << 1) | (self.state.imm >> 8 & 0x01)) << 11) | (self.state.imm >> 8 & 0x7fe) + } + Instruction::R4Type(r) => { + signed_imm + } + }; + + self.state.imm = signed_imm; + } + + /// Set the control signals for the datapath based on the + /// instruction's opcode. + fn set_control_signals(&mut self) { + match self.instruction { + Instruction::RType(r) => { + self.set_rtype_control_signals(r); + } + Instruction::IType(i) => { + self.set_itype_control_signals(i); + } + Instruction::SType(s) => { + self.set_stype_control_signals(s); + } + Instruction::BType(b) => { + self.set_btype_control_signals(b); + } + Instruction::UType(u) => { + self.set_utype_control_signals(u); + } + Instruction::JType(j) => { + self.set_jtype_control_signals(j); + } + _ => self.error(&format!("Unsupported Instruction!")), + } + } + + /// Set the control signals for the datapath, specifically in the + /// case where the instruction is an R-type. + fn set_rtype_control_signals(&mut self, r: RType) { + self.signals = ControlSignals { + alu_src: AluSrc::ReadRegister2, + branch: Branch::NoBranch, + jump: Jump::NoJump, + mem_read: MemRead::NoRead, + mem_to_reg: MemToReg::UseAlu, + mem_write: MemWrite::NoWrite, + reg_dst: RegDst::Reg3, + reg_width: RegWidth::Word, + reg_write: RegWrite::YesWrite, + ..Default::default() + }; + + match r.funct3 { + 0 => match r.funct7 { + 0b0000000 => self.signals.alu_control = AluControl::Addition, + 0b0100000 => self.signals.alu_control = AluControl::Subtraction + } + 1 => self.signals.alu_control = AluControl::ShiftLeftLogical(self.state.rs2), + 2 => self.signals.alu_control = AluControl::SetOnLessThanSigned, + 3 => self.signals.alu_control = AluControl::SetOnLessThanUnsigned, + 4 => self.signals.alu_control = AluControl::Xor, + 5 => match r.funct7 { + 0b0000000 => self.signals.alu_control = AluControl::ShiftRightLogical(self.state.rs2), + 0b0100000 => self.signals.alu_control = AluControl::ShiftRightArithmetic(self.state.rs2) + } + 6 => self.signals.alu_control = AluControl::Or, + 7 => self.signals.alu_control = AluControl::And + } + } + + /// Set the control signals for the datapath, specifically in the + /// case where the instruction is an I-type. + fn set_itype_control_signals(&mut self, i: IType) { + self.signals = ControlSignals { + alu_src: AluSrc::SignExtendedImmediate, + branch: Branch::NoBranch, + jump: Jump::NoJump, + mem_read: MemRead::NoRead, + mem_write: MemWrite::NoWrite, + mem_to_reg: MemToReg::UseAlu, + reg_dst: RegDst::Reg3, + reg_width: RegWidth::Word, + reg_write: RegWrite::YesWrite, + ..Default::default() + }; + + match i.op { + OPCODE_IMM => match i.funct3 { + 0 => self.signals.alu_control = AluControl::Addition, + 1 => self.signals.alu_control = AluControl::ShiftLeftLogical(self.state.shamt), + + 2 => self.signals.alu_control = AluControl::SetOnLessThanSigned, + 3 => self.signals.alu_control = AluControl::SetOnLessThanUnsigned, + 4 => self.signals.alu_control = AluControl::Xor, + 5 => { + match (i.imm >> 5) { + 0b0000000 => self.signals.alu_control = AluControl::ShiftRightLogical(self.state.shamt), + 0b0100000 => self.signals.alu_control = AluControl::ShiftRightArithmetic(self.state.shamt), + }; + } + 6 => self.signals.alu_control = AluControl::Or, + 7 => self.signals.alu_control = AluControl::And, + } + OPCODE_JALR => { + self.signals.alu_src = AluSrc::ZeroExtendedImmediate; + self.signals.mem_to_reg = MemToReg::UsePcPlusFour; + self.signals.jump = Jump::YesJumpJalr; + } + OPCODE_LOAD => { + self.signals.mem_to_reg = MemToReg::UseMemory; + self.signals.mem_write = MemWrite::YesWrite; + match i.funct3 { + 0 => self.signals.reg_width = RegWidth::Byte, + 1 => self.signals.reg_width = RegWidth::HalfWord, + 2 => self.signals.reg_width = RegWidth::Word, + 4 => self.signals.reg_width = RegWidth::ByteUnsigned, + 5 => self.signals.reg_width = RegWidth::HalfWordUnsigned + } + } + } + } + + /// Set the control signals for the datapath, specifically in the + /// case where the instruction is an S-type. + fn set_stype_control_signals(&mut self, s: SType) { + self.signals = ControlSignals { + alu_src: AluSrc::ZeroExtendedImmediate, + branch: Branch::NoBranch, + jump: Jump::NoJump, + mem_read: MemRead::YesRead, + mem_write: MemWrite::NoWrite, + reg_write: RegWrite::NoWrite, + ..Default::default() + }; + + match s.funct3 { + 0 => self.signals.reg_width = RegWidth::Byte, + 1 => self.signals.reg_width = RegWidth::HalfWord, + 2 => self.signals.reg_width = RegWidth::Word, + } + } + + /// Set the control signals for the datapath, specifically in the + /// case where the instruction is an B-type. + fn set_btype_control_signals(&mut self, b: BType) { + self.signals = ControlSignals { + alu_src: AluSrc::ZeroExtendedImmediate, + branch: Branch::YesBranch, + jump: Jump::NoJump, + mem_read: MemRead::NoRead, + mem_write: MemWrite::NoWrite, + reg_write: RegWrite::NoWrite, + reg_width: RegWidth::Word, + ..Default::default() + }; + + match b.funct3 { + 0 => self.signals.branch_type = BranchType::OnEqual, + 1 => self.signals.branch_type = BranchType::OnNotEqual, + 4 => self.signals.branch_type = BranchType::OnLessThan, + 5 => self.signals.branch_type = BranchType::OnGreaterEqual, + 6 => self.signals.branch_type = BranchType::OnLessThanUnsigned, + 7 => self.signals.branch_type = BranchType::OnGreaterEqualUnsigned, + } + } + + /// Set the control signals for the datapath, specifically in the + /// case where the instruction is an U-type. + fn set_utype_control_signals(&mut self, u: UType) { + self.signals = ControlSignals { + alu_src: AluSrc::ZeroExtendedImmediate, + branch: Branch::NoBranch, + jump: Jump::NoJump, + mem_read: MemRead::NoRead, + mem_write: MemWrite::NoWrite, + reg_dst: RegDst::Reg3, + reg_width: RegWidth::Word, + reg_write: RegWrite::YesWrite, + ..Default::default() + }; + + match u.op { + OPCODE_AUIPC => self.signals.mem_to_reg = MemToReg::UseAlu, + OPCODE_LUI => self.signals.mem_to_reg = MemToReg::UseImmediate, + } + } + + /// Set control signals for J-Type instructions + fn set_jtype_control_signals(&mut self, j: JType) { + self.signals = ControlSignals { + alu_src: AluSrc::ZeroExtendedImmediate, + branch: Branch::NoBranch, + jump: Jump::YesJump, + mem_read: MemRead::NoRead, + mem_write: MemWrite::NoWrite, + mem_to_reg: MemToReg::UsePcPlusFour, + reg_write: RegWrite::YesWrite, + ..Default::default() + }; + } + + /// Read the registers as specified from the instruction and pass + /// the data into the datapath. + fn read_registers(&mut self) { + self.state.read_data_1 = self.registers.gpr[self.state.rs1 as usize]; + self.state.read_data_2 = self.registers.gpr[self.state.rs2 as usize]; + + // Truncate the variable data if a 32-bit word is requested. + if let RegWidth::Word = self.signals.reg_width { + self.state.read_data_1 = self.state.read_data_1 as u32 as u64; + self.state.read_data_2 = self.state.read_data_2 as u32 as u64; + } + } + + fn shift_lower_26_left_by_2(&mut self) { + self.state.lower_26_shifted_left_by_2 = self.state.lower_26 << 2; + } + + fn construct_jump_address(&mut self) { + self.state.jump_address = (self.state.pc_plus_4 & 0xffff_ffff_f000_0000) + | self.state.lower_26_shifted_left_by_2 as u64; + } + + // ======================= Execute (EX) ======================= + /// Perform an ALU operation. + /// + /// **Implementation Note:** Unlike the MIPS64 specification, this ALU + /// does not handle exceptions due to integer overflow. + fn alu(&mut self) { + // Left shift the immediate value based on the ImmShift control signal. + let alu_immediate = self.state.sign_extend; + + // Specify the inputs for the operation. The first will always + // be the first register, but the second may be either the + // second register, the sign-extended immediate value, or the + // zero-extended immediate value. + self.state.alu_input1 = self.state.read_data_1; + self.state.alu_input2 = match self.signals.alu_src { + AluSrc::ReadRegister2 => self.state.read_data_2, + AluSrc::SignExtendedImmediate => alu_immediate, + AluSrc::ZeroExtendedImmediate => self.state.imm as u64, + }; + + // Truncate the inputs if 32-bit operations are expected. + if let RegWidth::Word = self.signals.reg_width { + self.state.alu_input1 = self.state.alu_input1 as i32 as u64; + self.state.alu_input2 = self.state.alu_input2 as i32 as u64; + } + + // Set the result. + self.state.alu_result = match self.signals.alu_control { + AluControl::Addition => self.state.alu_input1.wrapping_add(self.state.alu_input2), + AluControl::Subtraction => { + (self.state.alu_input1 as i64).wrapping_sub(self.state.alu_input2 as i64) as u64 + } + AluControl::SetOnLessThanSigned => { + ((self.state.alu_input1 as i64) < (self.state.alu_input2 as i64)) as u64 + } + AluControl::SetOnLessThanUnsigned => { + (self.state.alu_input1 < self.state.alu_input2) as u64 + } + AluControl::And => self.state.alu_input1 & self.state.alu_input2, + AluControl::Or => self.state.alu_input1 | self.state.alu_input2, + AluControl::Xor => self.state.alu_input1 ^ self.state.alu_input2, + AluControl::ShiftLeftLogical(shamt) => self.state.alu_input2 << shamt, + AluControl::ShiftRightLogical(shamt) => self.state.alu_input2 >> shamt, + AluControl::ShiftRightArithmetic(shamt) => (self.state.alu_input2 as i32 >> shamt) as u64, + AluControl::MultiplicationSigned => { + ((self.state.alu_input1 as i128) * (self.state.alu_input2 as i128)) as u64 + } + AluControl::MultiplicationUnsigned => { + ((self.state.alu_input1 as u128) * (self.state.alu_input2 as u128)) as u64 + } + AluControl::DivisionSigned => { + if self.state.alu_input2 == 0 { + 0 + } else { + ((self.state.alu_input1 as i64) / (self.state.alu_input2 as i64)) as u64 + } + } + AluControl::DivisionUnsigned => { + if self.state.alu_input2 == 0 { + 0 + } else { + self.state.alu_input1 / self.state.alu_input2 + } + } + }; + + // Truncate and sign-extend the output if 32-bit operations are expected. + if let RegWidth::Word = self.signals.reg_width { + self.state.alu_result = self.state.alu_result as i32 as i64 as u64; + } + + // Set the zero bit/signal. + self.datapath_signals.alu_z = match self.state.alu_result { + 0 => AluZ::YesZero, + _ => AluZ::NoZero, + }; + } + + fn calc_relative_pc_branch(&mut self) { + self.state.sign_extend_shift_left_by_2 = self.state.sign_extend << 2; + self.state.relative_pc_branch = self + .state + .sign_extend_shift_left_by_2 + .wrapping_add(self.state.pc_plus_4); + } + + /// Determine the value of the [`CpuBranch`] signal. + fn calc_cpu_branch_signal(&mut self) { + // Start by assuming there is no branch. + self.datapath_signals.cpu_branch = CpuBranch::NoBranch; + + // condition_is_true is based on the ALU and the BranchType. This + // is the line between the multiplexer and the AND gate, where the + // AND gate has as input the Branch control signal and said + // multiplexer. + // + // Depending on the branch type, this may use the ALU's Zero signal + // as-is or inverted. + let condition_is_true = match self.signals.branch_type { + BranchType::OnEqual => self.datapath_signals.alu_z == AluZ::YesZero, + BranchType::OnNotEqual => self.datapath_signals.alu_z == AluZ::NoZero, + }; + + if self.signals.branch == Branch::YesBranch && condition_is_true { + self.datapath_signals.cpu_branch = CpuBranch::YesBranch; + } + } + + // ======================= Memory (MEM) ======================= + /// Read from memory based on the address provided by the ALU in + /// [`DatapathState::alu_result`]. Returns the result to [`DatapathState::memory_data`]. + /// Should the address be invalid or otherwise memory cannot be + /// read at the given address, bitwise 0 will be used in lieu of + /// any data. + fn memory_read(&mut self) { + let address = self.state.alu_result; + + // Load memory, first choosing the correct load function by the + // RegWidth control signal, then reading the result from this + // memory access. + self.state.memory_data = match self.signals.reg_width { + RegWidth::Word => self.memory.load_word(address).unwrap_or(0) as u64, + RegWidth::DoubleWord => self.memory.load_double_word(address).unwrap_or(0), + }; + } + + /// Write to memory based on the address provided by the ALU in + /// [`DatapathState::alu_result`]. The source of the data being written to + /// memory is determined by [`MemWriteSrc`]. + fn memory_write(&mut self) { + let address = self.state.alu_result; + + self.state.write_data = self.state.read_data_2; + + // Choose the correct store function based on the RegWidth + // control signal. + match self.signals.reg_width { + RegWidth::Word => { + self.memory + .store_word(address, self.state.write_data as u32) + .ok(); + } + RegWidth::DoubleWord => { + self.memory + .store_double_word(address, self.state.write_data) + .ok(); + } + }; + } + + fn calc_general_branch_signal(&mut self) { + // Assume there is no branch initially. + self.datapath_signals.general_branch = GeneralBranch::NoBranch; + + if let CpuBranch::YesBranch = self.datapath_signals.cpu_branch { + self.datapath_signals.general_branch = GeneralBranch::YesBranch; + return; + } + + if let FpuTakeBranch::YesBranch = self.coprocessor.signals.fpu_take_branch { + self.datapath_signals.general_branch = GeneralBranch::YesBranch; + } + } + + fn pick_pc_plus_4_or_relative_branch_addr_mux1(&mut self) { + if let GeneralBranch::YesBranch = self.datapath_signals.general_branch { + self.state.mem_mux1_to_mem_mux2 = self.state.relative_pc_branch; + } else { + self.state.mem_mux1_to_mem_mux2 = self.state.pc_plus_4; + } + } + + fn set_new_pc_mux2(&mut self) { + self.state.new_pc = match self.signals.jump { + Jump::NoJump => self.state.mem_mux1_to_mem_mux2, + Jump::YesJump => self.state.jump_address, + Jump::YesJumpJalr => self.state.read_data_1, + }; + } + + // ====================== Writeback (WB) ====================== + /// Write to a register. This will only write if the RegWrite + /// control signal is set. + fn register_write(&mut self) { + // Determine what data will be sent to the register: either + // the result from the ALU, or data retrieved from memory. + self.state.data_result = match self.signals.mem_to_reg { + MemToReg::UseAlu => self.state.alu_result, + MemToReg::UseMemory => self.state.memory_data, + MemToReg::UsePcPlusFour => self.state.pc_plus_4, + }; + + // Decide to retrieve data either from the main processor or the coprocessor. + self.state.register_write_data = self.state.data_result; + + // Abort if the RegWrite signal is not set. + if self.signals.reg_write == RegWrite::NoWrite { + return; + } + + // Determine the destination for the data to write. This is + // determined by the RegDst control signal. + self.state.write_register_destination = match self.signals.reg_dst { + RegDst::Reg1 => self.state.rs1 as usize, + RegDst::Reg2 => self.state.rs2 as usize, + RegDst::Reg3 => self.state.rd as usize, + RegDst::ReturnRegister => 31_usize, + }; + + // If we are attempting to write to register $zero, stop. + if self.state.write_register_destination == 0 { + return; + } + + // If a 32-bit word is requested, ensure data is truncated and sign-extended. + if let RegWidth::Word = self.signals.reg_width { + self.state.data_result = self.state.data_result as i32 as u64; + } + + // Write. + self.registers.gpr[self.state.write_register_destination] = self.state.register_write_data; + } + + /// Update the program counter register. + /// + /// This function is called from the WB stage. + fn set_pc(&mut self) { + self.registers.pc = self.state.new_pc; + } +} diff --git a/src/emulation_core/riscv/datapath_signals.rs b/src/emulation_core/riscv/datapath_signals.rs new file mode 100644 index 000000000..a382522e8 --- /dev/null +++ b/src/emulation_core/riscv/datapath_signals.rs @@ -0,0 +1,55 @@ +//! Internal datapath signals. + +#[derive(Clone, Default, PartialEq)] +pub struct DatapathSignals { + pub alu_z: AluZ, + pub cpu_branch: CpuBranch, + pub general_branch: GeneralBranch, +} + +/// The "Zero" line that comes out of the ALU. +/// +/// Indicates whether or not the result of the last arithmetic +/// operation was equal to 0. +#[derive(Clone, Default, PartialEq)] +pub enum AluZ { + /// The result of the ALU is bitwise zero. + #[default] + YesZero = 0, + + /// The result of the ALU is non-zero. + NoZero = 1, +} + +/// CPU branch signal. This is the final determined branch signal from the CPU. +/// +/// This signal uses as input the [`Branch`](super::control_signals::Branch), +/// [`BranchType`](super::control_signals::BranchType), and [`AluZ`] signals to +/// determine its value. This signal is set in the EX stage. +#[derive(Clone, Default, PartialEq)] +pub enum CpuBranch { + /// Do not branch. + /// + /// Based on the following formula: `(Branch != YesBranch) || (AluZ != YesZero)` + #[default] + NoBranch = 0, + + /// Branch. + /// + /// Based on the following formula: `(Branch == YesBranch) && (AluZ == YesZero)` + YesBranch = 1, +} + +/// General branch signal. This is the final determined branch signal from +/// the CPU and FPU combined. +/// +/// This signal uses as input the [`CpuBranch`] and [`FpuBranch`](super::control_signals::floating_point::FpuBranch) signals. +/// This signal is set in the MEM stage. +/// +/// The following formula is considered: [`GeneralBranch`] = [`CpuBranch`] | [`FpuBranch`](super::control_signals::floating_point::FpuBranch) +#[derive(Clone, Default, PartialEq)] +pub enum GeneralBranch { + #[default] + NoBranch = 0, + YesBranch = 1, +} diff --git a/src/emulation_core/riscv/instruction.rs b/src/emulation_core/riscv/instruction.rs new file mode 100644 index 000000000..2d29bbf32 --- /dev/null +++ b/src/emulation_core/riscv/instruction.rs @@ -0,0 +1,167 @@ +//! Abstract representation of an instruction. + +use super::constants::*; + +/// Register (R-Type) Instruction +/// +/// ```text +/// 31 25 24 20 19 15 14 12 11 7 6 0 +/// ┌───────────────┬─────────────┬─────────────┬───────────┬─────────────┬───────────────┐ +/// │ funct7 │ rs2 │ rs1 │ funct3 │ rd │ opcode │ +/// │ │ │ │ │ │ │ +/// └───────────────┴─────────────┴─────────────┴───────────┴─────────────┴───────────────┘ +/// 7 5 5 3 5 7 +/// ``` +/// + +/// - funct7: +/// - rs2: CPU register - used as a source to read from in the register file. +/// - rs1: CPU register - used as a source to read from in the register file. +/// - funct3: +/// - rd: CPU register - can be used as a destination for the result of executed instructions. +/// - opcode: Determines the type of instruction executed. This is typically 0110011 in R-type instructions. +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct RType { + pub funct7: u8, + pub rs2: u8, + pub rs1: u8, + pub funct3: u8, + pub rd: u8, + pub op: u8, +} + +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct IType { + pub imm: u16, + pub rs1: u8, + pub funct3: u8, + pub rd: u8, + pub op: u8, +} + +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct SType { + pub imm1: u8, + pub rs2: u8, + pub rs1: u8, + pub funct3: u8, + pub imm2: u8, + pub op: u8, +} + +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct BType { + pub imm1: u8, + pub rs2: u8, + pub rs1: u8, + pub funct3: u8, + pub imm2: u8, + pub op: u8, +} + +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct UType { + pub imm: u32, + pub rd: u8, + pub op: u8, +} + +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct JType { + pub imm: u32, + pub rd: u8, + pub op: u8, +} + +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct R4Type { + pub rs3: u8, + pub funct2: u8, + pub rs2: u8, + pub rs1: u8, + pub funct3: u8, + pub rd: u8, + pub op: u8, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum Instruction { + RType(RType), + IType(IType), + SType(SType), + BType(BType), + UType(UType), + JType(JType), + R4Type(R4Type), +} + +impl Default for Instruction { + fn default() -> Self { + Instruction::RType(RType::default()) + } +} + +impl TryFrom for Instruction { + type Error = String; + + /// Based on the opcode, convert a binary instruction into a struct representation. + fn try_from(value: u32) -> Result { + let op = (value & 0x7f) as u8; + match op { + // R-type instructions: + OPCODE_OP => Ok(Instruction::RType(RType { + funct7: (value >> 25) as u8, + rs2: ((value >> 20) & 0x1f) as u8, + rs1: ((value >> 15) & 0x1f) as u8, + funct3: ((value >> 12) & 0x07) as u8, + rd: ((value >> 7) & 0x1f) as u8, + op: (value & 0x7f) as u8, + })), + + // I-type instructions: + OPCODE_IMM | OPCODE_JALR | OPCODE_LOAD | OPCODE_SYSTEM => Ok(Instruction::IType(IType { + imm: (value >> 20) as u16, + rs1: ((value >> 15) & 0x1f) as u8, + funct3: ((value >> 12) & 0x07) as u8, + rd: ((value >> 7) & 0x1f) as u8, + op: (value & 0x7f) as u8, + })), + + // S-type instruction: + OPCODE_STORE => Ok(Instruction::SType(SType { + imm1: (value >> 25) as u8, + rs2: ((value >> 20) & 0x1f) as u8, + rs1: ((value >> 15) & 0x1f) as u8, + funct3: ((value >> 12) & 0x07) as u8, + imm2: ((value >> 7) & 0x1f) as u8, + op: (value & 0x7f) as u8, + })), + + // B-type instruction: + OPCODE_BRANCH => Ok(Instruction::BType(BType { + imm1: (value >> 25) as u8, + rs2: ((value >> 20) & 0x1f) as u8, + rs1: ((value >> 15) & 0x1f) as u8, + funct3: ((value >> 12) & 0x07) as u8, + imm2: ((value >> 7) & 0x1f) as u8, + op: (value & 0x7f) as u8, + })), + + // U-type instruction: + OPCODE_LUI | OPCODE_AUIPC => Ok(Instruction::UType(UType { + imm: (value >> 12) as u32, + rd: ((value >> 7) & 0x1f) as u8, + op: (value & 0x7f) as u8, + })), + + // J-type instruction: + OPCODE_JAL => Ok(Instruction::JType(JType { + imm: (value >> 12) as u32, + rd: ((value >> 7) & 0x1f) as u8, + op: (value & 0x7f) as u8, + })), + + _ => Err(format!("opcode `{op}` not supported")), + } + } +} diff --git a/src/emulation_core/riscv/line_info.rs b/src/emulation_core/riscv/line_info.rs new file mode 100644 index 000000000..c28c0a8aa --- /dev/null +++ b/src/emulation_core/riscv/line_info.rs @@ -0,0 +1,334 @@ +//! Module for mapping lines in the visual datapath to information +//! and variables in the coded datapath. + +use super::super::datapath::VisualDatapath; +use super::datapath::MipsDatapath; + +/// A collection of data surrounding a line in the visual datapath. +pub struct LineInformation { + pub title: String, + pub description: String, + + /// The value stored in a line. This may not be a 64-bit value, but should + /// refer to the `bits` field to determine how many bits on the line are + /// relevant to be displayed. + pub value: u64, + + /// The number of bits on a given line. + pub bits: u64, +} + +impl VisualDatapath for MipsDatapath { + type LineInformation = LineInformation; + + fn visual_line_to_data(&self, variable: &str) -> LineInformation { + match variable { + "alu_input2" => LineInformation { + title: String::from("ALU Input 2"), + description: String::from("The second input to the ALU. This is determined by the ALUSrc control signal to select between register data, a sign-extended and left-shifted immediate value, or a zero-extended immediate value."), + value: self.state.alu_input2, + bits: 64, + }, + "alu_result" => LineInformation { + title: String::from("ALU Result"), + description: String::from("The result of the calculation performed by the ALU. This is used either as an address to access memory or as a value that is saved into a register."), + value: self.state.alu_result, + bits: 64, + }, + "data_result" => LineInformation { + title: String::from("Writeback Data"), + description: String::from("After finishing processing the instruction, this will either be the ALU result, data from memory, or PC + 4, based on the MemToReg control signal. This data is saved into registers."), + value: self.state.data_result, + bits: 64, + }, + "fpu_alu_result" => LineInformation { + title: String::from("Floating-Point ALU Result"), + description: String::from("The result of the calculation performed by the floating-point ALU. This is used as an option to be written to a floating-point register, based on the DataWrite and FpuMemToReg control signals."), + value: self.coprocessor.state.alu_result, + bits: 64, + }, + "fpu_branch_decision" => LineInformation { + title: String::from("FPU Branch Decision"), + description: String::from("Based on the true/false branch flag, determines whether to branch. (The FpuBranch control signal must also be set.)"), + value: self.coprocessor.state.condition_code_mux as u64, + bits: 1, + }, + "fpu_branch_flag" => LineInformation { + title: String::from("Instruction [16] (True/False Branch Flag)"), + description: String::from("The true/false branch flag of branching coprocessor instructions. This flag specifies whether a floating-point branch instruction is BC1T or BC1F."), + value: self.coprocessor.state.branch_flag as u64, + bits: 1, + }, + "fpu_comparator_result" => LineInformation { + title: String::from("Floating-Point Comparator Result"), + description: String::from("The result of the comparison of two floating-point values. This is routed to the \"Condition Code\" (cc) register, and will be written there if the CcWrite control signal is set."), + value: self.coprocessor.state.comparator_result, + bits: 64, + }, + "fpu_condition_code" => LineInformation { + title: String::from("Condition Code Value"), + description: String::from("Data retrieved from the \"Condition Code\" (cc) register. This specifies whether a previous conditional instruction was true or false."), + value: self.coprocessor.state.condition_code_bit as u64, + bits: 1, + }, + "fpu_condition_code_inverted" => LineInformation { + title: String::from("Condition Code Value (Inverted)"), + description: String::from("Inverted form of the condition code register value."), + value: self.coprocessor.state.condition_code_bit_inverted as u64, + bits: 1, + }, + "fpu_data" => LineInformation { + title: String::from("Floating-Point Data Register Value"), + description: String::from("Data retrieved from the \"Data\" register. This register acts as a means to communicate data between the main processor and floating-point coprocessor in MTC1 and MFC1 instructions."), + value: self.coprocessor.state.fmt as u64, + bits: 64, + }, + "fpu_data_writeback" => LineInformation { + title: String::from("Floating-Point Data Writeback"), + description: String::from("The value from the floating-point unit's \"Data\" register. Depending on the FpuRegWidth control signal, this will be 64-bit data or sign-extended 32-bit data."), + value: self.coprocessor.state.data_writeback, + bits: 64, + }, + "fpu_destination" => LineInformation { + title: String::from("Floating-Point Write Register"), + description: String::from("The register that will be written to, assuming FpuRegWrite is set. Depending on the FpuRegDst control signal, this will consist of the fs, ft, or fd register."), + value: self.coprocessor.state.destination as u64, + bits: 5, + }, + "fpu_fd" => LineInformation { + title: String::from("Instruction [10-6] (fd)"), + description: String::from("The fd field. Depending on the FpuRegDst control signal, this will be the register written to in a floating-point operation. This register is used as the destination for most floating-point arithmetic instructions."), + value: self.coprocessor.state.fd as u64, + bits: 5, + }, + "fpu_fmt" => LineInformation { + title: String::from("Instruction [25-21] (fmt)"), + description: String::from("The fmt field. This is used to distinguish between single-precision and double-precision floating-point instructions."), + value: self.coprocessor.state.fmt as u64, + bits: 5, + }, + "fpu_fp_register_data_from_main_processor" => LineInformation { + title: String::from("Writeback Data (To Floating-Point Coprocessor)"), + description: String::from("This data is written to a floating-point register, given FpuMemToReg is set. This line allows data to load from memory to a floating-point register, specifically in the case of the LWC1 instruction."), + value: self.coprocessor.state.fp_register_data_from_main_processor, + bits: 64, + }, + "fpu_fp_register_to_memory" => LineInformation { + title: String::from("Memory Write Data (from FPU)"), + description: String::from("If the MemWriteSrc control signal is set, this data will be written to memory. This is used for the SWC1 instruction."), + value: self.coprocessor.state.fp_register_to_memory, + bits: 64, + }, + "fpu_fs" => LineInformation { + title: String::from("Instruction [15-11] (fs)"), + description: String::from("The fs field. Contains the first register to be read for a floating-point instruction."), + value: self.coprocessor.state.fs as u64, + bits: 5, + }, + "fpu_ft" => LineInformation { + title: String::from("Instruction [20-16] (ft)"), + description: String::from("The ft field. Contains the second register to be read for a floating-point instruction."), + value: self.coprocessor.state.ft as u64, + bits: 5, + }, + "fpu_new_data" => LineInformation { + title: String::from("New Floating-Point Data Register Value"), + description: String::from("Data sent to the \"Data\" register. Depending on the DataSrc control signal, this will either be data from the main processor or the floating-point coprocessor. This register acts as a means to communicate data between the main processor and floating-point coprocessor in MTC1 and MFC1 instructions."), + value: self.coprocessor.state.fmt as u64, + bits: 64, + }, + "fpu_read_data_1" => LineInformation { + title: String::from("FPU Read Data 1"), + description: String::from("Data retrieved from the register specified by the fs instruction field. This is used as the first inputs to the floating-point ALU and comparator. This can additionally be written to the \"Data\" register, based on the DataSrc and DataWrite control signals."), + value: self.coprocessor.state.read_data_1, + bits: 64, + }, + "fpu_read_data_2" => LineInformation { + title: String::from("FPU Read Data 2"), + description: String::from("Data retrieved from the register specified by the ft instruction field. This is used as the second inputs to the floating-point ALU and comparator. This can additionally be used as data to be written to memory, based on the MemWriteSrc control signal."), + value: self.coprocessor.state.read_data_2, + bits: 64, + }, + "fpu_register_write_data" => LineInformation { + title: String::from("FPU Register Write Data"), + description: String::from("Data that will be written to a floating-point register, given that FpuRegWrite is set."), + value: self.coprocessor.state.register_write_data, + bits: 64, + }, + "fpu_register_write_mux_to_mux" => LineInformation { + title: String::from("FPU Register Write Data (When FpuMemToReg is Unset)"), + description: String::from("Based on the DataWrite control signal, this will either be the result of the floating-point ALU or the contents of the \"Data\" register. (The \"Data\" register is used for transferring data between the processor and floating-point coprocessor.)"), + value: self.coprocessor.state.register_write_mux_to_mux, + bits: 64, + }, + "fpu_sign_extend_data" => LineInformation { + title: String::from("Floating-Point Data Register Value (Sign-Extended)"), + description: String::from("In the case where FpuRegWidth indicates a 32-bit width, this is the bottom 32 bits of the value from the \"Data\" register, then sign-extended to 64 bits."), + value: self.coprocessor.state.sign_extend_data, + bits: 64, + }, + "funct" => LineInformation { + title: String::from("Instruction [5-0] (funct)"), + description: String::from("The funct field. Contains the type of operation to execute for R-type instructions."), + value: self.state.funct as u64, + bits: 6, + }, + "imm" => LineInformation { + title: String::from("Instruction [15-0] (immediate)"), + description: String::from("The immediate field. Contains the 16-bit constant value used for I-type instructions."), + value: self.state.imm as u64, + bits: 16, + }, + "instruction" => LineInformation { + title: String::from("Instruction"), + description: String::from("The currently-loaded instruction. This is broken down into different fields, where each field serves a different purpose in identifying what the instruction does."), + value: self.state.instruction as u64, + bits: 32, + }, + "jump_address" => LineInformation { + title: String::from("Jump Address"), + description: String::from("The concatenation of the upper 36 bits of PC + 4 with the lower 26 bits of the instruction, shifted left by 2. This is used as the new PC value for J-type instructions."), + value: self.state.jump_address, + bits: 64, + }, + "lower_26" => LineInformation { + title: String::from("Instruction [25-0]"), + description: String::from("The lower 26 bits of instruction. This is used as part of the new PC value for J-type instructions."), + value: self.state.lower_26 as u64, + bits: 26, + }, + "lower_26_shifted_left_by_2" => LineInformation { + title: String::from("Instruction [25-0] << 2"), + description: String::from("The lower 26 bits of instruction, shifted left by 2. This is used as part of the new PC value for J-type instructions."), + value: self.state.lower_26_shifted_left_by_2 as u64, + bits: 28, + }, + "mem_mux1_to_mem_mux2" => LineInformation { + title: String::from("Relative PC Address"), + description: String::from("Based on the control signals for branching and jumping, this address may be the next PC value. This is used for general non-branching instructions or branch-type instructions."), + value: self.state.mem_mux1_to_mem_mux2, + bits: 64, + }, + "memory_data" => LineInformation { + title: String::from("Memory Data"), + description: String::from("The data retrieved from memory, given that the MemRead control signal is set. This may be 32 bits or 64 bits, depending on the RegWidth control signal."), + value: self.state.memory_data, + bits: 64, + }, + "new_pc" => LineInformation { + title: String::from("New Program Counter"), + description: String::from("The address of the next instruction to execute. In other words, the next value of the program counter (PC) register."), + value: self.state.new_pc, + bits: 64, + }, + "pc" => LineInformation { + title: String::from("Program Counter"), + description: String::from("The address of the currently-executing instruction."), + value: self.registers.pc, + bits: 64, + }, + "pc_plus_4" => LineInformation { + title: String::from("PC + 4"), + description: String::from("The address of the currently-executing instruction, plus 4. By default, this will become the next value of the PC register. However, a different address may be used in the case of a branch or jump instruction."), + value: self.state.pc_plus_4, + bits: 64, + }, + "pc_plus_4_upper" => LineInformation { + title: String::from("PC + 4 [63-28]"), + description: String::from("The upper 36 bits of PC + 4. This is to be concatenated with the lower 26 bits of the instruction to calculate a jump address."), + value: self.state.pc_plus_4 & 0xffff_ffff_f000_0000 >> 28, + bits: 36, + }, + "ra_id" => LineInformation { + title: String::from("Return Address Register Index"), + description: String::from("The value 31. This represents the thirty-second register, the return address register ($ra)."), + value: 31, + bits: 5, + }, + "rd" => LineInformation { + title: String::from("Instruction [15-11] (rd)"), + description: String::from("The rd field. Depending on the RegDst control signal, this will be the register written to for an instruction. This register is used as the destination for most R-type instructions."), + value: self.state.rd as u64, + bits: 5, + }, + "read_data_1" => LineInformation { + title: String::from("Read Data 1"), + description: String::from("Data retrieved from the register specified by the rs instruction field. Based on the instruction, this may be used as the first input to the ALU, or the next value of the PC register."), + value: self.state.read_data_1, + bits: 64, + }, + "read_data_2" => LineInformation { + title: String::from("Read Data 2"), + description: String::from("Data retrieved from the register specified by the rt instruction field. Based on the instruction, this may be used as the second input to the ALU, data written to memory, or data transferred to the floating-point coprocessor."), + value: self.state.read_data_2, + bits: 64, + }, + "register_write_data" => LineInformation { + title: String::from("Register Write Data"), + description: String::from("Data that will be written to a general-purpose register, given that RegWrite is set."), + value: self.state.register_write_data, + bits: 64, + }, + "relative_pc_branch" => LineInformation { + title: String::from("Relative PC Branch Address"), + description: String::from("The relative address used in branch instructions. This is the sum of PC + 4 and the sign-extended immediate value, shifted left by 2."), + value: self.state.relative_pc_branch, + bits: 64, + }, + "rs" => LineInformation { + title: String::from("Instruction [25-21] (rs)"), + description: String::from("The rs field. Contains the first register to be read for an instruction."), + value: self.state.rs as u64, + bits: 5, + }, + "rt" => LineInformation { + title: String::from("Instruction [20-16] (rt)"), + description: String::from("The rt field. Contains the second register to be read for an instruction."), + value: self.state.rt as u64, + bits: 5, + }, + "shamt" => LineInformation { + title: String::from("Instruction [10-6] (shamt)"), + description: String::from("The shamt (\"shift amount\") field. Specifies the number of bits to shift for those instructions that perform bit-shifting."), + value: self.state.shamt as u64, + bits: 5, + }, + "sign_extend" => LineInformation { + title: String::from("Sign-Extended Immediate"), + description: String::from("The immediate field, sign-extended to a 64-bit value."), + value: self.state.sign_extend, + bits: 64, + }, + "sign_extend_shift_left_by_2" => LineInformation { + title: String::from("Sign-Extended Immediate << 2"), + description: String::from("The immediate field, sign-extended to a 64-bit value, then shifted left by 2."), + value: self.state.sign_extend_shift_left_by_2, + bits: 64, + }, + "write_data" => LineInformation { + title: String::from("Memory Write Data"), + description: String::from("Given that the MemWrite control signal is set, this data will be written to memory."), + value: self.state.write_data, + bits: 64, + }, + "write_register" => LineInformation { + title: String::from("Write Register"), + description: String::from("The register that will be written to, assuming RegWrite is set. Depending on the RegDst control signal, this will consist of the rs, rt, or rd register, or 31 (indicating the $ra register)."), + value: self.state.write_register_destination as u64, + bits: 5, + }, + "zero_extended_immediate" => LineInformation { + title: String::from("Zero-Extended Immediate"), + description: String::from("The immediate field, zero-extended to a 64-bit value."), + value: self.state.imm as u64, + bits: 64, + }, + _ => LineInformation { + title: String::from("[Title]"), + description: String::from("[Description]"), + value: 0, + bits: 0, + }, + } + } +} diff --git a/src/emulation_core/riscv/memory.rs b/src/emulation_core/riscv/memory.rs new file mode 100644 index 000000000..2abcf1921 --- /dev/null +++ b/src/emulation_core/riscv/memory.rs @@ -0,0 +1,145 @@ +//! Data and instruction memory implementation and API. + +// pub const CAPACITY_BYTES: usize = 2^12; // 4KB +pub const CAPACITY_BYTES: usize = 64 * 1024; // 64 KB + +#[derive(Clone, Debug, PartialEq)] +pub struct Memory { + pub memory: Vec, +} + +impl Default for Memory { + fn default() -> Self { + Self { + memory: vec![0; CAPACITY_BYTES], + } + } +} + +impl ToString for Memory { + fn to_string(&self) -> String { + let mut output = String::new(); + + for byte in self.memory.iter() { + output.push_str(&format!("{byte:02x}")); + } + + output + } +} + +impl Memory { + /// Determines if an address is valid in a given instance of Memory. + /// If invalid, returns an instance of Err describing the problem with + /// the address. + fn check_valid_address(&self, address: usize) -> Result<(), String> { + if address % 4 != 0 { + Err(format!("Address `{address}` is not word-aligned")) + } else if address >= self.memory.len() { + Err(format!( + "Address `{}` out of bounds of memory of size {}", + address, + self.memory.len() + )) + } else { + Ok(()) + } + } + + // A word is 32 bits. + pub fn store_word(&mut self, address: u64, data: u32) -> Result<(), String> { + let address = address as usize; + + self.check_valid_address(address)?; + + self.memory[address] = ((data >> 24) & 0b11111111) as u8; + self.memory[address + 1] = ((data >> 16) & 0b11111111) as u8; + self.memory[address + 2] = ((data >> 8) & 0b11111111) as u8; + self.memory[address + 3] = (data & 0b11111111) as u8; + + Ok(()) + } + + pub fn store_double_word(&mut self, address: u64, data: u64) -> Result<(), String> { + // Storing a doubleword is the same as storing two words. + let data_upper = (data >> 32) as u32; + let data_lower = data as u32; + + self.store_word(address, data_upper)?; + self.store_word(address + 4, data_lower)?; + + Ok(()) + } + + // A word is 32 bits. + pub fn load_word(&self, address: u64) -> Result { + let address = address as usize; + + self.check_valid_address(address)?; + + let mut result: u32 = 0; + result |= (self.memory[address] as u32) << 24; + result |= (self.memory[address + 1] as u32) << 16; + result |= (self.memory[address + 2] as u32) << 8; + result |= self.memory[address + 3] as u32; + + Ok(result) + } + + pub fn load_double_word(&self, address: u64) -> Result { + // Loading a doubleword is the same as loading two words. + let mut result: u64 = 0; + + // Get the upper 32 bits of the doubleword. + match self.load_word(address) { + Ok(upper_data) => { + result |= (upper_data as u64) << 32; + } + Err(e) => return Err(e), + } + + // Get the lower 32 bits of the doubleword. + match self.load_word(address + 4) { + Ok(lower_data) => { + result |= lower_data as u64; + } + Err(e) => return Err(e), + } + + Ok(result) + } + + pub fn generate_formatted_hex(&self) -> String { + let mut string: String = "".to_string(); + + let mut base = 0; + while base < self.memory.len() { + string.push_str(&format!("0x{base:04x}:\t\t")); + let mut char_version: String = "".to_string(); + + for offset in 0..4 { + let word_address = base as u64 + (offset * 4); + if let Ok(word) = self.load_word(word_address) { + string.push_str(&format!("{word:08x}\t")); + char_version.push_str(&convert_word_to_chars(word)) + }; + } + string.push_str(&format!("{char_version}\n")); + base += 16; + } + string + } +} + +fn convert_word_to_chars(word: u32) -> String { + let mut chars = "".to_string(); + for shift in (0..4).rev() { + let byte = (word >> (shift * 8)) as u8; + if byte > 32 && byte < 127 { + chars.push(byte as char); + } else { + chars.push('.'); + } + } + chars +} diff --git a/src/emulation_core/riscv/registers.rs b/src/emulation_core/riscv/registers.rs new file mode 100644 index 000000000..16a23b61e --- /dev/null +++ b/src/emulation_core/riscv/registers.rs @@ -0,0 +1,221 @@ +//! Register structure and API. + +use std::ops::{Index, IndexMut}; +use std::str::FromStr; +use strum::IntoEnumIterator; +use strum_macros::{Display, EnumIter, EnumString}; + +/// Collection of general-purpose registers used by the datapath. +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct GpRegisters { + pub pc: u64, + pub gpr: [u64; 32], +} + +/// Specifies all of the valid registers accessible in an instance +/// of [`GpRegisters`]. +#[derive(Clone, Copy, Debug, Display, EnumIter, EnumString, Eq, PartialEq)] +#[strum(ascii_case_insensitive)] +#[strum(serialize_all = "lowercase")] +pub enum GpRegisterType { + Pc = -1, + X0 = 0, + X1 = 1, + X2 = 2, + X3 = 3, + X4 = 4, + X5 = 5, + X6 = 6, + X7 = 7, + X8 = 8, + X9 = 9, + X10 = 10, + X11 = 11, + X12 = 12, + X13 = 13, + X14 = 14, + X15 = 15, + X16 = 16, + X17 = 17, + X18 = 18, + X19 = 19, + X20 = 20, + X21 = 21, + X22 = 22, + X23 = 23, + X24 = 24, + X25 = 25, + X26 = 26, + X27 = 27, + X28 = 28, + X29 = 29, + X30 = 30, + X31 = 31, +} + +impl ToString for GpRegisters { + fn to_string(&self) -> String { + let mut output = String::new(); + + output.push_str(&format!("PC = {}\n", self.pc)); + + let gpr_registers = self + .gpr + .iter() + .enumerate() + .map(|(i, inst)| format!("gpr[{i}] = {inst}")) + .collect::>() + .join("\n"); + output.push_str(&gpr_registers); + + output + } +} + +impl Index<&str> for GpRegisters { + type Output = u64; + + // Convert string to the corresponding RegistersEnum value and use this to index. + // If this is an invalid string, no enum will be returned, causing a panic as desired. + fn index(&self, index: &str) -> &Self::Output { + match GpRegisterType::from_str(index) { + Ok(register) => &self[register], + _ => panic!("{index} is not a valid register"), + } + } +} + +impl IndexMut<&str> for GpRegisters { + // Convert string to the corresponding RegistersEnum value and use this to index. + // If this is an invalid string, no enum will be returned, causing a panic as desired. + fn index_mut(&mut self, index: &str) -> &mut Self::Output { + match GpRegisterType::from_str(index) { + Ok(register) => &mut self[register], + _ => panic!("{index} is not a valid register"), + } + } +} + +impl Index for GpRegisters { + type Output = u64; + + fn index(&self, index: GpRegisterType) -> &Self::Output { + match index { + GpRegisterType::Pc => &self.pc, + GpRegisterType::X0 => &self.gpr[0], + GpRegisterType::X1 => &self.gpr[1], + GpRegisterType::X2 => &self.gpr[2], + GpRegisterType::X3 => &self.gpr[3], + GpRegisterType::X4 => &self.gpr[4], + GpRegisterType::X5 => &self.gpr[5], + GpRegisterType::X6 => &self.gpr[6], + GpRegisterType::X7 => &self.gpr[7], + GpRegisterType::X8 => &self.gpr[8], + GpRegisterType::X9 => &self.gpr[9], + GpRegisterType::X10 => &self.gpr[10], + GpRegisterType::X11 => &self.gpr[11], + GpRegisterType::X12 => &self.gpr[12], + GpRegisterType::X13 => &self.gpr[13], + GpRegisterType::X14 => &self.gpr[14], + GpRegisterType::X15 => &self.gpr[15], + GpRegisterType::X16 => &self.gpr[16], + GpRegisterType::X17 => &self.gpr[17], + GpRegisterType::X18 => &self.gpr[18], + GpRegisterType::X19 => &self.gpr[19], + GpRegisterType::X20 => &self.gpr[20], + GpRegisterType::X21 => &self.gpr[21], + GpRegisterType::X22 => &self.gpr[22], + GpRegisterType::X23 => &self.gpr[23], + GpRegisterType::X24 => &self.gpr[24], + GpRegisterType::X25 => &self.gpr[25], + GpRegisterType::X26 => &self.gpr[26], + GpRegisterType::X27 => &self.gpr[27], + GpRegisterType::X28 => &self.gpr[28], + GpRegisterType::X29 => &self.gpr[29], + GpRegisterType::X30 => &self.gpr[30], + GpRegisterType::X31 => &self.gpr[31], + } + } +} + +impl IndexMut for GpRegisters { + fn index_mut(&mut self, index: GpRegisterType) -> &mut Self::Output { + match index { + GpRegisterType::Pc => &mut self.pc, + GpRegisterType::X0 => panic!("The $zero register cannot be accessed as mutable"), + GpRegisterType::X1 => &mut self.gpr[1], + GpRegisterType::X2 => &mut self.gpr[2], + GpRegisterType::X3 => &mut self.gpr[3], + GpRegisterType::X4 => &mut self.gpr[4], + GpRegisterType::X5 => &mut self.gpr[5], + GpRegisterType::X6 => &mut self.gpr[6], + GpRegisterType::X7 => &mut self.gpr[7], + GpRegisterType::X8 => &mut self.gpr[8], + GpRegisterType::X9 => &mut self.gpr[9], + GpRegisterType::X10 => &mut self.gpr[10], + GpRegisterType::X11 => &mut self.gpr[11], + GpRegisterType::X12 => &mut self.gpr[12], + GpRegisterType::X13 => &mut self.gpr[13], + GpRegisterType::X14 => &mut self.gpr[14], + GpRegisterType::X15 => &mut self.gpr[15], + GpRegisterType::X16 => &mut self.gpr[16], + GpRegisterType::X17 => &mut self.gpr[17], + GpRegisterType::X18 => &mut self.gpr[18], + GpRegisterType::X19 => &mut self.gpr[19], + GpRegisterType::X20 => &mut self.gpr[20], + GpRegisterType::X21 => &mut self.gpr[21], + GpRegisterType::X22 => &mut self.gpr[22], + GpRegisterType::X23 => &mut self.gpr[23], + GpRegisterType::X24 => &mut self.gpr[24], + GpRegisterType::X25 => &mut self.gpr[25], + GpRegisterType::X26 => &mut self.gpr[26], + GpRegisterType::X27 => &mut self.gpr[27], + GpRegisterType::X28 => &mut self.gpr[28], + GpRegisterType::X29 => &mut self.gpr[29], + GpRegisterType::X30 => &mut self.gpr[30], + GpRegisterType::X31 => &mut self.gpr[31], + } + } +} + +/// Iterator that is used to view each register in the register file. +/// +/// This contains a copy of all the registers and their values, and a [`GpRegisterTypeIter`], +/// as generated by [`strum::IntoEnumIterator`]. In other iterator implementations, +/// the internal state might be data like a [`GpRegisterType`]. However, since we can't +/// normally just "add 1" to get to the next register, we use an internal iterator +/// that can track the progression of one [`GpRegisterType`] to the next. +pub struct GpRegistersIter { + registers: GpRegisters, + register_iter: GpRegisterTypeIter, +} + +/// This implementation of the [`Iterator`] trait essentially wraps the existing +/// [`GpRegisterTypeIter`] so that the register type can be paired with register data. +impl Iterator for GpRegistersIter { + type Item = (GpRegisterType, u64); + + fn next(&mut self) -> Option { + match self.register_iter.next() { + Some(register_type) => Some((register_type, self.registers[register_type])), + None => None, + } + } +} + +/// [`IntoIterator`] is a standard library trait that can convert any type into +/// an [`Iterator`]. In this case, this is an instance of [`GpRegistersIter`] with all the +/// data in the registers and a new [`GpRegisterTypeIter`]. +impl IntoIterator for GpRegisters { + type Item = (GpRegisterType, u64); + type IntoIter = GpRegistersIter; + + /// Consumes the [`GpRegisters`] struct to create a new [`GpRegistersIter`] that can + /// be iterated over. + fn into_iter(self) -> Self::IntoIter { + GpRegistersIter { + registers: self, + register_iter: GpRegisterType::iter(), + } + } +} From 50d8fd163db4550174d8fa713cecaf0f74e723e6 Mon Sep 17 00:00:00 2001 From: Cay Date: Thu, 1 Feb 2024 00:07:31 -0500 Subject: [PATCH 021/355] Move SwimEditor component into its own module --- src/bin/main.rs | 199 ++--------------------------- src/emulation_core/mips/memory.rs | 33 +++++ src/ui.rs | 6 +- src/ui/assembled_view/component.rs | 64 +++++----- src/ui/hex_editor/component.rs | 58 ++------- src/ui/regview/component.rs | 7 +- src/ui/swim_editor/component.rs | 145 +++++++++++++++++++++ src/ui/swim_editor/mod.rs | 1 + 8 files changed, 244 insertions(+), 269 deletions(-) create mode 100644 src/ui/swim_editor/component.rs create mode 100644 src/ui/swim_editor/mod.rs diff --git a/src/bin/main.rs b/src/bin/main.rs index 9076c5e8f..d03c45299 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -7,12 +7,12 @@ use monaco::{ api::TextModel, sys::{ editor::{ - IEditorMinimapOptions, IEditorScrollbarOptions, IMarkerData, IModelDecorationOptions, - IModelDeltaDecoration, IStandaloneEditorConstructionOptions, ISuggestOptions, ScrollType, + IMarkerData, + IModelDecorationOptions, + IModelDeltaDecoration, }, IMarkdownString, MarkerSeverity, - }, - yew::{CodeEditor, CodeEditorLink}, + } }; use swim::parser::parser_assembler_main::parser; use swim::parser::parser_structs_and_enums::ProgramInfo; @@ -24,15 +24,13 @@ use swim::emulation_core::mips::datapath::MipsDatapath; use swim::emulation_core::mips::datapath::Stage; use swim::ui::console::component::Console; use swim::ui::regview::component::Regview; -use swim::ui::assembled_view::component::{TextSegment, DataSegment}; -use swim::ui::hex_editor::component::generate_formatted_hex; +use swim::ui::swim_editor::component::SwimEditor; use wasm_bindgen::{JsCast, JsValue}; use wasm_bindgen_futures::spawn_local; use web_sys::HtmlInputElement; use yew::prelude::*; use yew::{html, Html, Properties}; use log::Level; -use std::cell::RefCell; use yew_agent::Spawnable; use yew_hooks::prelude::*; @@ -69,8 +67,8 @@ fn app(props: &AppProps) -> Html { // was executed after the execute button is pressed. let executed_line = js_sys::Array::new(); let not_highlighted = js_sys::Array::new(); - let curr_line = Rc::new(RefCell::new(0.0)); - let memory_curr_line = Rc::new(RefCell::new(0.0)); + let curr_line = use_mut_ref(|| 0.0); + let memory_curr_line = use_mut_ref(|| 0.0); // Setting up the options/parameters which // will highlight the previously executed line. @@ -99,36 +97,6 @@ fn app(props: &AppProps) -> Html { let memory_text_model = use_mut_ref(|| TextModel::create(&memory_text_output, Some("ini"), None).unwrap()); - // let on_did_change_content_handler = { - // let memory_text_model = Rc::clone(&memory_text_model); - // Callback::from(move |e: &IModelContentChangedEvent| { - - // // handle the event - // }) - // }; - - // use_effect_with_deps( - // move |_| { - - // let memory_text_model = Rc::clone(&memory_text_model); - // let curr_memory_model = memory_text_model.borrow_mut().as_ref(); - // // create a JavaScript closure that calls the Yew callback - // let cb: Closure = Closure::new(move |event: Event| { - // // Inside the Closure, call the Yew callback - // if let Some(event) = event.dyn_ref::() { - // on_did_change_content_handler.emit(event); - // } - // }); - // let cb_func = cb.as_ref().unchecked_ref(); - - // // pass the &js_sys::Function to the on_did_change_content method - // curr_memory_model.on_did_change_content(cb_func); - - // cb.forget(); - // }, - // (), - // ); - // Since we want the Datapath to be independent from all the // events within the app, we will create it when the app loads. This is also done // since the scope will be open across all events involved with it. To achieve this, @@ -136,39 +104,6 @@ fn app(props: &AppProps) -> Html { // the ability to access and change its contents be mutable. let datapath = use_mut_ref(MipsDatapath::default); - let link = CodeEditorLink::new(); - - let on_editor_created = { - let text_model = Rc::clone(&text_model); - let curr_line = Rc::clone(&curr_line); - let lines_content = Rc::clone(&lines_content); - - use_callback( - move |editor_link: CodeEditorLink, _text_model| { - let curr_line = curr_line.borrow_mut(); - match editor_link.with_editor(|editor| { - let raw_editor = editor.as_ref(); - let model = raw_editor.get_model().unwrap(); - // store each line from the original code editor's contents for assembled view - let js_lines = model.get_lines_content(); - let mut string_lines = lines_content.borrow_mut(); - for js_string in js_lines.into_iter() { - let string_value = match js_string.as_string() { - Some(string) => string, - None => String::from("") - }; - string_lines.push(string_value); - - }; - raw_editor.reveal_line_in_center(*curr_line, Some(ScrollType::Smooth)); - }) { - Some(()) => debug!("Editor linked!"), - None => debug!("No editor :<") - }; - }, - text_model, - ) - }; // Start listening for messages from the communicator. This effectively links the worker thread to the main thread // and will force updates whenever its internal state changes. { @@ -261,7 +196,7 @@ fn app(props: &AppProps) -> Html { } // log!(datapath.memory.to_string()); text_model.set_value(&program_info.updated_monaco_string); // Expands pseudo-instructions to their hardware counterpart. - let hexdump = &generate_formatted_hex(&datapath.memory); + let hexdump = &datapath.memory.generate_formatted_hex(); memory_text_model.set_value(hexdump); last_memory_text_model.set_value(hexdump); datapath.registers.pc = program_info.pc_starting_point as u64; @@ -352,7 +287,7 @@ fn app(props: &AppProps) -> Html { datapath.execute_instruction(); // Update memory - let hexdump = &generate_formatted_hex(&datapath.memory); + let hexdump = &datapath.memory.generate_formatted_hex(); memory_text_model.set_value(hexdump); last_memory_text_model.set_value(hexdump); @@ -425,7 +360,7 @@ fn app(props: &AppProps) -> Html { } // Update memory - let hexdump = &generate_formatted_hex(&datapath.memory); + let hexdump = &datapath.memory.generate_formatted_hex(); memory_text_model.set_value(hexdump); last_memory_text_model.set_value(hexdump); @@ -529,7 +464,7 @@ fn app(props: &AppProps) -> Html { } } - let hexdump = &generate_formatted_hex(&datapath.memory); + let hexdump = &datapath.memory.generate_formatted_hex(); memory_text_model.set_value(hexdump); last_memory_text_model.set_value(hexdump); @@ -717,7 +652,7 @@ fn app(props: &AppProps) -> Html { // Editor
- +
// Console @@ -725,7 +660,7 @@ fn app(props: &AppProps) -> Html {
// Right column - +
} @@ -736,114 +671,6 @@ fn new_object() -> JsValue { js_sys::Object::new().into() } -/********************** Editor Component **********************/ - -#[derive(PartialEq, Properties)] -pub struct SwimEditorProps { - pub text_model: TextModel, - pub link: CodeEditorLink, - pub on_editor_created: Callback, - pub lines_content: Rc>>, - pub program_info: ProgramInfo, - pub binary: Vec, - pub memory_curr_line: Rc>, - pub pc: u64 -} - -#[derive(Default, PartialEq)] -enum EditorTabState { - #[default] - Editor, - TextSegment, - DataSegment -} - -fn get_options() -> IStandaloneEditorConstructionOptions { - let options = IStandaloneEditorConstructionOptions::default(); - options.set_theme("vs-dark".into()); - options.set_language("mips".into()); - options.set_scroll_beyond_last_line(false.into()); - options.set_automatic_layout(true.into()); - - let minimap = IEditorMinimapOptions::default(); - minimap.set_enabled(false.into()); - options.set_minimap(Some(&minimap)); - - let scrollbar = IEditorScrollbarOptions::default(); - scrollbar.set_always_consume_mouse_wheel(false.into()); - options.set_scrollbar(Some(&scrollbar)); - - let suggest = ISuggestOptions::default(); - suggest.set_show_keywords(false.into()); - suggest.set_show_variables(false.into()); - suggest.set_show_icons(false.into()); - suggest.set_show_words(false.into()); - suggest.set_filter_graceful(false.into()); - options.set_suggest(Some(&suggest)); - - options -} - -#[function_component] -pub fn SwimEditor(props: &SwimEditorProps) -> Html { - let active_tab = use_state_eq(EditorTabState::default); - let change_tab = { - let active_tab = active_tab.clone(); - Callback::from(move |event: MouseEvent| { - let target = event.target().unwrap().dyn_into::().unwrap(); - let tab_name = target - .get_attribute("label") - .unwrap_or(String::from("editor")); - - let new_tab: EditorTabState = match tab_name.as_str() { - "editor" => EditorTabState::Editor, - "text" => EditorTabState::TextSegment, - "data" => EditorTabState::DataSegment, - _ => EditorTabState::default(), - }; - - active_tab.set(new_tab); - }) - }; - html! { - <> - // Editor buttons -
- if *active_tab == EditorTabState::Editor { - - } else { - - } - - if *active_tab == EditorTabState::TextSegment { - - } else { - - } - - if *active_tab == EditorTabState::DataSegment { - - } else { - - } -
- if *active_tab == EditorTabState::Editor { - - } else if *active_tab == EditorTabState::TextSegment { - - } else if *active_tab == EditorTabState::DataSegment { - - } - - } -} - -/********************** "Console" Component **********************/ -#[derive(PartialEq, Properties)] -pub struct Consoleprops { - pub parsermsg: String, -} - /********************** File I/O Function ***********************/ pub fn on_upload_file_clicked() { // log!("Upload clicked!"); diff --git a/src/emulation_core/mips/memory.rs b/src/emulation_core/mips/memory.rs index 3288f56db..183c7afa4 100644 --- a/src/emulation_core/mips/memory.rs +++ b/src/emulation_core/mips/memory.rs @@ -162,6 +162,39 @@ impl Memory { Ok(changed_lines) } + + pub fn generate_formatted_hex(&mut self) -> String { + let iterator = MemoryIter::new(&self); + + let mut string: String = "".to_string(); + + for (address, words) in iterator { + string.push_str(&format!("0x{address:04x}:\t\t")); + let mut char_version: String = "".to_string(); + + for word in words { + string.push_str(&format!("{:08x}\t", word)); + char_version.push_str(&Self::convert_word_to_chars(word)); + } + + string.push_str(&format!("{char_version}\n")); + } + + string + } + + pub fn convert_word_to_chars(word: u32) -> String { + let mut chars = "".to_string(); + for shift in (0..4).rev() { + let byte = (word >> (shift * 8)) as u8; + if byte > 32 && byte < 127 { + chars.push(byte as char); + } else { + chars.push('.'); + } + } + chars + } } pub struct MemoryIter<'a> { diff --git a/src/ui.rs b/src/ui.rs index fd4f689fb..ae0251e6f 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,7 +1,9 @@ //! User interface using Yew, organized into components. + +pub mod assembled_view; pub mod console; pub mod hex_editor; pub mod regview; -pub mod visual_datapath; -pub mod assembled_view; +pub mod swim_editor; +pub mod visual_datapath; \ No newline at end of file diff --git a/src/ui/assembled_view/component.rs b/src/ui/assembled_view/component.rs index 15759fa85..86787ee9f 100644 --- a/src/ui/assembled_view/component.rs +++ b/src/ui/assembled_view/component.rs @@ -1,7 +1,7 @@ use std::cell::RefCell; use std::rc::Rc; -use monaco::api::TextModel; +// use monaco::api::TextModel; use web_sys::HtmlInputElement; use yew::{Properties, Html}; use yew::prelude::*; @@ -33,30 +33,30 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html { let target = e.target(); let input = target.unwrap().unchecked_into::(); - if (input.checked()) { + if input.checked() { debug!("Breakpoint set at {:08x}", address); } - + }); let on_address_click = Callback::from(move |args: (MouseEvent, i64)| { - let (e, address) = args; - let target = e.target(); - let input = target.unwrap().unchecked_into::(); + let (_e, address) = args; + // let target = e.target(); + // let input = target.unwrap().unchecked_into::(); debug!("Go to address {:08x}", address); debug!("Go to line {:?}", (address / 4) as f64); // memory_curr_line.set((address / 4) as f64); - + }); let on_assembled_click = Callback::from(move |args: (MouseEvent, i64)| { - let (e, line_number) = args; - let target = e.target(); - let input = target.unwrap().unchecked_into::(); + let (_e, line_number) = args; + // let target = e.target(); + // let input = target.unwrap().unchecked_into::(); debug!("Go to line number {:08x}", line_number); - + }); let mut address = -4; @@ -71,7 +71,7 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html { {"Assembled"} {"Source"} - { + { program_info.instructions.iter().enumerate().map(|(index, instruction)| { let recreated_string = instruction.recreate_string(); let on_check = Callback::clone(&on_check); @@ -82,24 +82,24 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html { if props.pc as i64 == address { conditional_class = "executing"; } - html!{ - + html!{ +
- {format!("0x{:08x}", address as u64)} + {format!("0x{:08x}", address as u64)} - {format!("0b{:032b}", instruction.binary)} + {format!("0b{:032b}", instruction.binary)} - {format!("0x{:08x}", instruction.binary)} + {format!("0x{:08x}", instruction.binary)} - {recreated_string} + {recreated_string} {format!("{}: {:?}", instruction.line_number, lines_content.get(instruction.line_number).unwrap_or(&String::from("")))} @@ -119,22 +119,22 @@ pub fn DataSegment(props: &DataSegmentProps) -> Html { let lines_content = props.lines_content.borrow_mut().clone(); let on_address_click = Callback::from(move |args: (MouseEvent, usize)| { - let (e, address) = args; - let target = e.target(); - let input = target.unwrap().unchecked_into::(); + let (_e, address) = args; + // let target = e.target(); + // let input = target.unwrap().unchecked_into::(); debug!("Go to address {:08x}", address); debug!("Go to line {:?}", (address / 4) as f64); - + }); let on_assembled_click = Callback::from(move |args: (MouseEvent, usize)| { - let (e, line_number) = args; - let target = e.target(); - let input = target.unwrap().unchecked_into::(); + let (_e, line_number) = args; + // let target = e.target(); + // let input = target.unwrap().unchecked_into::(); debug!("Go to line number {:08x}", line_number); - + }); html! { @@ -146,7 +146,7 @@ pub fn DataSegment(props: &DataSegmentProps) -> Html { {"Assembled"} {"Source"} - { + { if program_info.instructions.len() > 0 && binary.len() > 0 { let mut address = program_info.instructions.len() * 4 - 4; program_info.data.iter().enumerate().map(|(index, data)| { @@ -154,17 +154,17 @@ pub fn DataSegment(props: &DataSegmentProps) -> Html { let on_address_click = Callback::clone(&on_address_click); let on_assembled_click = Callback::clone(&on_assembled_click); address += 4; - html!{ - + html!{ + - {format!("0x{:08x}", address as u64)} + {format!("0x{:08x}", address as u64)} - {format!("0x{:08x}", binary[data.line_number])} + {format!("0x{:08x}", binary[data.line_number])} - {recreated_string} + {recreated_string} {format!("{}: {:?}", data.line_number, lines_content.get(data.line_number).unwrap_or(&String::from("")))} diff --git a/src/ui/hex_editor/component.rs b/src/ui/hex_editor/component.rs index d401b5cb2..05f9bdaf1 100644 --- a/src/ui/hex_editor/component.rs +++ b/src/ui/hex_editor/component.rs @@ -1,7 +1,6 @@ use js_sys::Object; use wasm_bindgen::{closure::Closure, JsValue}; -use yew::{function_component, html, Html, Properties, use_callback, Callback, use_mut_ref, use_effect_with_deps}; -use crate::emulation_core::mips::memory::{Memory, MemoryIter}; +use yew::{function_component, html, Html, Properties, use_callback}; use std::rc::Rc; use std::cell::RefCell; use log::debug; @@ -11,7 +10,7 @@ use monaco::{ api::TextModel, sys:: editor::{ - IEditorMinimapOptions, IEditorScrollbarOptions, IStandaloneEditorConstructionOptions, ISuggestOptions, ScrollType + IEditorMinimapOptions, IEditorScrollbarOptions, IStandaloneEditorConstructionOptions, ISuggestOptions }, yew::{CodeEditor, CodeEditorLink}, }; @@ -24,10 +23,10 @@ pub struct HexEditorProps { #[function_component(HexEditor)] pub fn hex_editor(props: &HexEditorProps) -> Html { let editor_link = CodeEditorLink::new(); - let text_model = Rc::clone(&props.memory_text_model); - let curr_line = Rc::clone(&props.curr_line); - let not_highlighted = js_sys::Array::new(); - let mut mutated = false; + // let text_model = Rc::clone(&props.memory_text_model); + // let curr_line = Rc::clone(&props.curr_line); + // let not_highlighted = js_sys::Array::new(); + // let mut mutated = false; // create a JavaScript closure let cb = Closure::wrap(Box::new(move |event: monaco::sys::editor::ICursorSelectionChangedEvent| { @@ -51,9 +50,9 @@ pub fn hex_editor(props: &HexEditorProps) -> Html { .dyn_into::() .expect("Hex range is not found."); highlight_line.set_range(&monaco::sys::IRange::from(range_js)); - let highlight_js = highlight_line - .dyn_into::() - .expect("Hex highlight is not found."); + // let highlight_js = highlight_line + // .dyn_into::() + // .expect("Hex highlight is not found."); if start_column > 8.0 && end_column < 46.0 { // select ASCII @@ -67,11 +66,11 @@ pub fn hex_editor(props: &HexEditorProps) -> Html { let on_editor_created = { let text_model = Rc::clone(&props.memory_text_model); - let curr_line = Rc::clone(&curr_line); + // let curr_line = Rc::clone(&curr_line); use_callback( - move |editor_link: CodeEditorLink, text_model| { - let curr_line = curr_line.borrow_mut(); + move |editor_link: CodeEditorLink, _text_model| { + // let curr_line = curr_line.borrow_mut(); match editor_link.with_editor(|editor| { let raw_editor = editor.as_ref(); @@ -100,39 +99,6 @@ pub fn hex_editor(props: &HexEditorProps) -> Html { } } -pub fn generate_formatted_hex(memory: &Memory) -> String { - let iterator = MemoryIter::new(&memory); - - let mut string: String = "".to_string(); - - for (address, words) in iterator { - string.push_str(&format!("0x{address:04x}:\t\t")); - let mut char_version: String = "".to_string(); - - for word in words { - string.push_str(&format!("{:08x}\t", word)); - char_version.push_str(&convert_word_to_chars(word)); - } - - string.push_str(&format!("{char_version}\n")); - } - - string -} - -fn convert_word_to_chars(word: u32) -> String { - let mut chars = "".to_string(); - for shift in (0..4).rev() { - let byte = (word >> (shift * 8)) as u8; - if byte > 32 && byte < 127 { - chars.push(byte as char); - } else { - chars.push('.'); - } - } - chars -} - fn get_options() -> IStandaloneEditorConstructionOptions { let options = IStandaloneEditorConstructionOptions::default(); diff --git a/src/ui/regview/component.rs b/src/ui/regview/component.rs index b34c2e447..0456007eb 100644 --- a/src/ui/regview/component.rs +++ b/src/ui/regview/component.rs @@ -4,7 +4,7 @@ use crate::emulation_core::mips::memory::CAPACITY_BYTES; use crate::emulation_core::mips::registers::{GpRegisterType, GpRegisters}; //use gloo::console::log; use wasm_bindgen::JsCast; -use web_sys::{HtmlElement, InputEvent, HtmlInputElement}; +use web_sys::{InputEvent, HtmlInputElement}; use yew::prelude::*; use yew::{html, Html}; use std::rc::Rc; @@ -18,7 +18,7 @@ pub struct Regviewprops { pub fp: [u64; 32], pub datapath: Rc>, pub pc_limit: usize, - // pub communicator: &'static DatapathCommunicator + pub communicator: &'static DatapathCommunicator } #[derive(PartialEq, Properties)] pub struct Regrowprops { @@ -221,6 +221,7 @@ pub fn regview(props: &Regviewprops) -> Html { let on_input = Callback::from(move |args: (InputEvent, GpRegisterType)| { let (e, register) = args; + // let communicator = props.communicator; let target = e.target(); let input = target.unwrap().unchecked_into::(); let val: i64 = match input.value().parse() { @@ -248,7 +249,7 @@ pub fn regview(props: &Regviewprops) -> Html { } datapath.registers.pc = val as u64; - // props.communicator.send_test_message(val); + // communicator.send_test_message(val); } // check if pc is more than memory capacity // or if it's not word aligned diff --git a/src/ui/swim_editor/component.rs b/src/ui/swim_editor/component.rs new file mode 100644 index 000000000..1fb9894fb --- /dev/null +++ b/src/ui/swim_editor/component.rs @@ -0,0 +1,145 @@ +use std::{cell::RefCell, rc::Rc}; + +use monaco::{api::TextModel, sys::editor::{ + IEditorMinimapOptions, IEditorScrollbarOptions, IStandaloneEditorConstructionOptions, ISuggestOptions, ScrollType +}, yew::{CodeEditor, CodeEditorLink}}; +use yew::{Callback, Properties}; +use yew::prelude::*; +use wasm_bindgen::JsCast; + +use crate::{parser::parser_structs_and_enums::ProgramInfo, ui::assembled_view::component::{DataSegment, TextSegment}}; + +use log::debug; + +#[derive(PartialEq, Properties)] +pub struct SwimEditorProps { + pub text_model: Rc>, + pub lines_content: Rc>>, + pub program_info: ProgramInfo, + pub binary: Vec, + pub pc: u64, + pub memory_curr_line: Rc>, + pub curr_line: Rc> +} + +#[derive(Default, PartialEq)] +enum EditorTabState { + #[default] + Editor, + TextSegment, + DataSegment +} + +fn get_options() -> IStandaloneEditorConstructionOptions { + let options = IStandaloneEditorConstructionOptions::default(); + options.set_theme("vs-dark".into()); + options.set_language("mips".into()); + options.set_scroll_beyond_last_line(false.into()); + options.set_automatic_layout(true.into()); + + let minimap = IEditorMinimapOptions::default(); + minimap.set_enabled(false.into()); + options.set_minimap(Some(&minimap)); + + let scrollbar = IEditorScrollbarOptions::default(); + scrollbar.set_always_consume_mouse_wheel(false.into()); + options.set_scrollbar(Some(&scrollbar)); + + let suggest = ISuggestOptions::default(); + suggest.set_show_keywords(false.into()); + suggest.set_show_variables(false.into()); + suggest.set_show_icons(false.into()); + suggest.set_show_words(false.into()); + suggest.set_filter_graceful(false.into()); + options.set_suggest(Some(&suggest)); + + options +} + +#[function_component] +pub fn SwimEditor(props: &SwimEditorProps) -> Html { + let link = CodeEditorLink::new(); + + let on_editor_created = { + let text_model = Rc::clone(&props.text_model); + let curr_line = Rc::clone(&props.curr_line); + let lines_content = Rc::clone(&props.lines_content); + + use_callback( + move |editor_link: CodeEditorLink, _text_model| { + let curr_line = curr_line.borrow_mut(); + match editor_link.with_editor(|editor| { + let raw_editor = editor.as_ref(); + let model = raw_editor.get_model().unwrap(); + // store each line from the original code editor's contents for assembled view + let js_lines = model.get_lines_content(); + let mut string_lines = lines_content.borrow_mut(); + for js_string in js_lines.into_iter() { + let string_value = match js_string.as_string() { + Some(string) => string, + None => String::from("") + }; + string_lines.push(string_value); + + }; + raw_editor.reveal_line_in_center(*curr_line, Some(ScrollType::Smooth)); + }) { + Some(()) => debug!("Editor linked!"), + None => debug!("No editor :<") + }; + }, + text_model, + ) + }; + + let active_tab = use_state_eq(EditorTabState::default); + let change_tab = { + let active_tab = active_tab.clone(); + Callback::from(move |event: MouseEvent| { + let target = event.target().unwrap().dyn_into::().unwrap(); + let tab_name = target + .get_attribute("label") + .unwrap_or(String::from("editor")); + + let new_tab: EditorTabState = match tab_name.as_str() { + "editor" => EditorTabState::Editor, + "text" => EditorTabState::TextSegment, + "data" => EditorTabState::DataSegment, + _ => EditorTabState::default(), + }; + + active_tab.set(new_tab); + }) + }; + html! { + <> + // Editor buttons +
+ if *active_tab == EditorTabState::Editor { + + } else { + + } + + if *active_tab == EditorTabState::TextSegment { + + } else { + + } + + if *active_tab == EditorTabState::DataSegment { + + } else { + + } +
+ if *active_tab == EditorTabState::Editor { + + } else if *active_tab == EditorTabState::TextSegment { + + } else if *active_tab == EditorTabState::DataSegment { + + } + + } +} \ No newline at end of file diff --git a/src/ui/swim_editor/mod.rs b/src/ui/swim_editor/mod.rs new file mode 100644 index 000000000..519c53d92 --- /dev/null +++ b/src/ui/swim_editor/mod.rs @@ -0,0 +1 @@ +pub mod component; \ No newline at end of file From 63c0a5416846fab31018cdbe5481445a1c962cb6 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 1 Feb 2024 21:51:49 -0500 Subject: [PATCH 022/355] Design datapath communicator API (feedback wanted!) --- src/agent/datapath_communicator.rs | 58 +++++++++++++++++++++++++++++ src/emulation_core.rs | 1 + src/emulation_core/architectures.rs | 4 ++ 3 files changed, 63 insertions(+) create mode 100644 src/emulation_core/architectures.rs diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index bdd839e53..9b1d6dbda 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -1,4 +1,5 @@ use crate::agent::EmulationCoreAgent; +use crate::emulation_core::architectures::AvailableDatapaths; use futures::stream::{SplitSink, SplitStream}; use futures::FutureExt; use futures::SinkExt; @@ -6,6 +7,7 @@ use futures::StreamExt; use gloo_console::log; use gloo_console::warn; use std::cell::RefCell; +use std::collections::HashMap; use yew::UseForceUpdateHandle; use yew_agent::reactor::ReactorBridge; @@ -29,6 +31,8 @@ impl PartialEq for &DatapathCommunicator { } impl DatapathCommunicator { + // General operational functions + /// Initialize the DatapathCommunicator using a bridge. pub fn new(bridge: ReactorBridge) -> DatapathCommunicator { let (write, read) = bridge.split(); @@ -72,4 +76,58 @@ impl DatapathCommunicator { .expect("Send function did not immediately return, async logic needed.") .expect("Sending test message error") } + + // Wrapper functions for commands + + pub fn set_core(&self, _architecture: AvailableDatapaths) { + todo!() + } + + pub fn load_instructions(&self, _instructions: &[u8]) { + todo!() + } + + pub fn set_execute_speed(&self, _speed: u32) { + todo!() + } + + pub fn set_register(&self, _register: &str, _data: &str) { + todo!() + } + + pub fn set_memory(&self, _ptr: usize, _data: &[u8]) { + todo!() + } + + pub fn execute(&self) { + todo!() + } + + pub fn execute_instruction(&self) { + todo!() + } + + pub fn execute_stage(&self) { + todo!() + } + + pub fn pause_core(&self) {} + + // Getters for internal state + + pub fn get_registers(&self) -> HashMap { + todo!() + } + + pub fn get_memory(&self) -> Vec { + todo!() + } + + pub fn get_current_stage(&self) -> String { + todo!() + } + + pub fn get_current_instruction(&self) -> usize { + todo!() + } } diff --git a/src/emulation_core.rs b/src/emulation_core.rs index e62a37920..ac45cc291 100644 --- a/src/emulation_core.rs +++ b/src/emulation_core.rs @@ -1,4 +1,5 @@ //! The emulation core for the project. +pub mod architectures; pub mod datapath; pub mod mips; diff --git a/src/emulation_core/architectures.rs b/src/emulation_core/architectures.rs new file mode 100644 index 000000000..27fc363ed --- /dev/null +++ b/src/emulation_core/architectures.rs @@ -0,0 +1,4 @@ +pub enum AvailableDatapaths { + MIPS, + RISCV, +} From a3984077d2ba1bb6917ce3f8a7ba9fbb39d9be1b Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 1 Feb 2024 22:17:14 -0500 Subject: [PATCH 023/355] Remove the type alias for line information on the VisualDatapath trait --- src/emulation_core/datapath.rs | 7 +++---- src/emulation_core/mips/line_info.rs | 2 -- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index 0484ffc4a..21c80534d 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -1,5 +1,7 @@ //! Module for the API of a generic datapath. +use crate::emulation_core::mips::line_info::LineInformation; + /// A generic datapath. /// /// This has the ability to execute instructions, and to interface with @@ -96,10 +98,7 @@ pub trait Datapath { /// This requires a corresponding visual diagram with labels that can be mapped /// to the datapath. pub trait VisualDatapath { - /// The information about a piece of the diagram that is returned from the datapath. - type LineInformation; - /// Return the information from the datapath corresponding to the `variable` attribute on a /// part of the visual datapath diagram. - fn visual_line_to_data(&self, variable: &str) -> Self::LineInformation; + fn visual_line_to_data(&self, variable: &str) -> LineInformation; } diff --git a/src/emulation_core/mips/line_info.rs b/src/emulation_core/mips/line_info.rs index c28c0a8aa..add7c20ec 100644 --- a/src/emulation_core/mips/line_info.rs +++ b/src/emulation_core/mips/line_info.rs @@ -19,8 +19,6 @@ pub struct LineInformation { } impl VisualDatapath for MipsDatapath { - type LineInformation = LineInformation; - fn visual_line_to_data(&self, variable: &str) -> LineInformation { match variable { "alu_input2" => LineInformation { From c733a1642f7001715babe13fc4fec751fc79540b Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 1 Feb 2024 22:19:02 -0500 Subject: [PATCH 024/355] Add documentation for tentative API --- src/agent/datapath_communicator.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index 9b1d6dbda..e9cdb7f0d 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -1,5 +1,6 @@ use crate::agent::EmulationCoreAgent; use crate::emulation_core::architectures::AvailableDatapaths; +use crate::emulation_core::datapath::VisualDatapath; use futures::stream::{SplitSink, SplitStream}; use futures::FutureExt; use futures::SinkExt; @@ -79,55 +80,79 @@ impl DatapathCommunicator { // Wrapper functions for commands + /// Sets the current emulation core to the provided architecture. pub fn set_core(&self, _architecture: AvailableDatapaths) { todo!() } + /// Loads the parsed/assembled instructions provided into the current emulator core. pub fn load_instructions(&self, _instructions: &[u8]) { todo!() } + /// Sets the execution speed of the emulator core to the provided speed in hz. If set to zero, the emulator core + /// will execute as fast as possible. pub fn set_execute_speed(&self, _speed: u32) { todo!() } + /// Sets the register with the provided name to the provided value. pub fn set_register(&self, _register: &str, _data: &str) { todo!() } + /// Copies the contents of `data` to the emulator core's memory at `ptr`. Copies until either the end of `data` or + /// the end of the emulaot core's memory. pub fn set_memory(&self, _ptr: usize, _data: &[u8]) { todo!() } + /// Executes the emulator core at the current set speed. pub fn execute(&self) { todo!() } + /// Executes a single instruction on the emulator core and pauses. pub fn execute_instruction(&self) { todo!() } + /// Executes a single stage on the emulator core and pauses. pub fn execute_stage(&self) { todo!() } + /// Pauses the core. Does nothing if the emulator core is already paused. pub fn pause_core(&self) {} // Getters for internal state + /// Returns a list of all the registers on the current emulator core. pub fn get_registers(&self) -> HashMap { todo!() } + /// Returns the emulator core's memory as an array of bytes. pub fn get_memory(&self) -> Vec { todo!() } + /// Gets the current stage of the emulator core as a string. pub fn get_current_stage(&self) -> String { todo!() } + /// Gets the currently executing instruction on the emulator core. This is generally based on the value of the + /// program counter. pub fn get_current_instruction(&self) -> usize { todo!() } + + /// Returns the appropriate visual datapath for the current architecture. Returns a boxed generic VisualDatapath. + pub fn get_visual_datapath( + &self, + _architecture: AvailableDatapaths, + ) -> Box { + todo!() + } } From b145bb2e83a82f00ed7402f8676ef72d4b2e4cb6 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 1 Feb 2024 22:29:53 -0500 Subject: [PATCH 025/355] Add/document communication-related enums --- src/agent.rs | 1 + src/agent/messages.rs | 27 +++++++++++++++++++++++++++ src/emulation_core/architectures.rs | 3 +++ 3 files changed, 31 insertions(+) create mode 100644 src/agent/messages.rs diff --git a/src/agent.rs b/src/agent.rs index f74dda20b..65265ed2b 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -5,6 +5,7 @@ use gloo_console::log; use yew_agent::prelude::*; pub mod datapath_communicator; +pub mod messages; /// The main logic for the emulation core agent. All code within this function runs on a worker thread as opposed to /// the UI thread. diff --git a/src/agent/messages.rs b/src/agent/messages.rs new file mode 100644 index 000000000..059bc0532 --- /dev/null +++ b/src/agent/messages.rs @@ -0,0 +1,27 @@ +use crate::emulation_core::architectures::AvailableDatapaths; +use serde::{Deserialize, Serialize}; + +/// Commands sent from the UI thread to the worker thread. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum Command { + SetCore(AvailableDatapaths), + LoadInstructions(Vec), + SetExecuteSpeed(u32), + SetRegister(String, u64), + SetMemory(usize, Vec), + Execute, + ExecuteInstruction, + ExecuteStage, + Pause, +} + +/// Information about the emulator core's state sent from the worker thread to the UI thread. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum StateUpdate { + UpdateRegister(u64), + UpdateMemory(usize, Vec), + SetCurrentStage(String), + SetCurrentInstruction(usize), + AddMemorySegment, + RemoveMemorySegment, +} diff --git a/src/emulation_core/architectures.rs b/src/emulation_core/architectures.rs index 27fc363ed..bc29426d1 100644 --- a/src/emulation_core/architectures.rs +++ b/src/emulation_core/architectures.rs @@ -1,3 +1,6 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum AvailableDatapaths { MIPS, RISCV, From 2bc8f3815f37e85dcbd7592a90180c21998a152a Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 1 Feb 2024 23:30:05 -0500 Subject: [PATCH 026/355] Proof-of-concept implementation of the emulator core thread --- src/agent.rs | 111 ++++++++++++++++++++++++++--- src/agent/datapath_communicator.rs | 18 +++-- src/bin/main.rs | 2 - 3 files changed, 113 insertions(+), 18 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index 65265ed2b..7ae3acac9 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -1,7 +1,14 @@ //! The agent responsible for running the emulator core on the worker thread and communication functionalities. -use futures::{SinkExt, StreamExt}; +use crate::agent::messages::{Command, StateUpdate}; +use crate::emulation_core::datapath::Datapath; +use crate::emulation_core::mips::datapath::{MipsDatapath, Stage}; +use crate::emulation_core::mips::memory::Memory; +use crate::emulation_core::mips::registers::GpRegisterType; +use futures::{FutureExt, StreamExt}; use gloo_console::log; +use std::time::Duration; +use yew::platform::time::sleep; use yew_agent::prelude::*; pub mod datapath_communicator; @@ -10,15 +17,101 @@ pub mod messages; /// The main logic for the emulation core agent. All code within this function runs on a worker thread as opposed to /// the UI thread. #[reactor(EmulationCoreAgent)] -pub async fn emulation_core_agent(mut scope: ReactorScope) { +pub async fn emulation_core_agent(scope: ReactorScope) { log!("Hello world!"); - let mut num = 1; - scope.send(num).await.unwrap(); + let mut state = EmulatorCoreAgentState::new(scope); loop { - let msg = scope.next().await; - log!("Got message: ", msg); - num += 1; - scope.send(num).await.unwrap(); - log!("Sent."); + let execution_delay = state.get_delay(); + futures::select! { + // If we get a message, handle the command before attempting to execute. + msg = state.scope.next() => match msg { + Some(msg) => state.handle_command(msg), + None => return, + }, + // Delay to slow execution down to the intended speed. + _ = sleep(Duration::from_millis(execution_delay)).fuse() => {}, + } + + // Execute a single instruction if the emulator core should be executing. + state.execute(); + } +} + +struct EmulatorCoreAgentState { + current_datapath: Box< + dyn Datapath< + MemoryType = Memory, + RegisterData = u64, + RegisterEnum = GpRegisterType, + StageEnum = Stage, + >, + >, + pub scope: ReactorScope, + speed: u32, + executing: bool, +} + +impl EmulatorCoreAgentState { + pub fn new(scope: ReactorScope) -> EmulatorCoreAgentState { + EmulatorCoreAgentState { + current_datapath: Box::::default(), + scope, + speed: 0, + executing: false, + } + } + + pub fn handle_command(&mut self, command: Command) { + match command { + Command::SetCore(_architecture) => { + todo!() // Implement once we have a RISCV datapath + } + Command::LoadInstructions(_mem) => { + // FIXME: Uncomment once refactoring is done on the trait + // self.current_datapath.load_instructions(mem); + todo!() + } + Command::SetExecuteSpeed(speed) => { + self.speed = speed; + } + Command::SetRegister(_register, _value) => { + todo!() + } + Command::SetMemory(_ptr, _data) => { + // FIXME: Uncomment once refectoring is done on the trait + // self.current_datapath.set_memory(ptr, &data); + todo!() + } + Command::Execute => { + self.executing = true; + } + Command::ExecuteInstruction => { + self.current_datapath.execute_instruction(); + } + Command::ExecuteStage => { + self.current_datapath.execute_stage(); + } + Command::Pause => { + self.executing = false; + } + } + } + + pub fn execute(&mut self) { + // Skip the execution phase if the emulator core is not currently executing. + if !self.executing { + return; + } + self.current_datapath.execute_instruction(); + } + + /// Returns the delay between CPU cycles in milliseconds for the current execution speed. Will return zero if the + /// execution speed is zero. + pub fn get_delay(&self) -> u64 { + if self.speed == 0 { + 0 + } else { + (1000 / self.speed).into() + } } } diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index e9cdb7f0d..693dc33d8 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -1,3 +1,4 @@ +use crate::agent::messages::Command; use crate::agent::EmulationCoreAgent; use crate::emulation_core::architectures::AvailableDatapaths; use crate::emulation_core::datapath::VisualDatapath; @@ -18,7 +19,7 @@ use yew_agent::reactor::ReactorBridge; /// The DatapathCommunicator will also handle receiving information about the state of the emulation core and maintain /// internal state that can be displayed by the UI. pub struct DatapathCommunicator { - writer: RefCell, i32>>, + writer: RefCell, Command>>, reader: RefCell>>, } @@ -68,11 +69,14 @@ impl DatapathCommunicator { } /// Sends a test message to the worker thread. - pub fn send_test_message(&self) { + fn send_message(&self, command: Command) { let mut writer = self.writer.borrow_mut(); writer - .send(1) - // The + .send(command) + // The logic for sending a message is synchronous but the API for writing to a SplitSink is asynchronous, + // so we attempt to resolve the future immediately so we can expose a synchronous API for sending commands. + // If the future doesn't return immediately, there's serious logic changes that need to happen so we just + // log an error message and panic. .now_or_never() .expect("Send function did not immediately return, async logic needed.") .expect("Sending test message error") @@ -103,13 +107,13 @@ impl DatapathCommunicator { /// Copies the contents of `data` to the emulator core's memory at `ptr`. Copies until either the end of `data` or /// the end of the emulaot core's memory. - pub fn set_memory(&self, _ptr: usize, _data: &[u8]) { - todo!() + pub fn set_memory(&self, ptr: usize, data: Vec) { + self.send_message(Command::SetMemory(ptr, data)); } /// Executes the emulator core at the current set speed. pub fn execute(&self) { - todo!() + self.send_message(Command::Execute); } /// Executes a single instruction on the emulator core and pauses. diff --git a/src/bin/main.rs b/src/bin/main.rs index e0fbc285b..487c0254b 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -99,7 +99,6 @@ fn app(props: &AppProps) -> Html { // This is where code is assembled and loaded into the emulation core's memory. let on_assemble_clicked = { - let communicator = props.communicator; let text_model = Rc::clone(&text_model); let datapath = Rc::clone(&datapath); let parser_text_output = parser_text_output.clone(); @@ -110,7 +109,6 @@ fn app(props: &AppProps) -> Html { use_callback( move |_, text_model| { - communicator.send_test_message(); // Test message, remove later. let mut datapath = datapath.borrow_mut(); let text_model = text_model.borrow_mut(); From 6ad90f5eff1c023290acbe095347aa272ac5076c Mon Sep 17 00:00:00 2001 From: rharding8 Date: Fri, 2 Feb 2024 18:09:44 -0500 Subject: [PATCH 027/355] Emulation core updated incorporating correct RISCV control signals in the datapath, minus memory operations. STILL TODO: Memory operations Adding operations Making it all work --- src/emulation_core.rs | 2 +- src/emulation_core/riscv.rs | 12 + src/emulation_core/riscv/control_signals.rs | 274 ++++++-------------- src/emulation_core/riscv/datapath.rs | 230 +++++++--------- 4 files changed, 181 insertions(+), 337 deletions(-) create mode 100644 src/emulation_core/riscv.rs diff --git a/src/emulation_core.rs b/src/emulation_core.rs index e62a37920..6bc6a6d54 100644 --- a/src/emulation_core.rs +++ b/src/emulation_core.rs @@ -1,4 +1,4 @@ //! The emulation core for the project. pub mod datapath; -pub mod mips; +pub mod mips; \ No newline at end of file diff --git a/src/emulation_core/riscv.rs b/src/emulation_core/riscv.rs new file mode 100644 index 000000000..9eef52183 --- /dev/null +++ b/src/emulation_core/riscv.rs @@ -0,0 +1,12 @@ +//! All facets of this project's implementation of the MIPS64 ISA, including +//! the datapath, control signals, registers, and memory. + +pub mod constants; +pub mod control_signals; +pub mod coprocessor; +pub mod datapath; +pub mod datapath_signals; +pub mod instruction; +pub mod line_info; +pub mod memory; +pub mod registers; diff --git a/src/emulation_core/riscv/control_signals.rs b/src/emulation_core/riscv/control_signals.rs index 414b1dd7c..d5c4b151b 100644 --- a/src/emulation_core/riscv/control_signals.rs +++ b/src/emulation_core/riscv/control_signals.rs @@ -3,20 +3,42 @@ /// Full collection of control signals. #[derive(Clone, Default, PartialEq)] pub struct ControlSignals { - pub alu_control: AluControl, + pub imm_select: ImmSelect, + pub op1_select: OP1Select, + pub op2_select: OP2Select, pub alu_op: AluOp, - pub alu_src: AluSrc, - pub branch: Branch, - pub branch_type: BranchType, - pub imm_shift: ImmShift, - pub jump: Jump, - pub mem_read: MemRead, - pub mem_to_reg: MemToReg, - pub mem_write: MemWrite, + pub branch_jump: BranchJump, + pub read_write: ReadWrite, + pub wb_sel: WBSel, pub mem_write_src: MemWriteSrc, pub reg_dst: RegDst, - pub reg_width: RegWidth, - pub reg_write: RegWrite, + pub reg_write_en: RegWriteEn, +} + +#[derive(Clone, Default, PartialEq)] +pub enum ImmSelect { + UType, + JType, + SType, + BType, + #[default] + ISigned, + IShamt, + IUnsigned, +} + +#[derive(Clone, Default, PartialEq)] +pub enum OP1Select { + #[default] + DATA1, + PC, +} + +#[derive(Clone, Default, PartialEq)] +pub enum OP2Select { + DATA2, + #[default] + IMM, } /// The output of the ALU control unit that directly controls the ALU. @@ -29,7 +51,7 @@ pub struct ControlSignals { /// the input and output data within the datapath. See [`RegWidth`] for /// more details. #[derive(Clone, Default, PartialEq)] -pub enum AluControl { +pub enum AluOp { /// `_0000` (0) - Perform an addition. (Also used in cases where the ALU result does not matter.) #[default] Addition, @@ -37,175 +59,73 @@ pub enum AluControl { /// `_0001` (1) - Perform a subtraction. Will not set any underflow signal on underflow. Subtraction, - /// `_0010` (2) - Perform a "set on less than" operation. + /// `_0010` (2) - Perform a shift left logical operation by `shamt` bits. + ShiftLeftLogical(u32), + + /// `_0011` (3) - Perform a "set on less than" operation. SetOnLessThanSigned, - /// `_0011` (3) - Perform a "set on less than unsigned" operation. + /// `_0100` (4) - Perform a "set on less than unsigned" operation. SetOnLessThanUnsigned, - /// `_0100` (4) - Perform a bitwise "AND" operation. - And, - - /// `_0101` (5) - Perform a bitwise "OR" operation. - Or, - - /// `_0110` (6) - Left shift the sign-extended immediate value 16 bits. - LeftShift16, - - /// `_0111` (7) - Perform a bitwise "Xor" operation. + /// `_0101` (5) - Perform a bitwise "Xor" operation. Xor, - /// `_1000` (8) - Perform signed multiplication. - MultiplicationSigned, - - /// `_1001` (9) - Perform unsigned multiplication. - MultiplicationUnsigned, - - /// `_1010` (10) - Perform signed integer division. (Returns the integer quotient.) - DivisionSigned, - - /// `_1011` (11) - Perform unsigned integer division. (Returns the integer quotient.) - DivisionUnsigned, - - /// `_1100` (12) - Perform a shift left logical operation by `shamt` bits. - ShiftLeftLogical(u32), - - /// `_1101` (13) - Perform a shift right logical operation by `shamt` bits. + /// `_0110` (6) - Perform a shift right logical operation by `shamt` bits. ShiftRightLogical(u32), - /// `_1110` (14) - Perform a shift right arithmetic operation by `shamt` bits. + /// `_0111` (7) - Perform a shift right arithmetic operation by `shamt` bits. ShiftRightArithmetic(u32), -} - -/// This determines the operation sent to the ALU control unit. -/// -/// This is on a higher abstraction than the output of this control -/// unit, which more specifically determines what operation the ALU -/// will perform. -#[derive(Clone, Default, PartialEq)] -pub enum AluOp { - /// `0000` (0) - Perform an addition. (Also used in cases where the ALU result does not matter.) - #[default] - Addition = 0, - - /// `0001` (1) - Perform a subtraction. Will not set any underflow signal on underflow. - Subtraction = 1, - - /// `0010` (2) - Perform a "set on less than" operation. - SetOnLessThanSigned = 2, - - /// `0011` (3) - Perform a "set on less than unsigned" operation. - SetOnLessThanUnsigned = 3, - /// `0100` (4) - Perform a binary "AND" operation. - And = 4, - - /// `0101` (5) - Perform a binary "OR" operation. - Or = 5, - - /// `0110` (6) - Left shift the sign-extended immediate value 16 bits. - LeftShift16 = 6, - - /// `0111` (7) - This is an R-type instruction and the operation - /// should instead refer to the `funct` field in the instruction. - /// - /// (Note: For the `mul` and `div` instructions, the operation of - /// the ALU may additionally be determined by bits 10-6 of the - /// instruction (same bits as the `shamt` field), as the `funct` - /// field alone does not provide the full description of those - /// instructions.) - UseFunctField = 7, -} - -/// Determines the second source of the ALU. -/// -/// The first input is always the data read from the register `rs1` (or -/// called `base` in some contexts.) -#[derive(Clone, Default, PartialEq)] -pub enum AluSrc { - /// Use the data from the from the second source register `rs2`. - #[default] - ReadRegister2 = 0, - - /// Use the sign-extended 16-bit immediate field in the instruction. This may be left-shifted by some amount given by the [`ImmShift`] control signal. - SignExtendedImmediate = 1, - - /// Use the zero-extended 16-bit immediate field in the instruction. - ZeroExtendedImmediate = 2, -} + /// `_1000` (8) - Perform a bitwise "OR" operation. + Or, -/// Determines if the datapath should consider branching. -/// -/// Exact choice of branching or not branching relies on the result from the ALU. -/// This can be overridden by the [`Jump`] signal. -#[derive(Clone, Default, PartialEq)] -pub enum Branch { - /// Do not consider branching. - #[default] - NoBranch = 0, + /// `_1001` (9) - Perform a bitwise "AND" operation. + And, - /// Consider branching. - YesBranch = 1, -} + /// `_1010` (10) - Left shift the sign-extended immediate value 16 bits. + LeftShift16, -/// Determines, given [`Branch`] is set, whether to branch when the [`AluZ`](super::datapath_signals::AluZ) signal is set, -/// or when [`AluZ`](super::datapath_signals::AluZ) is not set. -/// -/// In effect, this decides whether or not to invert the [`AluZ`](super::datapath_signals::AluZ) signal, which is -/// used between the `beq` and `bne` instructions. -#[derive(Clone, Default, PartialEq)] -pub enum BranchType { - /// Branch based on [`AluZ`](super::datapath_signals::AluZ). (Used in `beq`.) - #[default] - OnEqual = 0, + /// `_1011` (11) - Perform signed multiplication. + MultiplicationSigned, - /// Branch based on the inverse of [`AluZ`](super::datapath_signals::AluZ). (Used in `bne`.) - OnNotEqual = 1, + /// `_1100` (12) - Perform unsigned multiplication. + MultiplicationUnsigned, - /// Branch based on being less than [`AluZ`](super::datapath_signals::AluZ). (Used in `blt`) - OnLessThan = 2, + /// `_1101` (13) - Perform signed integer division. (Returns the integer quotient.) + DivisionSigned, - OnGreaterEqual = 3, - OnLessThanUnsigned = 4, - OnGreaterEqualUnsigned = 5, + /// `_1110` (14) - Perform unsigned integer division. (Returns the integer quotient.) + DivisionUnsigned, } -/// Determines the amount of bits to left-shift the immediate value before being passed to the ALU. #[derive(Clone, Default, PartialEq)] -pub enum ImmShift { +pub enum BranchJump { + Beq, + Bne, #[default] - Shift0 = 0, - Shift16 = 1, - Shift32 = 2, - Shift48 = 3, + NoBranch, + J, + Blt, + Bge, + Bltu, + Bgeu, } -/// Determines if the datapath should jump. This is an unconditional branch. -/// -/// The [`Branch`] signal may be overridden depending on the value of this signal. #[derive(Clone, Default, PartialEq)] -pub enum Jump { - /// Do not jump. Defer to the [`Branch`] signal. +pub enum ReadWrite { #[default] - NoJump = 0, - - /// Jump by using the address specified in the instruction's lower bits. - YesJump = 1, - - /// Jump by using the address specified in the contents of register `rs`. - /// This is used in `jr` and `jalr` instructions. - YesJumpJalr = 2, + NoLoadStore, + LoadByte, + LoadHalf, + LoadWord, + LoadByteUnsigned, + LoadHalfUnsigned, + StoreByte, + StoreHalf, + StoreWord, } -/// Determines if memory should be read. -/// -/// This should not be set in combination with [`MemWrite`]. -#[derive(Clone, Default, PartialEq)] -pub enum MemRead { - #[default] - NoRead = 0, - YesRead = 1, -} /// Determines, given [`RegWrite`] is set, what the source of a /// register's new data will be. @@ -216,22 +136,12 @@ pub enum MemRead { /// This control signal also applies to what data is sent to the /// floating-point unit to be stored in its registers. #[derive(Clone, Default, PartialEq)] -pub enum MemToReg { +pub enum WBSel { #[default] UseAlu = 0, UseMemory = 1, - UsePcPlusFour = 2, - UseImmediate = 3, -} - -/// Determines if memory should be written to. -/// -/// This should not be set in combination with the [`MemRead`] control signal. -#[derive(Clone, Default, PartialEq)] -pub enum MemWrite { - #[default] - NoWrite = 0, - YesWrite = 1, + UseImmediate = 2, + UsePcPlusFour = 3, } /// Determines, given that [`MemWrite`] is set, the source of the data @@ -269,35 +179,9 @@ pub enum RegDst { ReturnRegister = 3, } -/// Determines the amount of data to be sent or recieved from registers -/// and the ALU. While all buses carrying information are 64 bits wide, -/// some bits of the bus may be ignored in the case of this control -/// signal. -#[derive(Clone, Default, PartialEq)] -pub enum RegWidth { - /// Use words (32 bits). - Word = 0, - - /// Use doublewords (64 bits). - #[default] - DoubleWord = 1, - - /// Use bytes (8 bits). - Byte = 2, - - /// Use halfwords (16 bits). - HalfWord = 3, - - /// Use unsigned bytes (8 bits). - ByteUnsigned = 4, - - /// Use unsigned halfwords (16 bits). - HalfWordUnsigned = 5, -} - /// Determines if the register file should be written to. #[derive(Clone, Default, Eq, PartialEq)] -pub enum RegWrite { +pub enum RegWriteEn { #[default] NoWrite = 0, YesWrite = 1, diff --git a/src/emulation_core/riscv/datapath.rs b/src/emulation_core/riscv/datapath.rs index 3cc24e159..068ebdeb5 100644 --- a/src/emulation_core/riscv/datapath.rs +++ b/src/emulation_core/riscv/datapath.rs @@ -320,13 +320,11 @@ impl RiscDatapath { /// finish the instruction and set the `is_halted` flag. fn stage_instruction_decode(&mut self) { self.instruction_decode(); - self.set_immediate(); - self.sign_extend(); self.set_control_signals(); + self.set_immediate(); self.read_registers(); // Upper part of datapath, PC calculation - self.shift_lower_26_left_by_2(); self.construct_jump_address(); self.coprocessor.stage_instruction_decode(); @@ -474,7 +472,7 @@ impl RiscDatapath { fn set_immediate(&mut self) { let mut signed_imm = 0x0000 as u32; if self.state.instruction >> 31 == 1 { - signed_imm = 0xffff as u32; + signed_imm = 0xffffffff as u32; } signed_imm = match self.instruction { @@ -501,6 +499,10 @@ impl RiscDatapath { } }; + if (self.signals.imm_select == ImmSelect::IUnsigned) { + signed_imm = signed_imm & 0x00000fff; + } + self.state.imm = signed_imm; } @@ -534,33 +536,30 @@ impl RiscDatapath { /// case where the instruction is an R-type. fn set_rtype_control_signals(&mut self, r: RType) { self.signals = ControlSignals { - alu_src: AluSrc::ReadRegister2, - branch: Branch::NoBranch, - jump: Jump::NoJump, - mem_read: MemRead::NoRead, - mem_to_reg: MemToReg::UseAlu, - mem_write: MemWrite::NoWrite, + op2_select: OP2Select::DATA2, + branch_jump: BranchJump::NoBranch, + read_write: ReadWrite::NoLoadStore, + wb_sel: WBSel::UseAlu, reg_dst: RegDst::Reg3, - reg_width: RegWidth::Word, - reg_write: RegWrite::YesWrite, + reg_write_en: RegWriteEn::YesWrite, ..Default::default() }; match r.funct3 { 0 => match r.funct7 { - 0b0000000 => self.signals.alu_control = AluControl::Addition, - 0b0100000 => self.signals.alu_control = AluControl::Subtraction + 0b0000000 => self.signals.alu_op = AluOp::Addition, + 0b0100000 => self.signals.alu_op = AluOp::Subtraction } - 1 => self.signals.alu_control = AluControl::ShiftLeftLogical(self.state.rs2), - 2 => self.signals.alu_control = AluControl::SetOnLessThanSigned, - 3 => self.signals.alu_control = AluControl::SetOnLessThanUnsigned, - 4 => self.signals.alu_control = AluControl::Xor, + 1 => self.signals.alu_op = AluOp::ShiftLeftLogical(self.state.rs2), + 2 => self.signals.alu_op = AluOp::SetOnLessThanSigned, + 3 => self.signals.alu_op = AluOp::SetOnLessThanUnsigned, + 4 => self.signals.alu_op = AluOp::Xor, 5 => match r.funct7 { - 0b0000000 => self.signals.alu_control = AluControl::ShiftRightLogical(self.state.rs2), - 0b0100000 => self.signals.alu_control = AluControl::ShiftRightArithmetic(self.state.rs2) + 0b0000000 => self.signals.alu_op = AluOp::ShiftRightLogical(self.state.rs2), + 0b0100000 => self.signals.alu_op = AluOp::ShiftRightArithmetic(self.state.rs2) } - 6 => self.signals.alu_control = AluControl::Or, - 7 => self.signals.alu_control = AluControl::And + 6 => self.signals.alu_op = AluOp::Or, + 7 => self.signals.alu_op = AluOp::And } } @@ -568,49 +567,41 @@ impl RiscDatapath { /// case where the instruction is an I-type. fn set_itype_control_signals(&mut self, i: IType) { self.signals = ControlSignals { - alu_src: AluSrc::SignExtendedImmediate, - branch: Branch::NoBranch, - jump: Jump::NoJump, - mem_read: MemRead::NoRead, - mem_write: MemWrite::NoWrite, - mem_to_reg: MemToReg::UseAlu, reg_dst: RegDst::Reg3, - reg_width: RegWidth::Word, - reg_write: RegWrite::YesWrite, + reg_write_en: RegWriteEn::YesWrite, ..Default::default() }; match i.op { OPCODE_IMM => match i.funct3 { - 0 => self.signals.alu_control = AluControl::Addition, - 1 => self.signals.alu_control = AluControl::ShiftLeftLogical(self.state.shamt), + 0 => self.signals.alu_op = AluOp::Addition, + 1 => self.signals.alu_op = AluOp::ShiftLeftLogical(self.state.shamt), - 2 => self.signals.alu_control = AluControl::SetOnLessThanSigned, - 3 => self.signals.alu_control = AluControl::SetOnLessThanUnsigned, - 4 => self.signals.alu_control = AluControl::Xor, + 2 => self.signals.alu_op = AluOp::SetOnLessThanSigned, + 3 => self.signals.alu_op = AluOp::SetOnLessThanUnsigned, + 4 => self.signals.alu_op = AluOp::Xor, 5 => { match (i.imm >> 5) { - 0b0000000 => self.signals.alu_control = AluControl::ShiftRightLogical(self.state.shamt), - 0b0100000 => self.signals.alu_control = AluControl::ShiftRightArithmetic(self.state.shamt), + 0b0000000 => self.signals.alu_op = AluOp::ShiftRightLogical(self.state.shamt), + 0b0100000 => self.signals.alu_op = AluOp::ShiftRightArithmetic(self.state.shamt), }; } - 6 => self.signals.alu_control = AluControl::Or, - 7 => self.signals.alu_control = AluControl::And, + 6 => self.signals.alu_op = AluOp::Or, + 7 => self.signals.alu_op = AluOp::And, } OPCODE_JALR => { - self.signals.alu_src = AluSrc::ZeroExtendedImmediate; - self.signals.mem_to_reg = MemToReg::UsePcPlusFour; - self.signals.jump = Jump::YesJumpJalr; + self.signals.imm_select = ImmSelect::IUnsigned; + self.signals.wb_sel = WBSel::UsePcPlusFour; + self.signals.branch_jump = BranchJump::J; } OPCODE_LOAD => { - self.signals.mem_to_reg = MemToReg::UseMemory; - self.signals.mem_write = MemWrite::YesWrite; + self.signals.wb_sel = WBSel::UseMemory; match i.funct3 { - 0 => self.signals.reg_width = RegWidth::Byte, - 1 => self.signals.reg_width = RegWidth::HalfWord, - 2 => self.signals.reg_width = RegWidth::Word, - 4 => self.signals.reg_width = RegWidth::ByteUnsigned, - 5 => self.signals.reg_width = RegWidth::HalfWordUnsigned + 0 => self.signals.read_write = ReadWrite::LoadByte, + 1 => self.signals.read_write = ReadWrite::LoadHalf, + 2 => self.signals.read_write = ReadWrite::LoadWord, + 4 => self.signals.read_write = ReadWrite::LoadByteUnsigned, + 5 => self.signals.read_write = ReadWrite::LoadHalfUnsigned, } } } @@ -620,19 +611,15 @@ impl RiscDatapath { /// case where the instruction is an S-type. fn set_stype_control_signals(&mut self, s: SType) { self.signals = ControlSignals { - alu_src: AluSrc::ZeroExtendedImmediate, - branch: Branch::NoBranch, - jump: Jump::NoJump, - mem_read: MemRead::YesRead, - mem_write: MemWrite::NoWrite, - reg_write: RegWrite::NoWrite, + imm_select: ImmSelect::IUnsigned, + reg_write_en: RegWriteEn::NoWrite, ..Default::default() }; match s.funct3 { - 0 => self.signals.reg_width = RegWidth::Byte, - 1 => self.signals.reg_width = RegWidth::HalfWord, - 2 => self.signals.reg_width = RegWidth::Word, + 0 => self.signals.read_write = ReadWrite::StoreByte, + 1 => self.signals.read_write = ReadWrite::StoreHalf, + 2 => self.signals.read_write = ReadWrite::StoreWord, } } @@ -640,23 +627,18 @@ impl RiscDatapath { /// case where the instruction is an B-type. fn set_btype_control_signals(&mut self, b: BType) { self.signals = ControlSignals { - alu_src: AluSrc::ZeroExtendedImmediate, - branch: Branch::YesBranch, - jump: Jump::NoJump, - mem_read: MemRead::NoRead, - mem_write: MemWrite::NoWrite, - reg_write: RegWrite::NoWrite, - reg_width: RegWidth::Word, + imm_select: ImmSelect::IUnsigned, + reg_write_en: RegWriteEn::NoWrite, ..Default::default() }; match b.funct3 { - 0 => self.signals.branch_type = BranchType::OnEqual, - 1 => self.signals.branch_type = BranchType::OnNotEqual, - 4 => self.signals.branch_type = BranchType::OnLessThan, - 5 => self.signals.branch_type = BranchType::OnGreaterEqual, - 6 => self.signals.branch_type = BranchType::OnLessThanUnsigned, - 7 => self.signals.branch_type = BranchType::OnGreaterEqualUnsigned, + 0 => self.signals.branch_jump = BranchJump::Beq, + 1 => self.signals.branch_jump = BranchJump::Bne, + 4 => self.signals.branch_jump = BranchJump::Blt, + 5 => self.signals.branch_jump = BranchJump::Bge, + 6 => self.signals.branch_jump = BranchJump::Bltu, + 7 => self.signals.branch_jump = BranchJump::Bgeu, } } @@ -664,33 +646,25 @@ impl RiscDatapath { /// case where the instruction is an U-type. fn set_utype_control_signals(&mut self, u: UType) { self.signals = ControlSignals { - alu_src: AluSrc::ZeroExtendedImmediate, - branch: Branch::NoBranch, - jump: Jump::NoJump, - mem_read: MemRead::NoRead, - mem_write: MemWrite::NoWrite, + imm_select: ImmSelect::IUnsigned, reg_dst: RegDst::Reg3, - reg_width: RegWidth::Word, - reg_write: RegWrite::YesWrite, + reg_write_en: RegWriteEn::YesWrite, ..Default::default() }; match u.op { - OPCODE_AUIPC => self.signals.mem_to_reg = MemToReg::UseAlu, - OPCODE_LUI => self.signals.mem_to_reg = MemToReg::UseImmediate, + OPCODE_AUIPC => self.signals.wb_sel = WBSel::UseAlu, + OPCODE_LUI => self.signals.wb_sel = WBSel::UseImmediate, } } /// Set control signals for J-Type instructions fn set_jtype_control_signals(&mut self, j: JType) { self.signals = ControlSignals { - alu_src: AluSrc::ZeroExtendedImmediate, - branch: Branch::NoBranch, - jump: Jump::YesJump, - mem_read: MemRead::NoRead, - mem_write: MemWrite::NoWrite, - mem_to_reg: MemToReg::UsePcPlusFour, - reg_write: RegWrite::YesWrite, + imm_select: ImmSelect::IUnsigned, + branch_jump: BranchJump::J, + wb_sel: WBSel::UsePcPlusFour, + reg_write_en: RegWriteEn::YesWrite, ..Default::default() }; } @@ -700,16 +674,6 @@ impl RiscDatapath { fn read_registers(&mut self) { self.state.read_data_1 = self.registers.gpr[self.state.rs1 as usize]; self.state.read_data_2 = self.registers.gpr[self.state.rs2 as usize]; - - // Truncate the variable data if a 32-bit word is requested. - if let RegWidth::Word = self.signals.reg_width { - self.state.read_data_1 = self.state.read_data_1 as u32 as u64; - self.state.read_data_2 = self.state.read_data_2 as u32 as u64; - } - } - - fn shift_lower_26_left_by_2(&mut self) { - self.state.lower_26_shifted_left_by_2 = self.state.lower_26 << 2; } fn construct_jump_address(&mut self) { @@ -731,63 +695,52 @@ impl RiscDatapath { // second register, the sign-extended immediate value, or the // zero-extended immediate value. self.state.alu_input1 = self.state.read_data_1; - self.state.alu_input2 = match self.signals.alu_src { - AluSrc::ReadRegister2 => self.state.read_data_2, - AluSrc::SignExtendedImmediate => alu_immediate, - AluSrc::ZeroExtendedImmediate => self.state.imm as u64, + self.state.alu_input2 = match self.signals.op2_select { + OP2Select::DATA2 => self.state.read_data_2, + OP2Select::IMM => self.state.imm as u64, }; - // Truncate the inputs if 32-bit operations are expected. - if let RegWidth::Word = self.signals.reg_width { - self.state.alu_input1 = self.state.alu_input1 as i32 as u64; - self.state.alu_input2 = self.state.alu_input2 as i32 as u64; - } - // Set the result. - self.state.alu_result = match self.signals.alu_control { - AluControl::Addition => self.state.alu_input1.wrapping_add(self.state.alu_input2), - AluControl::Subtraction => { + self.state.alu_result = match self.signals.alu_op { + AluOp::Addition => self.state.alu_input1.wrapping_add(self.state.alu_input2), + AluOp::Subtraction => { (self.state.alu_input1 as i64).wrapping_sub(self.state.alu_input2 as i64) as u64 } - AluControl::SetOnLessThanSigned => { + AluOp::SetOnLessThanSigned => { ((self.state.alu_input1 as i64) < (self.state.alu_input2 as i64)) as u64 } - AluControl::SetOnLessThanUnsigned => { + AluOp::SetOnLessThanUnsigned => { (self.state.alu_input1 < self.state.alu_input2) as u64 } - AluControl::And => self.state.alu_input1 & self.state.alu_input2, - AluControl::Or => self.state.alu_input1 | self.state.alu_input2, - AluControl::Xor => self.state.alu_input1 ^ self.state.alu_input2, - AluControl::ShiftLeftLogical(shamt) => self.state.alu_input2 << shamt, - AluControl::ShiftRightLogical(shamt) => self.state.alu_input2 >> shamt, - AluControl::ShiftRightArithmetic(shamt) => (self.state.alu_input2 as i32 >> shamt) as u64, - AluControl::MultiplicationSigned => { + AluOp::And => self.state.alu_input1 & self.state.alu_input2, + AluOp::Or => self.state.alu_input1 | self.state.alu_input2, + AluOp::Xor => self.state.alu_input1 ^ self.state.alu_input2, + AluOp::ShiftLeftLogical(shamt) => self.state.alu_input2 << shamt, + AluOp::ShiftRightLogical(shamt) => self.state.alu_input2 >> shamt, + AluOp::ShiftRightArithmetic(shamt) => (self.state.alu_input2 as i32 >> shamt) as u64, + AluOp::MultiplicationSigned => { ((self.state.alu_input1 as i128) * (self.state.alu_input2 as i128)) as u64 } - AluControl::MultiplicationUnsigned => { + AluOp::MultiplicationUnsigned => { ((self.state.alu_input1 as u128) * (self.state.alu_input2 as u128)) as u64 } - AluControl::DivisionSigned => { + AluOp::DivisionSigned => { if self.state.alu_input2 == 0 { 0 } else { ((self.state.alu_input1 as i64) / (self.state.alu_input2 as i64)) as u64 } } - AluControl::DivisionUnsigned => { + AluOp::DivisionUnsigned => { if self.state.alu_input2 == 0 { 0 } else { self.state.alu_input1 / self.state.alu_input2 } } + _ => 0, }; - // Truncate and sign-extend the output if 32-bit operations are expected. - if let RegWidth::Word = self.signals.reg_width { - self.state.alu_result = self.state.alu_result as i32 as i64 as u64; - } - // Set the zero bit/signal. self.datapath_signals.alu_z = match self.state.alu_result { 0 => AluZ::YesZero, @@ -815,12 +768,12 @@ impl RiscDatapath { // // Depending on the branch type, this may use the ALU's Zero signal // as-is or inverted. - let condition_is_true = match self.signals.branch_type { - BranchType::OnEqual => self.datapath_signals.alu_z == AluZ::YesZero, - BranchType::OnNotEqual => self.datapath_signals.alu_z == AluZ::NoZero, + let condition_is_true = match self.signals.branch_jump { + BranchJump::Beq => self.datapath_signals.alu_z == AluZ::YesZero, + _ => self.datapath_signals.alu_z == AluZ::NoZero, }; - if self.signals.branch == Branch::YesBranch && condition_is_true { + if self.signals.branch_jump != BranchJump::NoBranch && condition_is_true { self.datapath_signals.cpu_branch = CpuBranch::YesBranch; } } @@ -903,17 +856,17 @@ impl RiscDatapath { fn register_write(&mut self) { // Determine what data will be sent to the register: either // the result from the ALU, or data retrieved from memory. - self.state.data_result = match self.signals.mem_to_reg { - MemToReg::UseAlu => self.state.alu_result, - MemToReg::UseMemory => self.state.memory_data, - MemToReg::UsePcPlusFour => self.state.pc_plus_4, + self.state.data_result = match self.signals.wb_sel { + WBSel::UseAlu => self.state.alu_result, + WBSel::UseMemory => self.state.memory_data, + WBSel::UsePcPlusFour => self.state.pc_plus_4, }; // Decide to retrieve data either from the main processor or the coprocessor. self.state.register_write_data = self.state.data_result; // Abort if the RegWrite signal is not set. - if self.signals.reg_write == RegWrite::NoWrite { + if self.signals.reg_write_en == RegWriteEn::NoWrite { return; } @@ -931,11 +884,6 @@ impl RiscDatapath { return; } - // If a 32-bit word is requested, ensure data is truncated and sign-extended. - if let RegWidth::Word = self.signals.reg_width { - self.state.data_result = self.state.data_result as i32 as u64; - } - // Write. self.registers.gpr[self.state.write_register_destination] = self.state.register_write_data; } From 4728d39a210b3dbc0d05e8081f474bddb7e7e5d1 Mon Sep 17 00:00:00 2001 From: rharding8 Date: Fri, 2 Feb 2024 18:17:22 -0500 Subject: [PATCH 028/355] Removed one file to make Git Checks work. --- src/emulation_core/riscv.rs | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 src/emulation_core/riscv.rs diff --git a/src/emulation_core/riscv.rs b/src/emulation_core/riscv.rs deleted file mode 100644 index 9eef52183..000000000 --- a/src/emulation_core/riscv.rs +++ /dev/null @@ -1,12 +0,0 @@ -//! All facets of this project's implementation of the MIPS64 ISA, including -//! the datapath, control signals, registers, and memory. - -pub mod constants; -pub mod control_signals; -pub mod coprocessor; -pub mod datapath; -pub mod datapath_signals; -pub mod instruction; -pub mod line_info; -pub mod memory; -pub mod registers; From 39ac465761ca3d39120a0d80e1a24824e2e55262 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Fri, 2 Feb 2024 18:37:28 -0500 Subject: [PATCH 029/355] Remove the MemoryType type alias from the Datapath trait to make it more generic --- src/agent.rs | 11 ++--------- src/emulation_core/datapath.rs | 12 ++++-------- src/emulation_core/mips/datapath.rs | 3 +-- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index 7ae3acac9..a77b3c1c0 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -3,7 +3,6 @@ use crate::agent::messages::{Command, StateUpdate}; use crate::emulation_core::datapath::Datapath; use crate::emulation_core::mips::datapath::{MipsDatapath, Stage}; -use crate::emulation_core::mips::memory::Memory; use crate::emulation_core::mips::registers::GpRegisterType; use futures::{FutureExt, StreamExt}; use gloo_console::log; @@ -38,14 +37,8 @@ pub async fn emulation_core_agent(scope: ReactorScope) { } struct EmulatorCoreAgentState { - current_datapath: Box< - dyn Datapath< - MemoryType = Memory, - RegisterData = u64, - RegisterEnum = GpRegisterType, - StageEnum = Stage, - >, - >, + current_datapath: + Box>, pub scope: ReactorScope, speed: u32, executing: bool, diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index 21c80534d..00081844a 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -1,6 +1,7 @@ //! Module for the API of a generic datapath. use crate::emulation_core::mips::line_info::LineInformation; +use crate::emulation_core::mips::memory::Memory; /// A generic datapath. /// @@ -24,11 +25,6 @@ pub trait Datapath { /// at the discretion of the developer. type RegisterEnum; - /// The data type that describes memory for this datapath. This must be - /// defined separately. This allows raw access to any parts of memory - /// or its own interface at will. - type MemoryType; - /// This enum describes all possible stages in the datapath. This is /// used primarily for the visual datapath view. Must be convertable /// into a string for highlighting purposes. @@ -60,15 +56,15 @@ pub trait Datapath { /// Loads the instructions from the provided array into an emulation core's /// memory. This will also clear the memory of the emulation core and reset /// the core's program counter. - fn load_instructions(&mut self, instructions: &[Self::MemoryType]) { + fn load_instructions(&mut self, instructions: &[u8]) { self.reset(); self.set_memory(0, instructions); } /// Retrieve all memory as-is. - fn get_memory(&self) -> &Self::MemoryType; + fn get_memory(&self) -> &Memory; - fn set_memory(&mut self, _ptr: usize, _data: &[Self::MemoryType]) { + fn set_memory(&mut self, _ptr: usize, _data: &[u8]) { todo!() } diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index 072ec2fb7..e982d3c96 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -222,7 +222,6 @@ impl Default for MipsDatapath { impl Datapath for MipsDatapath { type RegisterData = u64; type RegisterEnum = super::registers::GpRegisterType; - type MemoryType = Memory; type StageEnum = Stage; @@ -269,7 +268,7 @@ impl Datapath for MipsDatapath { self.registers[register] } - fn get_memory(&self) -> &Self::MemoryType { + fn get_memory(&self) -> &Memory { &self.memory } From 0b15f91f59b4de9aad8707c90e165fac0a3532cd Mon Sep 17 00:00:00 2001 From: Cay Date: Fri, 2 Feb 2024 19:16:00 -0500 Subject: [PATCH 030/355] Adds cross references, converts curr_line variables to use state --- src/bin/main.rs | 24 +++++++------- src/ui/assembled_view/component.rs | 51 +++++++++++++++++------------- src/ui/console/component.rs | 4 +-- src/ui/hex_editor/component.rs | 25 ++++++--------- src/ui/regview/component.rs | 3 +- src/ui/swim_editor/component.rs | 18 +++++------ 6 files changed, 62 insertions(+), 63 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index d03c45299..731393e5e 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -67,8 +67,9 @@ fn app(props: &AppProps) -> Html { // was executed after the execute button is pressed. let executed_line = js_sys::Array::new(); let not_highlighted = js_sys::Array::new(); - let curr_line = use_mut_ref(|| 0.0); - let memory_curr_line = use_mut_ref(|| 0.0); + let editor_curr_line = use_state_eq(|| 0.0); + // let memory_curr_line = use_mut_ref(|| 0.0); + let memory_curr_line = use_state_eq(|| 0.0); // Setting up the options/parameters which // will highlight the previously executed line. @@ -222,7 +223,7 @@ fn app(props: &AppProps) -> Html { let executed_line = executed_line.clone(); let not_highlighted = not_highlighted.clone(); let highlight_decor = highlight_decor.clone(); - let curr_line = Rc::clone(&curr_line); + let editor_curr_line = editor_curr_line.clone(); // Hex editor let memory_text_model = Rc::clone(&memory_text_model); @@ -230,13 +231,13 @@ fn app(props: &AppProps) -> Html { let trigger = use_force_update(); use_callback( - move |_, _| { + move |_, editor_curr_line| { let mut datapath = datapath.borrow_mut(); let text_model = text_model.borrow_mut(); let highlight_decor = highlight_decor.borrow_mut(); let memory_text_model = memory_text_model.borrow_mut(); let last_memory_text_model = last_memory_text_model.borrow_mut(); - let mut curr_line = curr_line.borrow_mut(); + // let mut editor_curr_line = editor_curr_line.borrow_mut(); // Pull ProgramInfo from the parser let (programinfo, _) = parser(text_model.get_value()); @@ -244,11 +245,12 @@ fn app(props: &AppProps) -> Html { // Get the current line and convert it to f64 let list_of_line_numbers = programinfo.address_to_line_number; let index = datapath.registers.pc as usize / 4; - *curr_line = *list_of_line_numbers.get(index).unwrap_or(&0) as f64 + 1.0; // add one to account for the editor's line numbers + editor_curr_line.set(*list_of_line_numbers.get(index).unwrap_or(&0) as f64 + 1.0); // add one to account for the editor's line numbers + debug!("Setting curr line to {}", **editor_curr_line); // Setup the range let curr_model = text_model.as_ref(); - let curr_range = monaco::sys::Range::new(*curr_line, 0.0, *curr_line, 0.0); + let curr_range = monaco::sys::Range::new(**editor_curr_line, 0.0, **editor_curr_line, 0.0); // element to be stored in the stack to highlight the line let highlight_line: monaco::sys::editor::IModelDeltaDecoration = @@ -301,7 +303,7 @@ fn app(props: &AppProps) -> Html { trigger.force_update(); }, - (), + editor_curr_line, ) }; @@ -333,9 +335,9 @@ fn app(props: &AppProps) -> Html { let (programinfo, _) = parser(text_model.get_value()); let list_of_line_numbers = programinfo.address_to_line_number; let index = datapath.registers.pc as usize / 4; - let curr_line = *list_of_line_numbers.get(index).unwrap_or(&0) as f64 + 1.0; + let editor_curr_line = *list_of_line_numbers.get(index).unwrap_or(&0) as f64 + 1.0; let curr_model = text_model.as_ref(); - let curr_range = monaco::sys::Range::new(curr_line, 0.0, curr_line, 0.0); + let curr_range = monaco::sys::Range::new(editor_curr_line, 0.0, editor_curr_line, 0.0); let highlight_line: monaco::sys::editor::IModelDeltaDecoration = Object::new().unchecked_into(); highlight_line.set_options(&highlight_decor); @@ -652,7 +654,7 @@ fn app(props: &AppProps) -> Html { // Editor
- +
// Console diff --git a/src/ui/assembled_view/component.rs b/src/ui/assembled_view/component.rs index 86787ee9f..79c4cc383 100644 --- a/src/ui/assembled_view/component.rs +++ b/src/ui/assembled_view/component.rs @@ -8,13 +8,17 @@ use yew::prelude::*; use wasm_bindgen::JsCast; use log::debug; use crate::parser::parser_structs_and_enums::ProgramInfo; +use crate::ui::swim_editor::component::EditorTabState; #[derive(PartialEq, Properties)] pub struct TextSegmentProps { pub program_info: ProgramInfo, pub lines_content: Rc>>, - pub pc: u64 + pub memory_curr_line: UseStateHandle, + pub editor_curr_line: UseStateHandle, + pub pc: u64, + pub active_tab: UseStateHandle, } #[derive(PartialEq, Properties)] pub struct DataSegmentProps { @@ -27,6 +31,9 @@ pub struct DataSegmentProps { pub fn TextSegment(props: &TextSegmentProps) -> Html { let program_info = &props.program_info; let lines_content = props.lines_content.borrow_mut().clone(); + let memory_curr_line = &props.memory_curr_line; + let editor_curr_line = &props.editor_curr_line; + let active_tab = &props.active_tab; let on_check = Callback::from(move |args: (MouseEvent, i64)| { let (e, address) = args; @@ -39,25 +46,23 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html { }); - let on_address_click = Callback::from(move |args: (MouseEvent, i64)| { - let (_e, address) = args; - // let target = e.target(); - // let input = target.unwrap().unchecked_into::(); - - debug!("Go to address {:08x}", address); - debug!("Go to line {:?}", (address / 4) as f64); - // memory_curr_line.set((address / 4) as f64); - - }); - - let on_assembled_click = Callback::from(move |args: (MouseEvent, i64)| { - let (_e, line_number) = args; - // let target = e.target(); - // let input = target.unwrap().unchecked_into::(); - - debug!("Go to line number {:08x}", line_number); - - }); + let on_address_click = { + let memory_curr_line = memory_curr_line.clone(); + use_callback(move |args: (MouseEvent, i64), memory_curr_line| { + let (_e, address) = args; + memory_curr_line.set((address / 4) as f64); + }, memory_curr_line) + }; + + let on_assembled_click = { + let editor_curr_line = editor_curr_line.clone(); + let active_tab = active_tab.clone(); + use_callback(move |args: (MouseEvent, usize), _| { + let (_e, line_number) = args; + editor_curr_line.set(line_number as f64); + active_tab.set(EditorTabState::Editor); + }, ()) + }; let mut address = -4; html! { @@ -82,6 +87,8 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html { if props.pc as i64 == address { conditional_class = "executing"; } + + let line_number = instruction.line_number.clone(); html!{ @@ -98,11 +105,11 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html { {format!("0x{:08x}", instruction.binary)} - + {recreated_string} - {format!("{}: {:?}", instruction.line_number, lines_content.get(instruction.line_number).unwrap_or(&String::from("")))} + {format!("{}: {:?}", line_number, lines_content.get(line_number).unwrap_or(&String::from("")))} } diff --git a/src/ui/console/component.rs b/src/ui/console/component.rs index 96c7b5d40..a63a43356 100644 --- a/src/ui/console/component.rs +++ b/src/ui/console/component.rs @@ -19,7 +19,7 @@ pub struct Consoleprops { pub datapath: MipsDatapath, pub parsermsg: String, pub memory_text_model: Rc>, - pub memory_curr_line: Rc> + pub memory_curr_line: UseStateHandle } #[derive(Default, PartialEq)] @@ -98,7 +98,7 @@ pub fn console(props: &Consoleprops) -> Html {
} else if *active_tab == TabState::HexEditor {
- +
}
diff --git a/src/ui/hex_editor/component.rs b/src/ui/hex_editor/component.rs index 05f9bdaf1..1a3d36e33 100644 --- a/src/ui/hex_editor/component.rs +++ b/src/ui/hex_editor/component.rs @@ -1,6 +1,6 @@ use js_sys::Object; use wasm_bindgen::{closure::Closure, JsValue}; -use yew::{function_component, html, Html, Properties, use_callback}; +use yew::{function_component, html, use_callback, Html, Properties, UseStateHandle}; use std::rc::Rc; use std::cell::RefCell; use log::debug; @@ -10,25 +10,22 @@ use monaco::{ api::TextModel, sys:: editor::{ - IEditorMinimapOptions, IEditorScrollbarOptions, IStandaloneEditorConstructionOptions, ISuggestOptions + IEditorMinimapOptions, IEditorScrollbarOptions, IStandaloneEditorConstructionOptions, ISuggestOptions, ScrollType }, yew::{CodeEditor, CodeEditorLink}, }; #[derive(PartialEq, Properties)] pub struct HexEditorProps { pub memory_text_model: Rc>, - pub curr_line: Rc> + pub curr_line: UseStateHandle } #[function_component(HexEditor)] pub fn hex_editor(props: &HexEditorProps) -> Html { let editor_link = CodeEditorLink::new(); - // let text_model = Rc::clone(&props.memory_text_model); - // let curr_line = Rc::clone(&props.curr_line); - // let not_highlighted = js_sys::Array::new(); - // let mut mutated = false; + let curr_line = *props.curr_line; - // create a JavaScript closure + // create a JavaScript closure for hex highlighting let cb = Closure::wrap(Box::new(move |event: monaco::sys::editor::ICursorSelectionChangedEvent| { let highlight_decor = monaco::sys::editor::IModelDecorationOptions::default(); highlight_decor.set_class_name("hexHighlight".into()); @@ -65,27 +62,23 @@ pub fn hex_editor(props: &HexEditorProps) -> Html { }) as Box); let on_editor_created = { - let text_model = Rc::clone(&props.memory_text_model); - // let curr_line = Rc::clone(&curr_line); + let curr_line = curr_line; use_callback( - move |editor_link: CodeEditorLink, _text_model| { - // let curr_line = curr_line.borrow_mut(); + move |editor_link: CodeEditorLink, curr_line| { match editor_link.with_editor(|editor| { let raw_editor = editor.as_ref(); - - debug!("Helo!"); let cb_func = &cb.as_ref().unchecked_ref(); raw_editor.on_did_change_cursor_selection(cb_func); - // raw_editor.reveal_line_in_center(*curr_line, Some(ScrollType::Smooth)) + raw_editor.reveal_line_in_center(*curr_line, Some(ScrollType::Smooth)) }) { Some(()) => debug!("Hex Editor linked!"), None => debug!("No editor :<") }; }, - text_model, + curr_line, ) }; html! { diff --git a/src/ui/regview/component.rs b/src/ui/regview/component.rs index 0456007eb..b48550d51 100644 --- a/src/ui/regview/component.rs +++ b/src/ui/regview/component.rs @@ -292,8 +292,7 @@ pub fn regview(props: &Regviewprops) -> Html { UnitState::Dec => "Decimal", UnitState::Hex => "Hex", UnitState::Float => "Float", - UnitState::Double => "Double", - _ => "dec", + UnitState::Double => "Double" } }> diff --git a/src/ui/swim_editor/component.rs b/src/ui/swim_editor/component.rs index 1fb9894fb..5c5ede839 100644 --- a/src/ui/swim_editor/component.rs +++ b/src/ui/swim_editor/component.rs @@ -18,12 +18,12 @@ pub struct SwimEditorProps { pub program_info: ProgramInfo, pub binary: Vec, pub pc: u64, - pub memory_curr_line: Rc>, - pub curr_line: Rc> + pub memory_curr_line: UseStateHandle, + pub editor_curr_line: UseStateHandle } #[derive(Default, PartialEq)] -enum EditorTabState { +pub enum EditorTabState { #[default] Editor, TextSegment, @@ -61,13 +61,11 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html { let link = CodeEditorLink::new(); let on_editor_created = { - let text_model = Rc::clone(&props.text_model); - let curr_line = Rc::clone(&props.curr_line); + let curr_line = props.editor_curr_line.clone(); let lines_content = Rc::clone(&props.lines_content); use_callback( - move |editor_link: CodeEditorLink, _text_model| { - let curr_line = curr_line.borrow_mut(); + move |editor_link: CodeEditorLink, curr_line| { match editor_link.with_editor(|editor| { let raw_editor = editor.as_ref(); let model = raw_editor.get_model().unwrap(); @@ -82,13 +80,13 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html { string_lines.push(string_value); }; - raw_editor.reveal_line_in_center(*curr_line, Some(ScrollType::Smooth)); + raw_editor.reveal_line_in_center(**curr_line, Some(ScrollType::Smooth)); }) { Some(()) => debug!("Editor linked!"), None => debug!("No editor :<") }; }, - text_model, + curr_line, ) }; @@ -136,7 +134,7 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html { if *active_tab == EditorTabState::Editor { } else if *active_tab == EditorTabState::TextSegment { - + } else if *active_tab == EditorTabState::DataSegment { } From a498a1cf85004e126f5168ffd1e610651c321d44 Mon Sep 17 00:00:00 2001 From: Cay Date: Sat, 3 Feb 2024 22:24:27 -0500 Subject: [PATCH 031/355] replace text_model with use_state_eq --- src/bin/main.rs | 263 +++++++++++--------------------- src/ui/console/component.rs | 25 +-- src/ui/hex_editor/component.rs | 5 +- src/ui/swim_editor/component.rs | 56 +++++-- 4 files changed, 144 insertions(+), 205 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index 731393e5e..591a57290 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -14,7 +14,7 @@ use monaco::{ IMarkdownString, MarkerSeverity, } }; -use swim::parser::parser_assembler_main::parser; +use swim::{parser::parser_assembler_main::parser, ui::{console::component::TabState, swim_editor::component::EditorTabState}}; use swim::parser::parser_structs_and_enums::ProgramInfo; use std::rc::Rc; use swim::agent::EmulationCoreAgent; @@ -56,33 +56,17 @@ fn app(props: &AppProps) -> Html { // use_state_eq hook is created so that the component can be updated // when the text model changes. //let text_model = use_mut_ref(|| TextModel::create(&code, Some(&language), None).unwrap()); - let text_model = use_mut_ref(|| TextModel::create(CONTENT, Some("mips"), None).unwrap()); + let text_model = use_state_eq(|| TextModel::create(CONTENT, Some("mips"), None).unwrap()); // Setup the array that would store decorations applied to the // text model and initialize the options for it. let hover_jsarray = js_sys::Array::new(); let hover_decor_array = use_mut_ref(js_sys::Array::new); - // Setup the highlight stacks that would store which line - // was executed after the execute button is pressed. - let executed_line = js_sys::Array::new(); - let not_highlighted = js_sys::Array::new(); + // Store the currently executed line in code editor and hex editor let editor_curr_line = use_state_eq(|| 0.0); - // let memory_curr_line = use_mut_ref(|| 0.0); let memory_curr_line = use_state_eq(|| 0.0); - // Setting up the options/parameters which - // will highlight the previously executed line. - // The highlight decor does not need to be changed, - // the only parameter that will change is the range. - let highlight_decor = use_mut_ref(monaco::sys::editor::IModelDecorationOptions::default); - (*highlight_decor) - .borrow_mut() - .set_is_whole_line(true.into()); - (*highlight_decor) - .borrow_mut() - .set_inline_class_name("myInlineDecoration".into()); - // Output strings for the console and memory viewers. let parser_text_output = use_state_eq(String::new); let memory_text_output = use_state_eq(String::new); @@ -94,9 +78,14 @@ fn app(props: &AppProps) -> Html { let program_info_ref = use_mut_ref(ProgramInfo::default); let binary_ref = use_mut_ref(Vec::::new); - let last_memory_text_model = use_mut_ref(|| TextModel::create(&memory_text_output, Some("ini"), None).unwrap()); + // let last_memory_text_model = use_mut_ref(|| TextModel::create(&memory_text_output, Some("ini"), None).unwrap()); + // let memory_text_model = use_mut_ref(|| TextModel::create(&memory_text_output, Some("ini"), None).unwrap()); + let last_memory_text_model = use_state_eq(|| TextModel::create(&memory_text_output, Some("ini"), None).unwrap()); + let memory_text_model = use_state_eq(|| TextModel::create(&memory_text_output, Some("ini"), None).unwrap()); - let memory_text_model = use_mut_ref(|| TextModel::create(&memory_text_output, Some("ini"), None).unwrap()); + // Store the currently selected tabs in windows + let console_active_tab = use_state_eq(TabState::default); + let editor_active_tab = use_state_eq(EditorTabState::default); // Since we want the Datapath to be independent from all the // events within the app, we will create it when the app loads. This is also done @@ -118,33 +107,34 @@ fn app(props: &AppProps) -> Html { let on_assemble_clicked = { // props.communicator.send_test_message(1); // Test message, remove later. let communicator = props.communicator; - let text_model = Rc::clone(&text_model); - let memory_text_model = Rc::clone(&memory_text_model); + // let text_model = Rc::clone(&text_model); + let text_model = text_model.clone(); + // let memory_text_model = Rc::clone(&memory_text_model); + let memory_text_model = memory_text_model.clone(); + // let last_memory_text_model = Rc::clone(&last_memory_text_model); + let last_memory_text_model = last_memory_text_model.clone(); let datapath = Rc::clone(&datapath); let parser_text_output = parser_text_output.clone(); - let trigger = use_force_update(); + let editor_curr_line = editor_curr_line.clone(); - let executed_line = executed_line.clone(); - let not_highlighted = not_highlighted.clone(); // Clone the value before moving it into the closure - let last_memory_text_model = Rc::clone(&last_memory_text_model); let pc_limit = pc_limit.clone(); let program_info_ref = Rc::clone(&program_info_ref); let binary_ref = Rc::clone(&binary_ref); use_callback( - move |_, text_model| { + move |_, (text_model, editor_curr_line)| { communicator.send_test_message(); // Test message, remove later. let mut datapath = datapath.borrow_mut(); - let text_model = text_model.borrow_mut(); - let memory_text_model = memory_text_model.borrow_mut(); + let text_model = text_model.clone(); + let memory_text_model = memory_text_model.clone(); // parses through the code to assemble the binary and retrieves programinfo for error marking and mouse hover let (program_info, assembled) = parser(text_model.get_value()); *program_info_ref.borrow_mut() = program_info.clone(); *binary_ref.borrow_mut() = assembled.clone(); pc_limit.set(assembled.len() * 4); parser_text_output.set(program_info.console_out_post_assembly); - let last_memory_text_model = last_memory_text_model.borrow_mut(); + let last_memory_text_model = last_memory_text_model.clone(); let mut markers: Vec = vec![]; @@ -175,15 +165,9 @@ fn app(props: &AppProps) -> Html { "owner", &marker_jsarray, ); - // Acts like reset and clears the highlight - let curr_model = text_model.as_ref(); - executed_line.pop(); - not_highlighted.set( - 0, - curr_model - .delta_decorations(¬_highlighted, &executed_line, None) - .into(), - ); + + // Reset highlighted line to 0 + editor_curr_line.set(0.0); // Proceed with loading into memory and expand pseudo-instructions if there are no errors. if marker_jsarray.length() == 0 { @@ -202,10 +186,8 @@ fn app(props: &AppProps) -> Html { last_memory_text_model.set_value(hexdump); datapath.registers.pc = program_info.pc_starting_point as u64; } - - trigger.force_update(); }, - text_model, + (text_model, editor_curr_line), ) }; @@ -219,24 +201,24 @@ fn app(props: &AppProps) -> Html { let datapath = Rc::clone(&datapath); // Code editor - let text_model = Rc::clone(&text_model); - let executed_line = executed_line.clone(); - let not_highlighted = not_highlighted.clone(); - let highlight_decor = highlight_decor.clone(); + // let text_model = Rc::clone(&text_model); + let text_model = text_model.clone(); let editor_curr_line = editor_curr_line.clone(); // Hex editor - let memory_text_model = Rc::clone(&memory_text_model); - let last_memory_text_model = Rc::clone(&last_memory_text_model); - let trigger = use_force_update(); + // let memory_text_model = Rc::clone(&memory_text_model); + let memory_text_model = memory_text_model.clone(); + // let last_memory_text_model = Rc::clone(&last_memory_text_model); + let last_memory_text_model = last_memory_text_model.clone(); use_callback( move |_, editor_curr_line| { let mut datapath = datapath.borrow_mut(); - let text_model = text_model.borrow_mut(); - let highlight_decor = highlight_decor.borrow_mut(); - let memory_text_model = memory_text_model.borrow_mut(); - let last_memory_text_model = last_memory_text_model.borrow_mut(); + let text_model = text_model.clone(); + // let memory_text_model = Rc::clone(&memory_text_model); + let memory_text_model = memory_text_model.clone(); + // let last_memory_text_model = Rc::clone(&last_memory_text_model); + let last_memory_text_model = last_memory_text_model.clone(); // let mut editor_curr_line = editor_curr_line.borrow_mut(); // Pull ProgramInfo from the parser @@ -246,44 +228,6 @@ fn app(props: &AppProps) -> Html { let list_of_line_numbers = programinfo.address_to_line_number; let index = datapath.registers.pc as usize / 4; editor_curr_line.set(*list_of_line_numbers.get(index).unwrap_or(&0) as f64 + 1.0); // add one to account for the editor's line numbers - debug!("Setting curr line to {}", **editor_curr_line); - - // Setup the range - let curr_model = text_model.as_ref(); - let curr_range = monaco::sys::Range::new(**editor_curr_line, 0.0, **editor_curr_line, 0.0); - - // element to be stored in the stack to highlight the line - let highlight_line: monaco::sys::editor::IModelDeltaDecoration = - Object::new().unchecked_into(); - highlight_line.set_options(&highlight_decor); - let range_js = curr_range - .dyn_into::() - .expect("Range is not found."); - highlight_line.set_range(&monaco::sys::IRange::from(range_js)); - let highlight_js = highlight_line - .dyn_into::() - .expect("Highlight is not found."); - - // log!("These are the stacks before the push"); - // log!(executed_line.at(0)); - // log!(not_highlighted.at(0)); - - // push the decoration onto the executed_line stack - executed_line.push(&highlight_js); - - // it may look ugly, but it makes sense. Uncomment debug statements to see why. - not_highlighted.set( - 0, - curr_model - .delta_decorations(¬_highlighted, &executed_line, None) - .into(), - ); - - // memory_text_model.as_ref().delta_decorations(¬_highlighted, &executed_line, None); - - // log!("These are the stacks after the push"); - // log!(executed_line.at(0)); - // log!(not_highlighted.at(0)); // Execute instruction datapath.execute_instruction(); @@ -293,15 +237,6 @@ fn app(props: &AppProps) -> Html { memory_text_model.set_value(hexdump); last_memory_text_model.set_value(hexdump); - - // done with the highlight, prepare for the next one. - executed_line.pop(); - - // log!("These are the stacks after the pop"); - // log!(executed_line.at(0)); - // log!(not_highlighted.at(0)); - - trigger.force_update(); }, editor_curr_line, ) @@ -309,54 +244,35 @@ fn app(props: &AppProps) -> Html { let on_execute_stage_clicked = { let datapath = Rc::clone(&datapath); - let trigger = use_force_update(); // Code editor - let text_model = Rc::clone(&text_model); - let executed_line = executed_line.clone(); - let not_highlighted = not_highlighted.clone(); - let highlight_decor = highlight_decor; + // let text_model = Rc::clone(&text_model); + let text_model = text_model.clone(); + let editor_curr_line = editor_curr_line.clone(); // Hex editor - let memory_text_model = Rc::clone(&memory_text_model); - let last_memory_text_model = Rc::clone(&last_memory_text_model); + // let memory_text_model = Rc::clone(&memory_text_model); + let memory_text_model = memory_text_model.clone(); + // let last_memory_text_model = Rc::clone(&last_memory_text_model); + let last_memory_text_model = last_memory_text_model.clone(); use_callback( - move |_, _| { + move |_, editor_curr_line| { let mut datapath = datapath.borrow_mut(); - let highlight_decor = highlight_decor.borrow_mut(); - let memory_text_model = memory_text_model.borrow_mut(); - let last_memory_text_model = last_memory_text_model.borrow_mut(); + // let memory_text_model = Rc::clone(&memory_text_model); + let memory_text_model = memory_text_model.clone(); + // let last_memory_text_model = Rc::clone(&last_memory_text_model); + let last_memory_text_model = last_memory_text_model.clone(); if datapath.current_stage == Stage::InstructionDecode { // highlight on InstructionDecode since syscall stops at that stage. - let text_model = text_model.borrow_mut(); + let text_model = text_model.clone(); let (programinfo, _) = parser(text_model.get_value()); let list_of_line_numbers = programinfo.address_to_line_number; let index = datapath.registers.pc as usize / 4; - let editor_curr_line = *list_of_line_numbers.get(index).unwrap_or(&0) as f64 + 1.0; - let curr_model = text_model.as_ref(); - let curr_range = monaco::sys::Range::new(editor_curr_line, 0.0, editor_curr_line, 0.0); - let highlight_line: monaco::sys::editor::IModelDeltaDecoration = - Object::new().unchecked_into(); - highlight_line.set_options(&highlight_decor); - let range_js = curr_range - .dyn_into::() - .expect("Range is not found."); - highlight_line.set_range(&monaco::sys::IRange::from(range_js)); - let highlight_js = highlight_line - .dyn_into::() - .expect("Highlight is not found."); - executed_line.push(&highlight_js); - not_highlighted.set( - 0, - curr_model - .delta_decorations(¬_highlighted, &executed_line, None) - .into(), - ); + editor_curr_line.set(*list_of_line_numbers.get(index).unwrap_or(&0) as f64 + 1.0); datapath.execute_stage(); - executed_line.pop(); } else { datapath.execute_stage(); } @@ -366,33 +282,36 @@ fn app(props: &AppProps) -> Html { memory_text_model.set_value(hexdump); last_memory_text_model.set_value(hexdump); - trigger.force_update(); }, - (), + editor_curr_line, ) }; let on_memory_clicked = { let datapath = Rc::clone(&datapath); - let trigger = use_force_update(); // Code editor - let text_model = Rc::clone(&text_model); + // let text_model = Rc::clone(&text_model); + let text_model = text_model.clone(); // Hex editor - let memory_text_model = Rc::clone(&memory_text_model); - let last_memory_text_model = Rc::clone(&last_memory_text_model); + // let memory_text_model = Rc::clone(&memory_text_model); + let memory_text_model = memory_text_model.clone(); + // let last_memory_text_model = Rc::clone(&last_memory_text_model); + let last_memory_text_model = last_memory_text_model.clone(); use_callback( move |_, _| { let mut datapath = datapath.borrow_mut(); - let text_model = text_model.borrow_mut(); + let text_model = text_model.clone(); let (programinfo, binary) = parser(text_model.get_value()); // Update memory - let memory_text_model = memory_text_model.borrow_mut(); - let last_memory_text_model = last_memory_text_model.borrow_mut(); + // let memory_text_model = Rc::clone(&memory_text_model); + let memory_text_model = memory_text_model.clone(); + // let last_memory_text_model = Rc::clone(&last_memory_text_model); + let last_memory_text_model = last_memory_text_model.clone(); let last_memory_text_model_value = last_memory_text_model.get_value(); let current_memory_text_model_value = memory_text_model.get_value(); @@ -471,8 +390,6 @@ fn app(props: &AppProps) -> Html { memory_text_model.set_value(hexdump); last_memory_text_model.set_value(hexdump); - trigger.force_update(); - }, (), ) @@ -482,53 +399,47 @@ fn app(props: &AppProps) -> Html { // This will also clear any highlight on the editor. let on_reset_clicked = { let datapath = Rc::clone(&datapath); - let trigger = use_force_update(); // Code editor - let text_model = Rc::clone(&text_model); let parser_text_output = parser_text_output.clone(); - - let executed_line = executed_line; - let not_highlighted = not_highlighted; + let editor_curr_line = editor_curr_line.clone(); // Hex editor - let memory_text_model = Rc::clone(&memory_text_model); - let last_memory_text_model = Rc::clone(&last_memory_text_model); + // let memory_text_model = Rc::clone(&memory_text_model); + let memory_text_model = memory_text_model.clone(); + // let last_memory_text_model = Rc::clone(&last_memory_text_model); + let last_memory_text_model = last_memory_text_model.clone(); use_callback( - move |_, _| { + move |_, editor_curr_line| { let mut datapath = datapath.borrow_mut(); - let text_model = text_model.borrow_mut(); - let curr_model = text_model.as_ref(); - executed_line.pop(); - not_highlighted.set( - 0, - curr_model - .delta_decorations(¬_highlighted, &executed_line, None) - .into(), - ); + + // Set highlighted line to 0 + editor_curr_line.set(0.0); + parser_text_output.set("".to_string()); datapath.reset(); // Clear hex editor content - let memory_text_model = memory_text_model.borrow_mut(); - let last_memory_text_model = last_memory_text_model.borrow_mut(); + // let memory_text_model = Rc::clone(&memory_text_model); + let memory_text_model = memory_text_model.clone(); + // let last_memory_text_model = Rc::clone(&last_memory_text_model); + let last_memory_text_model = last_memory_text_model.clone(); memory_text_model.set_value(""); last_memory_text_model.set_value(""); - - trigger.force_update(); }, - (), + editor_curr_line, ) }; // Copies text to the user's clipboard let on_clipboard_clicked = { - let text_model = Rc::clone(&text_model); + // let text_model = Rc::clone(&text_model); + let text_model = text_model.clone(); let clipboard = use_clipboard(); Callback::from(move |_: _| { - let text_model = text_model.borrow_mut(); + let text_model = text_model.clone(); clipboard.write_text(text_model.get_value()); alert("Your code is saved to the clipboard.\nPaste it onto a text file to save it.\n(Ctrl/Cmd + V)"); }) @@ -536,11 +447,12 @@ fn app(props: &AppProps) -> Html { // We'll have the Mouse Hover event running at all times. { - let text_model = Rc::clone(&text_model); + // let text_model = Rc::clone(&text_model); + let text_model = text_model.clone(); use_event_with_window("mouseover", move |_: MouseEvent| { let hover_jsarray = hover_jsarray.clone(); let hover_decor_array = hover_decor_array.clone(); - let text_model = text_model.borrow_mut(); + let text_model = text_model.clone(); let curr_model = text_model.as_ref(); let (program_info, _) = parser(text_model.get_value()); @@ -609,10 +521,11 @@ fn app(props: &AppProps) -> Html { // This is the callback to get the file's contents and load it onto the Editor let file_picked_callback = { - let text_model = Rc::clone(&text_model); + // let text_model = Rc::clone(&text_model); + let text_model = text_model.clone(); use_callback( move |e: Event, _| { - let text_model = text_model.borrow_mut().clone(); + let text_model = text_model.clone(); let input: HtmlInputElement = e.target_unchecked_into(); // gloo making the code readable and easy to implement let filelist = FileList::from(input.files().unwrap()); @@ -654,11 +567,11 @@ fn app(props: &AppProps) -> Html { // Editor
- +
// Console - +
// Right column diff --git a/src/ui/console/component.rs b/src/ui/console/component.rs index a63a43356..c47cc8b1b 100644 --- a/src/ui/console/component.rs +++ b/src/ui/console/component.rs @@ -18,12 +18,13 @@ use crate::ui::hex_editor::component::HexEditor; pub struct Consoleprops { pub datapath: MipsDatapath, pub parsermsg: String, - pub memory_text_model: Rc>, - pub memory_curr_line: UseStateHandle + pub memory_text_model: UseStateHandle, + pub memory_curr_line: UseStateHandle, + pub active_tab: UseStateHandle, } #[derive(Default, PartialEq)] -enum TabState { +pub enum TabState { #[default] Console, Datapath, @@ -32,7 +33,7 @@ enum TabState { #[function_component(Console)] pub fn console(props: &Consoleprops) -> Html { - let active_tab = use_state_eq(TabState::default); + let active_tab = &props.active_tab; let zoom_datapath = use_bool_toggle(false); let switch_datapath = use_bool_toggle(false); let change_tab = { @@ -88,41 +89,41 @@ pub fn console(props: &Consoleprops) -> Html { html! { <> // Console buttons - if *active_tab == TabState::Console { + if **active_tab == TabState::Console {
                     { props.parsermsg.clone() }
                 
- } else if *active_tab == TabState::Datapath { + } else if **active_tab == TabState::Datapath {
- } else if *active_tab == TabState::HexEditor { + } else if **active_tab == TabState::HexEditor {
- +
}
- if *active_tab == TabState::Console { + if **active_tab == TabState::Console { } else { } - if *active_tab == TabState::Datapath { + if **active_tab == TabState::Datapath { } else { } - if *active_tab == TabState::HexEditor { + if **active_tab == TabState::HexEditor { } else { }
- if *active_tab == TabState::Datapath { + if **active_tab == TabState::Datapath {
diff --git a/src/ui/hex_editor/component.rs b/src/ui/hex_editor/component.rs index 1a3d36e33..94a343202 100644 --- a/src/ui/hex_editor/component.rs +++ b/src/ui/hex_editor/component.rs @@ -16,7 +16,7 @@ use monaco::{ }; #[derive(PartialEq, Properties)] pub struct HexEditorProps { - pub memory_text_model: Rc>, + pub memory_text_model: UseStateHandle, pub curr_line: UseStateHandle } @@ -24,6 +24,7 @@ pub struct HexEditorProps { pub fn hex_editor(props: &HexEditorProps) -> Html { let editor_link = CodeEditorLink::new(); let curr_line = *props.curr_line; + let text_model = &*props.memory_text_model; // create a JavaScript closure for hex highlighting let cb = Closure::wrap(Box::new(move |event: monaco::sys::editor::ICursorSelectionChangedEvent| { @@ -86,7 +87,7 @@ pub fn hex_editor(props: &HexEditorProps) -> Html { classes={"editor"} link={editor_link} options={get_options()} - model={props.memory_text_model.borrow().clone()} + model={text_model.clone()} on_editor_created={on_editor_created} /> } diff --git a/src/ui/swim_editor/component.rs b/src/ui/swim_editor/component.rs index 5c5ede839..7210279e4 100644 --- a/src/ui/swim_editor/component.rs +++ b/src/ui/swim_editor/component.rs @@ -1,11 +1,11 @@ use std::{cell::RefCell, rc::Rc}; -use monaco::{api::TextModel, sys::editor::{ - IEditorMinimapOptions, IEditorScrollbarOptions, IStandaloneEditorConstructionOptions, ISuggestOptions, ScrollType -}, yew::{CodeEditor, CodeEditorLink}}; +use monaco::{api::TextModel, sys::{editor::{ + IEditorMinimapOptions, IEditorScrollbarOptions, IModelDecorationOptions, IModelDeltaDecoration, IStandaloneEditorConstructionOptions, ISuggestOptions, ScrollType +}, Range}, yew::{CodeEditor, CodeEditorLink}}; use yew::{Callback, Properties}; use yew::prelude::*; -use wasm_bindgen::JsCast; +use wasm_bindgen::{JsCast, JsValue}; use crate::{parser::parser_structs_and_enums::ProgramInfo, ui::assembled_view::component::{DataSegment, TextSegment}}; @@ -13,13 +13,14 @@ use log::debug; #[derive(PartialEq, Properties)] pub struct SwimEditorProps { - pub text_model: Rc>, + pub text_model: UseStateHandle, pub lines_content: Rc>>, pub program_info: ProgramInfo, pub binary: Vec, pub pc: u64, pub memory_curr_line: UseStateHandle, - pub editor_curr_line: UseStateHandle + pub editor_curr_line: UseStateHandle, + pub active_tab: UseStateHandle } #[derive(Default, PartialEq)] @@ -59,6 +60,7 @@ fn get_options() -> IStandaloneEditorConstructionOptions { #[function_component] pub fn SwimEditor(props: &SwimEditorProps) -> Html { let link = CodeEditorLink::new(); + let text_model = &*props.text_model; let on_editor_created = { let curr_line = props.editor_curr_line.clone(); @@ -80,17 +82,39 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html { string_lines.push(string_value); }; + // Scroll to current line raw_editor.reveal_line_in_center(**curr_line, Some(ScrollType::Smooth)); + // Highlight current line using delta decorations + let not_highlighted = js_sys::Array::new(); + let executed_line = js_sys::Array::new(); + let decoration: IModelDeltaDecoration = js_sys::Object::new().unchecked_into(); + let options: IModelDecorationOptions = js_sys::Object::new().unchecked_into(); + if **curr_line != 0.0 { + // Show highlight if current line is not 0 + options.set_inline_class_name("myInlineDecoration".into()); + options.set_is_whole_line(true.into()); + } + decoration.set_options(&options); + let curr_range = Range::new(**curr_line, 0.0, **curr_line, 0.0); + let range_js = curr_range + .dyn_into::() + .expect("Range is not found."); + decoration.set_range(&monaco::sys::IRange::from(range_js)); + let decoration_js = decoration + .dyn_into::() + .expect("Highlight is not found."); + executed_line.push(&decoration_js); + raw_editor.delta_decorations(¬_highlighted, &executed_line); }) { - Some(()) => debug!("Editor linked!"), - None => debug!("No editor :<") + Some(_) => (), + None => () }; }, curr_line, ) }; - let active_tab = use_state_eq(EditorTabState::default); + let active_tab = &props.active_tab; let change_tab = { let active_tab = active_tab.clone(); Callback::from(move |event: MouseEvent| { @@ -113,29 +137,29 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html { <> // Editor buttons
- if *active_tab == EditorTabState::Editor { + if **active_tab == EditorTabState::Editor { } else { } - if *active_tab == EditorTabState::TextSegment { + if **active_tab == EditorTabState::TextSegment { } else { } - if *active_tab == EditorTabState::DataSegment { + if **active_tab == EditorTabState::DataSegment { } else { }
- if *active_tab == EditorTabState::Editor { - - } else if *active_tab == EditorTabState::TextSegment { + if **active_tab == EditorTabState::Editor { + + } else if **active_tab == EditorTabState::TextSegment { - } else if *active_tab == EditorTabState::DataSegment { + } else if **active_tab == EditorTabState::DataSegment { } From e65efd628406de49aa9087c92b98867f37e32338 Mon Sep 17 00:00:00 2001 From: Cay Date: Sat, 3 Feb 2024 22:51:09 -0500 Subject: [PATCH 032/355] re-add force update for datapath --- src/bin/main.rs | 28 +++++++++++++++++++--------- src/ui/visual_datapath/mod.rs | 3 ++- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index 190144358..692d977e1 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -17,8 +17,8 @@ use monaco::{ use swim::{parser::parser_assembler_main::parser, ui::{console::component::TabState, swim_editor::component::EditorTabState}}; use swim::parser::parser_structs_and_enums::ProgramInfo; use std::rc::Rc; -use swim::agent::datapath_communicator::DatapathCommunicator; use swim::agent::EmulationCoreAgent; +use swim::agent::datapath_communicator::DatapathCommunicator; use swim::emulation_core::datapath::Datapath; use swim::emulation_core::mips::datapath::MipsDatapath; use swim::emulation_core::mips::datapath::Stage; @@ -98,12 +98,9 @@ fn app(props: &AppProps) -> Html { // and will force updates whenever its internal state changes. { let trigger = use_force_update(); - use_effect_with_deps( - move |communicator| { - spawn_local(communicator.listen_for_updates(trigger)); - }, - props.communicator, - ); + use_effect_with_deps(move |communicator| { + spawn_local(communicator.listen_for_updates(trigger)); + }, props.communicator); } // This is where code is assembled and loaded into the emulation core's memory. @@ -118,6 +115,7 @@ fn app(props: &AppProps) -> Html { let last_memory_text_model = last_memory_text_model.clone(); let datapath = Rc::clone(&datapath); let parser_text_output = parser_text_output.clone(); + let trigger = use_force_update(); let editor_curr_line = editor_curr_line.clone(); // Clone the value before moving it into the closure @@ -188,6 +186,8 @@ fn app(props: &AppProps) -> Html { last_memory_text_model.set_value(hexdump); datapath.registers.pc = program_info.pc_starting_point as u64; } + + trigger.force_update(); }, (text_model, editor_curr_line), ) @@ -212,6 +212,7 @@ fn app(props: &AppProps) -> Html { let memory_text_model = memory_text_model.clone(); // let last_memory_text_model = Rc::clone(&last_memory_text_model); let last_memory_text_model = last_memory_text_model.clone(); + let trigger = use_force_update(); use_callback( move |_, editor_curr_line| { @@ -239,6 +240,8 @@ fn app(props: &AppProps) -> Html { memory_text_model.set_value(hexdump); last_memory_text_model.set_value(hexdump); + + trigger.force_update(); }, editor_curr_line, ) @@ -251,6 +254,7 @@ fn app(props: &AppProps) -> Html { // let text_model = Rc::clone(&text_model); let text_model = text_model.clone(); let editor_curr_line = editor_curr_line.clone(); + let trigger = use_force_update(); // Hex editor // let memory_text_model = Rc::clone(&memory_text_model); @@ -284,6 +288,7 @@ fn app(props: &AppProps) -> Html { memory_text_model.set_value(hexdump); last_memory_text_model.set_value(hexdump); + trigger.force_update(); }, editor_curr_line, ) @@ -291,6 +296,7 @@ fn app(props: &AppProps) -> Html { let on_memory_clicked = { let datapath = Rc::clone(&datapath); + let trigger = use_force_update(); // Code editor // let text_model = Rc::clone(&text_model); @@ -392,6 +398,8 @@ fn app(props: &AppProps) -> Html { memory_text_model.set_value(hexdump); last_memory_text_model.set_value(hexdump); + trigger.force_update(); + }, (), ) @@ -401,6 +409,7 @@ fn app(props: &AppProps) -> Html { // This will also clear any highlight on the editor. let on_reset_clicked = { let datapath = Rc::clone(&datapath); + let trigger = use_force_update(); // Code editor let parser_text_output = parser_text_output.clone(); @@ -430,6 +439,8 @@ fn app(props: &AppProps) -> Html { memory_text_model.set_value(""); last_memory_text_model.set_value(""); + + trigger.force_update(); }, editor_curr_line, ) @@ -614,8 +625,7 @@ pub fn on_upload_file_clicked() { fn main() { console_log::init_with_level(Level::Debug).unwrap(); // Initialize and leak the communicator to ensure that the thread spawns immediately and the bridge to it lives - // for the remainder of the program. We can use the communicator exclusively through immutable references for the - // rest of the program. + // for the remainder of the program. let bridge = EmulationCoreAgent::spawner().spawn("./worker.js"); let communicator = Box::new(DatapathCommunicator::new(bridge)); yew::Renderer::::with_props(AppProps { diff --git a/src/ui/visual_datapath/mod.rs b/src/ui/visual_datapath/mod.rs index 8f8727af8..3139d8e95 100644 --- a/src/ui/visual_datapath/mod.rs +++ b/src/ui/visual_datapath/mod.rs @@ -28,6 +28,7 @@ pub mod utils; use std::{cell::RefCell, rc::Rc}; use gloo_events::EventListener; +use log::debug; use wasm_bindgen::{JsCast, JsValue}; use web_sys::{Element, Event, HtmlCollection, HtmlElement}; use yew::prelude::*; @@ -112,6 +113,7 @@ impl Component for VisualDatapath { Stage::WriteBack => "memory", }); + debug!("Current stage: {:?}", current_stage); if first_render || self.should_reinitialize { self.initialize(current_stage, ctx.props().datapath.clone()); self.should_reinitialize = false; @@ -208,7 +210,6 @@ impl VisualDatapath { }); } }); - Self::highlight_stage(&nodes, current_stage.clone(), datapath.clone()) }); From 539903a13c996b9ab097950cadfe5b01e9338123 Mon Sep 17 00:00:00 2001 From: Cay Date: Sun, 4 Feb 2024 16:52:14 -0500 Subject: [PATCH 033/355] Add hex highlighting and switch tabs on cross reference click --- Cargo.toml | 2 +- src/bin/main.rs | 30 +++-- src/ui/assembled_view/component.rs | 116 ++++++++++++------ src/ui/console/component.rs | 35 +++--- src/ui/hex_editor/component.rs | 189 +++++++++++++++++++++-------- src/ui/swim_editor/component.rs | 32 ++--- static/styles/main.css | 48 ++++++-- 7 files changed, 308 insertions(+), 144 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 164dacbe9..3ffe346c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ js-sys = "0.3.61" monaco = { git = "https://github.com/SWIM-ucf/rust-monaco", rev = "c9586e4af77131a15daf53e91e1ad5161a5265e8", features = ["yew-components"] } wasm-bindgen = "0.2.83" wasm-bindgen-futures = "0.4.33" -web-sys = {version = "0.3.60", features = ["CssStyleDeclaration", "Event", "HtmlCollection", "HtmlElement", "HtmlInputElement", "HtmlObjectElement", "SvgElement", "CanvasRenderingContext2d", "Document", "HtmlCanvasElement", "EventTarget", "InputEvent"]} +web-sys = {version = "0.3.60", features = ["CssStyleDeclaration", "Event", "HtmlCollection", "HtmlElement", "HtmlInputElement", "HtmlObjectElement", "SvgElement", "CanvasRenderingContext2d", "Document", "HtmlCanvasElement", "EventTarget", "InputEvent", "ScrollLogicalPosition", "ScrollIntoViewOptions"]} yew = {version = "0.20.0", features = ["csr"] } yew-hooks = "0.2.0" yew-agent = "0.3.0" diff --git a/src/bin/main.rs b/src/bin/main.rs index 692d977e1..d09a518da 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -14,7 +14,7 @@ use monaco::{ IMarkdownString, MarkerSeverity, } }; -use swim::{parser::parser_assembler_main::parser, ui::{console::component::TabState, swim_editor::component::EditorTabState}}; +use swim::{parser::parser_assembler_main::parser, ui::{console::component::ConsoleTabState, swim_editor::component::EditorTabState}}; use swim::parser::parser_structs_and_enums::ProgramInfo; use std::rc::Rc; use swim::agent::EmulationCoreAgent; @@ -65,7 +65,7 @@ fn app(props: &AppProps) -> Html { // Store the currently executed line in code editor and hex editor let editor_curr_line = use_state_eq(|| 0.0); - let memory_curr_line = use_state_eq(|| 0.0); + let memory_curr_instr = use_state_eq(|| 0); // Output strings for the console and memory viewers. let parser_text_output = use_state_eq(String::new); @@ -84,7 +84,7 @@ fn app(props: &AppProps) -> Html { let memory_text_model = use_state_eq(|| TextModel::create(&memory_text_output, Some("ini"), None).unwrap()); // Store the currently selected tabs in windows - let console_active_tab = use_state_eq(TabState::default); + let console_active_tab = use_state_eq(ConsoleTabState::default); let editor_active_tab = use_state_eq(EditorTabState::default); // Since we want the Datapath to be independent from all the @@ -111,6 +111,7 @@ fn app(props: &AppProps) -> Html { let text_model = text_model.clone(); // let memory_text_model = Rc::clone(&memory_text_model); let memory_text_model = memory_text_model.clone(); + let memory_curr_instr = memory_curr_instr.clone(); // let last_memory_text_model = Rc::clone(&last_memory_text_model); let last_memory_text_model = last_memory_text_model.clone(); let datapath = Rc::clone(&datapath); @@ -124,7 +125,7 @@ fn app(props: &AppProps) -> Html { let binary_ref = Rc::clone(&binary_ref); use_callback( - move |_, (text_model, editor_curr_line)| { + move |_, (text_model, editor_curr_line, memory_curr_instr)| { let mut datapath = datapath.borrow_mut(); let text_model = text_model.clone(); let memory_text_model = memory_text_model.clone(); @@ -179,6 +180,7 @@ fn app(props: &AppProps) -> Html { parser_text_output.set(format!("This program failed to load into the datapath. Message returned by datapath: {msg}")); } } + memory_curr_instr.set(datapath.registers.pc); // log!(datapath.memory.to_string()); text_model.set_value(&program_info.updated_monaco_string); // Expands pseudo-instructions to their hardware counterpart. let hexdump = &datapath.memory.generate_formatted_hex(); @@ -189,7 +191,7 @@ fn app(props: &AppProps) -> Html { trigger.force_update(); }, - (text_model, editor_curr_line), + (text_model, editor_curr_line, memory_curr_instr), ) }; @@ -206,6 +208,7 @@ fn app(props: &AppProps) -> Html { // let text_model = Rc::clone(&text_model); let text_model = text_model.clone(); let editor_curr_line = editor_curr_line.clone(); + let memory_curr_instr = memory_curr_instr.clone(); // Hex editor // let memory_text_model = Rc::clone(&memory_text_model); @@ -215,7 +218,7 @@ fn app(props: &AppProps) -> Html { let trigger = use_force_update(); use_callback( - move |_, editor_curr_line| { + move |_, (editor_curr_line, memory_curr_instr)| { let mut datapath = datapath.borrow_mut(); let text_model = text_model.clone(); // let memory_text_model = Rc::clone(&memory_text_model); @@ -231,6 +234,7 @@ fn app(props: &AppProps) -> Html { let list_of_line_numbers = programinfo.address_to_line_number; let index = datapath.registers.pc as usize / 4; editor_curr_line.set(*list_of_line_numbers.get(index).unwrap_or(&0) as f64 + 1.0); // add one to account for the editor's line numbers + memory_curr_instr.set(datapath.registers.pc); // Execute instruction datapath.execute_instruction(); @@ -243,7 +247,7 @@ fn app(props: &AppProps) -> Html { trigger.force_update(); }, - editor_curr_line, + (editor_curr_line, memory_curr_instr), ) }; @@ -261,9 +265,10 @@ fn app(props: &AppProps) -> Html { let memory_text_model = memory_text_model.clone(); // let last_memory_text_model = Rc::clone(&last_memory_text_model); let last_memory_text_model = last_memory_text_model.clone(); + let memory_curr_instr = memory_curr_instr.clone(); use_callback( - move |_, editor_curr_line| { + move |_, (editor_curr_line, memory_curr_instr)| { let mut datapath = datapath.borrow_mut(); // let memory_text_model = Rc::clone(&memory_text_model); @@ -278,6 +283,7 @@ fn app(props: &AppProps) -> Html { let list_of_line_numbers = programinfo.address_to_line_number; let index = datapath.registers.pc as usize / 4; editor_curr_line.set(*list_of_line_numbers.get(index).unwrap_or(&0) as f64 + 1.0); + memory_curr_instr.set(datapath.registers.pc); datapath.execute_stage(); } else { datapath.execute_stage(); @@ -290,7 +296,7 @@ fn app(props: &AppProps) -> Html { last_memory_text_model.set_value(hexdump); trigger.force_update(); }, - editor_curr_line, + (editor_curr_line, memory_curr_instr), ) }; @@ -420,6 +426,7 @@ fn app(props: &AppProps) -> Html { let memory_text_model = memory_text_model.clone(); // let last_memory_text_model = Rc::clone(&last_memory_text_model); let last_memory_text_model = last_memory_text_model.clone(); + let memory_curr_instr = memory_curr_instr.clone(); use_callback( move |_, editor_curr_line| { @@ -427,6 +434,7 @@ fn app(props: &AppProps) -> Html { // Set highlighted line to 0 editor_curr_line.set(0.0); + memory_curr_instr.set(datapath.registers.pc); parser_text_output.set("".to_string()); datapath.reset(); @@ -580,11 +588,11 @@ fn app(props: &AppProps) -> Html { // Editor
- +
// Console - +
// Right column diff --git a/src/ui/assembled_view/component.rs b/src/ui/assembled_view/component.rs index 79c4cc383..aaa8b5673 100644 --- a/src/ui/assembled_view/component.rs +++ b/src/ui/assembled_view/component.rs @@ -2,12 +2,13 @@ use std::cell::RefCell; use std::rc::Rc; // use monaco::api::TextModel; -use web_sys::HtmlInputElement; +use web_sys::{HtmlElement, HtmlInputElement}; use yew::{Properties, Html}; use yew::prelude::*; use wasm_bindgen::JsCast; use log::debug; use crate::parser::parser_structs_and_enums::ProgramInfo; +use crate::ui::console::component::ConsoleTabState; use crate::ui::swim_editor::component::EditorTabState; @@ -15,10 +16,11 @@ use crate::ui::swim_editor::component::EditorTabState; pub struct TextSegmentProps { pub program_info: ProgramInfo, pub lines_content: Rc>>, - pub memory_curr_line: UseStateHandle, + pub memory_curr_instr: UseStateHandle, pub editor_curr_line: UseStateHandle, pub pc: u64, - pub active_tab: UseStateHandle, + pub editor_active_tab: UseStateHandle, + pub console_active_tab: UseStateHandle } #[derive(PartialEq, Properties)] pub struct DataSegmentProps { @@ -31,9 +33,21 @@ pub struct DataSegmentProps { pub fn TextSegment(props: &TextSegmentProps) -> Html { let program_info = &props.program_info; let lines_content = props.lines_content.borrow_mut().clone(); - let memory_curr_line = &props.memory_curr_line; + let memory_curr_instr = &props.memory_curr_instr; let editor_curr_line = &props.editor_curr_line; - let active_tab = &props.active_tab; + let editor_active_tab = &props.editor_active_tab; + let console_active_tab = &props.console_active_tab; + let executed_ref = use_node_ref(); + + { + // Always scroll to the executed row on re-render + let executed_row = executed_ref.cast::(); + if let Some(executed_row) = executed_row { + let mut options = web_sys::ScrollIntoViewOptions::new(); + options.block(web_sys::ScrollLogicalPosition::Center); + executed_row.scroll_into_view_with_scroll_into_view_options(&options); + } + } let on_check = Callback::from(move |args: (MouseEvent, i64)| { let (e, address) = args; @@ -47,20 +61,22 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html { }); let on_address_click = { - let memory_curr_line = memory_curr_line.clone(); - use_callback(move |args: (MouseEvent, i64), memory_curr_line| { + let memory_curr_instr = memory_curr_instr.clone(); + let console_active_tab = console_active_tab.clone(); + use_callback(move |args: (MouseEvent, i64), memory_curr_instr| { let (_e, address) = args; - memory_curr_line.set((address / 4) as f64); - }, memory_curr_line) + memory_curr_instr.set(address as u64); + console_active_tab.set(ConsoleTabState::HexEditor); + }, memory_curr_instr) }; let on_assembled_click = { let editor_curr_line = editor_curr_line.clone(); - let active_tab = active_tab.clone(); + let editor_active_tab = editor_active_tab.clone(); use_callback(move |args: (MouseEvent, usize), _| { let (_e, line_number) = args; editor_curr_line.set(line_number as f64); - active_tab.set(EditorTabState::Editor); + editor_active_tab.set(EditorTabState::Editor); }, ()) }; @@ -82,36 +98,62 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html { let on_check = Callback::clone(&on_check); let on_address_click = Callback::clone(&on_address_click); let on_assembled_click = Callback::clone(&on_assembled_click); + let executed_ref = executed_ref.clone(); address += 4; + + let line_number = instruction.line_number.clone(); + let mut conditional_class = ""; if props.pc as i64 == address { - conditional_class = "executing"; + conditional_class = "executedLine"; + html!{ + + + +
+ + + {format!("0x{:08x}", address as u64)} + + + {format!("0b{:032b}", instruction.binary)} + + + {format!("0x{:08x}", instruction.binary)} + + + {recreated_string} + + + {format!("{}: {:?}", line_number, lines_content.get(line_number).unwrap_or(&String::from("")))} + + + } } - - let line_number = instruction.line_number.clone(); - html!{ - - - - -
- - - {format!("0x{:08x}", address as u64)} - - - {format!("0b{:032b}", instruction.binary)} - - - {format!("0x{:08x}", instruction.binary)} - - - {recreated_string} - - - {format!("{}: {:?}", line_number, lines_content.get(line_number).unwrap_or(&String::from("")))} - - + else { + html!{ + + + +
+ + + {format!("0x{:08x}", address as u64)} + + + {format!("0b{:032b}", instruction.binary)} + + + {format!("0x{:08x}", instruction.binary)} + + + {recreated_string} + + + {format!("{}: {:?}", line_number, lines_content.get(line_number).unwrap_or(&String::from("")))} + + + } } }).collect::() } diff --git a/src/ui/console/component.rs b/src/ui/console/component.rs index c47cc8b1b..46431702c 100644 --- a/src/ui/console/component.rs +++ b/src/ui/console/component.rs @@ -4,12 +4,7 @@ use wasm_bindgen::JsCast; use web_sys::HtmlElement; use yew::prelude::*; use yew_hooks::prelude::*; -use std::rc::Rc; -use std::cell::RefCell; - - use monaco::api::TextModel; - use crate::emulation_core::mips::datapath::MipsDatapath; use crate::ui::visual_datapath::{DatapathSize, VisualDatapath}; use crate::ui::hex_editor::component::HexEditor; @@ -19,12 +14,12 @@ pub struct Consoleprops { pub datapath: MipsDatapath, pub parsermsg: String, pub memory_text_model: UseStateHandle, - pub memory_curr_line: UseStateHandle, - pub active_tab: UseStateHandle, + pub memory_curr_instr: UseStateHandle, + pub active_tab: UseStateHandle, } #[derive(Default, PartialEq)] -pub enum TabState { +pub enum ConsoleTabState { #[default] Console, Datapath, @@ -45,10 +40,10 @@ pub fn console(props: &Consoleprops) -> Html { .unwrap_or(String::from("console")); let new_tab = match tab_name.as_str() { - "console" => TabState::Console, - "datapath" => TabState::Datapath, - "hex_editor" => TabState::HexEditor, - _ => TabState::default(), + "console" => ConsoleTabState::Console, + "datapath" => ConsoleTabState::Datapath, + "hex_editor" => ConsoleTabState::HexEditor, + _ => ConsoleTabState::default(), }; active_tab.set(new_tab); @@ -89,41 +84,41 @@ pub fn console(props: &Consoleprops) -> Html { html! { <> // Console buttons - if **active_tab == TabState::Console { + if **active_tab == ConsoleTabState::Console {
                     { props.parsermsg.clone() }
                 
- } else if **active_tab == TabState::Datapath { + } else if **active_tab == ConsoleTabState::Datapath {
- } else if **active_tab == TabState::HexEditor { + } else if **active_tab == ConsoleTabState::HexEditor {
- +
}
- if **active_tab == TabState::Console { + if **active_tab == ConsoleTabState::Console { } else { } - if **active_tab == TabState::Datapath { + if **active_tab == ConsoleTabState::Datapath { } else { } - if **active_tab == TabState::HexEditor { + if **active_tab == ConsoleTabState::HexEditor { } else { }
- if **active_tab == TabState::Datapath { + if **active_tab == ConsoleTabState::Datapath {
diff --git a/src/ui/hex_editor/component.rs b/src/ui/hex_editor/component.rs index 94a343202..819eb7574 100644 --- a/src/ui/hex_editor/component.rs +++ b/src/ui/hex_editor/component.rs @@ -1,85 +1,171 @@ -use js_sys::Object; -use wasm_bindgen::{closure::Closure, JsValue}; -use yew::{function_component, html, use_callback, Html, Properties, UseStateHandle}; -use std::rc::Rc; -use std::cell::RefCell; use log::debug; +use std::ops::Deref; +use std::rc::Rc; use wasm_bindgen::JsCast; +use wasm_bindgen::{closure::Closure, JsValue}; +use yew::{function_component, html, use_callback, Html, Properties, UseStateHandle}; +use yew::prelude::*; use monaco::{ api::TextModel, - sys:: + sys::{ editor::{ - IEditorMinimapOptions, IEditorScrollbarOptions, IStandaloneEditorConstructionOptions, ISuggestOptions, ScrollType + IEditorMinimapOptions, IEditorScrollbarOptions, IModelDecorationOptions, + IModelDeltaDecoration, IStandaloneEditorConstructionOptions, ISuggestOptions, + ScrollType, }, + Range, + }, yew::{CodeEditor, CodeEditorLink}, }; + +#[derive(PartialEq, Properties)] +pub struct HexCoord { + pub line_number: f64, + pub start_column: f64, + pub end_column: f64, +} + #[derive(PartialEq, Properties)] pub struct HexEditorProps { pub memory_text_model: UseStateHandle, - pub curr_line: UseStateHandle + // The instruction to highlight + pub instruction_num: UseStateHandle, } #[function_component(HexEditor)] pub fn hex_editor(props: &HexEditorProps) -> Html { let editor_link = CodeEditorLink::new(); - let curr_line = *props.curr_line; - let text_model = &*props.memory_text_model; + // Program counter - will probably change + let instruction_num = *props.instruction_num; + let text_model = &props.memory_text_model; + // Store highlight decoration IDs + let decorations = use_mut_ref(js_sys::Array::new); // create a JavaScript closure for hex highlighting - let cb = Closure::wrap(Box::new(move |event: monaco::sys::editor::ICursorSelectionChangedEvent| { - let highlight_decor = monaco::sys::editor::IModelDecorationOptions::default(); - highlight_decor.set_class_name("hexHighlight".into()); - - debug!("Selection: {:?}", event.selection()); - let selection = event.selection(); - let start_line_number = selection.selection_start_line_number(); - let end_line_number = selection.position_line_number(); - let start_column = selection.start_column(); - let end_column = selection.end_column(); - - let curr_range = monaco::sys::Range::new(start_line_number, start_column, end_line_number, end_column); - - // element to be stored in the stack to highlight the line - let highlight_line: monaco::sys::editor::IModelDeltaDecoration = - Object::new().unchecked_into(); - highlight_line.set_options(&highlight_decor); - let range_js = curr_range - .dyn_into::() - .expect("Hex range is not found."); - highlight_line.set_range(&monaco::sys::IRange::from(range_js)); - // let highlight_js = highlight_line - // .dyn_into::() - // .expect("Hex highlight is not found."); - - if start_column > 8.0 && end_column < 46.0 { - // select ASCII - } - else if start_column > 45.0 && end_column < 63.0 { - // select hex - } - + let text_model_ref = text_model.clone(); + let cb = Closure::new(Box::new( + move |event: monaco::sys::editor::ICursorSelectionChangedEvent| { + // Get a mutable reference to decorations + let decorations = Rc::clone(&decorations); + let mut decorations = decorations.borrow_mut(); + + // Create the ASCII highlight range + let selection = event.selection(); + let start_line_number = selection.selection_start_line_number(); + let start_column = selection.start_column(); + let end_column = selection.end_column(); + let (start_column, end_column) = calculate_ascii_columns(start_column as usize, end_column as usize); + let range = Range::new( + start_line_number, + start_column, + start_line_number, + end_column, + ); + + // Style the highlighting + let highlight_decoration: IModelDeltaDecoration = js_sys::Object::new().unchecked_into(); + let highlight_options: IModelDecorationOptions = js_sys::Object::new().unchecked_into(); + highlight_options.set_inline_class_name("highlightHex".into()); + highlight_options.set_is_whole_line(false.into()); + highlight_decoration.set_options(&highlight_options); + let range_js = range + .dyn_into::() + .expect("Range is not found."); + highlight_decoration.set_range(&monaco::sys::IRange::from(range_js)); + let decoration_js = highlight_decoration + .dyn_into::() + .expect("Highlight is not found."); + + // Create JS Arrays + let not_highlighted = js_sys::Array::new(); + let executed_line = js_sys::Array::new(); + executed_line.push(&decoration_js); + + // Get the monaco text model + let text_model = text_model_ref.clone(); + let text_model = text_model.as_ref(); + // Clear previous highlights + let existing_decorations = text_model.get_all_decorations(None, None); + text_model.delta_decorations(&decorations, ¬_highlighted, None); + // Set new decorations and save their IDs + *decorations = text_model.delta_decorations(&existing_decorations, &executed_line, None); + }, + ) as Box); + + // Returns a struct containing monaco-like coordinates (start and end line numbers and columns) + // given the program counter (index of a WORD) + fn get_hex_coords(instruction_num: u64) -> HexCoord { + let line_number = instruction_num / 16 + 1; + let offset = 10; + let start_column = offset + ((instruction_num % 16) * 2 + ((instruction_num % 16) / 4)); + let end_column = start_column + 8; + + let coords = HexCoord { + line_number: line_number as f64, + start_column: start_column as f64, + end_column: end_column as f64, + }; + + coords + } - }) as Box); + // Calculates which columns in the ASCII portion belong to the given hex portion + fn calculate_ascii_columns(hex_start_column: usize, hex_end_column: usize) -> (f64, f64) { + if hex_start_column > 8 && hex_start_column < 46 && hex_end_column > 8 && hex_end_column < 46 && hex_end_column > hex_start_column { + let ascii_length = (hex_end_column - hex_start_column) / 2; + let start_column = 46 + ((hex_start_column - 8) / 2) - 1; + let end_column = start_column + ascii_length; + (start_column as f64, end_column as f64) + } else { + (0.0, 0.0) + } + } let on_editor_created = { - let curr_line = curr_line; - use_callback( - move |editor_link: CodeEditorLink, curr_line| { + move |editor_link: CodeEditorLink, instruction_num| { match editor_link.with_editor(|editor| { let raw_editor = editor.as_ref(); let cb_func = &cb.as_ref().unchecked_ref(); + let coords = get_hex_coords(*instruction_num); raw_editor.on_did_change_cursor_selection(cb_func); - raw_editor.reveal_line_in_center(*curr_line, Some(ScrollType::Smooth)) - + raw_editor.reveal_line_in_center(coords.line_number, Some(ScrollType::Smooth)); + + // Highlight line using delta decorations + let not_highlighted = js_sys::Array::new(); + let executed_line = js_sys::Array::new(); + let decoration: IModelDeltaDecoration = js_sys::Object::new().unchecked_into(); + let options: IModelDecorationOptions = js_sys::Object::new().unchecked_into(); + if coords.line_number != 0.0 { + // Show highlight if current line is not 0 + options.set_inline_class_name("executedLine".into()); + options.set_is_whole_line(false.into()); + } + decoration.set_options(&options); + let curr_range = Range::new( + coords.line_number, + coords.start_column, + coords.line_number, + coords.end_column, + ); + let range_js = curr_range + .dyn_into::() + .expect("Range is not found."); + decoration.set_range(&monaco::sys::IRange::from(range_js)); + let decoration_js = decoration + .dyn_into::() + .expect("Highlight is not found."); + executed_line.push(&decoration_js); + + raw_editor.delta_decorations(¬_highlighted, &executed_line); }) { Some(()) => debug!("Hex Editor linked!"), - None => debug!("No editor :<") + None => debug!("No editor :<"), }; }, - curr_line, + instruction_num, ) }; html! { @@ -87,13 +173,12 @@ pub fn hex_editor(props: &HexEditorProps) -> Html { classes={"editor"} link={editor_link} options={get_options()} - model={text_model.clone()} + model={text_model.deref().clone()} on_editor_created={on_editor_created} /> } } - fn get_options() -> IStandaloneEditorConstructionOptions { let options = IStandaloneEditorConstructionOptions::default(); options.set_theme("vs-dark".into()); diff --git a/src/ui/swim_editor/component.rs b/src/ui/swim_editor/component.rs index 7210279e4..73ae88b18 100644 --- a/src/ui/swim_editor/component.rs +++ b/src/ui/swim_editor/component.rs @@ -7,9 +7,7 @@ use yew::{Callback, Properties}; use yew::prelude::*; use wasm_bindgen::{JsCast, JsValue}; -use crate::{parser::parser_structs_and_enums::ProgramInfo, ui::assembled_view::component::{DataSegment, TextSegment}}; - -use log::debug; +use crate::{parser::parser_structs_and_enums::ProgramInfo, ui::{assembled_view::component::{DataSegment, TextSegment}, console::component::ConsoleTabState}}; #[derive(PartialEq, Properties)] pub struct SwimEditorProps { @@ -18,9 +16,10 @@ pub struct SwimEditorProps { pub program_info: ProgramInfo, pub binary: Vec, pub pc: u64, - pub memory_curr_line: UseStateHandle, + pub memory_curr_instr: UseStateHandle, pub editor_curr_line: UseStateHandle, - pub active_tab: UseStateHandle + pub editor_active_tab: UseStateHandle, + pub console_active_tab: UseStateHandle } #[derive(Default, PartialEq)] @@ -61,6 +60,8 @@ fn get_options() -> IStandaloneEditorConstructionOptions { pub fn SwimEditor(props: &SwimEditorProps) -> Html { let link = CodeEditorLink::new(); let text_model = &*props.text_model; + let editor_active_tab = &props.editor_active_tab; + let console_active_tab = &props.console_active_tab; let on_editor_created = { let curr_line = props.editor_curr_line.clone(); @@ -91,7 +92,7 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html { let options: IModelDecorationOptions = js_sys::Object::new().unchecked_into(); if **curr_line != 0.0 { // Show highlight if current line is not 0 - options.set_inline_class_name("myInlineDecoration".into()); + options.set_inline_class_name("executedLine".into()); options.set_is_whole_line(true.into()); } decoration.set_options(&options); @@ -114,9 +115,8 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html { ) }; - let active_tab = &props.active_tab; let change_tab = { - let active_tab = active_tab.clone(); + let editor_active_tab = editor_active_tab.clone(); Callback::from(move |event: MouseEvent| { let target = event.target().unwrap().dyn_into::().unwrap(); let tab_name = target @@ -130,36 +130,36 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html { _ => EditorTabState::default(), }; - active_tab.set(new_tab); + editor_active_tab.set(new_tab); }) }; html! { <> // Editor buttons
- if **active_tab == EditorTabState::Editor { + if **editor_active_tab == EditorTabState::Editor { } else { } - if **active_tab == EditorTabState::TextSegment { + if **editor_active_tab == EditorTabState::TextSegment { } else { } - if **active_tab == EditorTabState::DataSegment { + if **editor_active_tab == EditorTabState::DataSegment { } else { }
- if **active_tab == EditorTabState::Editor { + if **editor_active_tab == EditorTabState::Editor { - } else if **active_tab == EditorTabState::TextSegment { - - } else if **active_tab == EditorTabState::DataSegment { + } else if **editor_active_tab == EditorTabState::TextSegment { + + } else if **editor_active_tab == EditorTabState::DataSegment { } diff --git a/static/styles/main.css b/static/styles/main.css index b4dea1afb..f7bf66afa 100644 --- a/static/styles/main.css +++ b/static/styles/main.css @@ -45,7 +45,7 @@ body { .code { display: flex; flex-direction: column; - flex-grow: 1; + flex-grow: 1; min-height: 4em; margin-top: 8px; } @@ -55,13 +55,47 @@ body { min-height: 96%; min-width: 100%; } -.myInlineDecoration { - color: rgb(49, 212, 144) !important; +.executedLine { + /* color: rgb(49, 212, 144) !important; */ font-weight: bold; + animation-name: flash_executed; + animation-duration: 3s; + animation-fill-mode: forwards; } -.hexHighlight { - color: rgb(49, 212, 144) !important; +.updatedLine { + /* color: rgb(49, 212, 144) !important; */ font-weight: bold; + animation-name: flash_updated; + animation-duration: 1s; + animation-timing-function: ease-in; +} + +.highlightHex { + background-color: rgb(71 188 255 / 41%); +} + +@keyframes flash_executed { + from { + color: rgb(49, 212, 144); + } + to { + color: rgb(49, 212, 144); + } + to { + color: white; + } +} + +@keyframes flash_updated { + from { + color: red; + } + to { + color: red; + } + to { + color: white; + } } /****** Assembled View ******/ @@ -221,7 +255,7 @@ tr:nth-child(even) { background-color: #1e1e1e; input { - + background-color: #1e1e1e; } } @@ -229,7 +263,7 @@ tr:nth-child(odd) { background-color: #101010; input { - + background-color: #101010; } } From d20606967063a3906b702f4dd11b01a9524bcb24 Mon Sep 17 00:00:00 2001 From: Cay Date: Sun, 4 Feb 2024 20:02:11 -0500 Subject: [PATCH 034/355] Additional polish to the hex editor and segment views --- src/bin/main.rs | 275 +++++++--------------- src/parser/parser_assembler_main.rs | 9 +- src/parser/parser_structs_and_enums.rs | 1 + src/tests/parser/parser_assembler_main.rs | 2 +- src/ui/assembled_view/component.rs | 70 +++--- src/ui/swim_editor/component.rs | 97 +++++++- static/styles/main.css | 14 +- 7 files changed, 225 insertions(+), 243 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index d09a518da..09c573e43 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -7,11 +7,9 @@ use monaco::{ api::TextModel, sys::{ editor::{ - IMarkerData, - IModelDecorationOptions, - IModelDeltaDecoration, + IMarkerData }, - IMarkdownString, MarkerSeverity, + MarkerSeverity, } }; use swim::{parser::parser_assembler_main::parser, ui::{console::component::ConsoleTabState, swim_editor::component::EditorTabState}}; @@ -58,11 +56,6 @@ fn app(props: &AppProps) -> Html { //let text_model = use_mut_ref(|| TextModel::create(&code, Some(&language), None).unwrap()); let text_model = use_state_eq(|| TextModel::create(CONTENT, Some("mips"), None).unwrap()); - // Setup the array that would store decorations applied to the - // text model and initialize the options for it. - let hover_jsarray = js_sys::Array::new(); - let hover_decor_array = use_mut_ref(js_sys::Array::new); - // Store the currently executed line in code editor and hex editor let editor_curr_line = use_state_eq(|| 0.0); let memory_curr_instr = use_state_eq(|| 0); @@ -78,9 +71,6 @@ fn app(props: &AppProps) -> Html { let program_info_ref = use_mut_ref(ProgramInfo::default); let binary_ref = use_mut_ref(Vec::::new); - // let last_memory_text_model = use_mut_ref(|| TextModel::create(&memory_text_output, Some("ini"), None).unwrap()); - // let memory_text_model = use_mut_ref(|| TextModel::create(&memory_text_output, Some("ini"), None).unwrap()); - let last_memory_text_model = use_state_eq(|| TextModel::create(&memory_text_output, Some("ini"), None).unwrap()); let memory_text_model = use_state_eq(|| TextModel::create(&memory_text_output, Some("ini"), None).unwrap()); // Store the currently selected tabs in windows @@ -107,13 +97,9 @@ fn app(props: &AppProps) -> Html { let on_assemble_clicked = { // props.communicator.send_test_message(1); // Test message, remove later. let communicator = props.communicator; - // let text_model = Rc::clone(&text_model); let text_model = text_model.clone(); - // let memory_text_model = Rc::clone(&memory_text_model); let memory_text_model = memory_text_model.clone(); let memory_curr_instr = memory_curr_instr.clone(); - // let last_memory_text_model = Rc::clone(&last_memory_text_model); - let last_memory_text_model = last_memory_text_model.clone(); let datapath = Rc::clone(&datapath); let parser_text_output = parser_text_output.clone(); let trigger = use_force_update(); @@ -135,7 +121,6 @@ fn app(props: &AppProps) -> Html { *binary_ref.borrow_mut() = assembled.clone(); pc_limit.set(assembled.len() * 4); parser_text_output.set(program_info.console_out_post_assembly); - let last_memory_text_model = last_memory_text_model.clone(); let mut markers: Vec = vec![]; @@ -185,7 +170,6 @@ fn app(props: &AppProps) -> Html { text_model.set_value(&program_info.updated_monaco_string); // Expands pseudo-instructions to their hardware counterpart. let hexdump = &datapath.memory.generate_formatted_hex(); memory_text_model.set_value(hexdump); - last_memory_text_model.set_value(hexdump); datapath.registers.pc = program_info.pc_starting_point as u64; } @@ -203,34 +187,25 @@ fn app(props: &AppProps) -> Html { // code, the previously executed line is highlighted. let on_execute_clicked = { let datapath = Rc::clone(&datapath); + let program_info_ref = Rc::clone(&program_info_ref); // Code editor - // let text_model = Rc::clone(&text_model); - let text_model = text_model.clone(); let editor_curr_line = editor_curr_line.clone(); let memory_curr_instr = memory_curr_instr.clone(); // Hex editor - // let memory_text_model = Rc::clone(&memory_text_model); let memory_text_model = memory_text_model.clone(); - // let last_memory_text_model = Rc::clone(&last_memory_text_model); - let last_memory_text_model = last_memory_text_model.clone(); + let trigger = use_force_update(); use_callback( move |_, (editor_curr_line, memory_curr_instr)| { let mut datapath = datapath.borrow_mut(); - let text_model = text_model.clone(); - // let memory_text_model = Rc::clone(&memory_text_model); let memory_text_model = memory_text_model.clone(); - // let last_memory_text_model = Rc::clone(&last_memory_text_model); - let last_memory_text_model = last_memory_text_model.clone(); - // let mut editor_curr_line = editor_curr_line.borrow_mut(); - - // Pull ProgramInfo from the parser - let (programinfo, _) = parser(text_model.get_value()); // Get the current line and convert it to f64 + let programinfo = Rc::clone(&program_info_ref); + let programinfo = programinfo.borrow().clone(); let list_of_line_numbers = programinfo.address_to_line_number; let index = datapath.registers.pc as usize / 4; editor_curr_line.set(*list_of_line_numbers.get(index).unwrap_or(&0) as f64 + 1.0); // add one to account for the editor's line numbers @@ -243,7 +218,6 @@ fn app(props: &AppProps) -> Html { let hexdump = &datapath.memory.generate_formatted_hex(); memory_text_model.set_value(hexdump); - last_memory_text_model.set_value(hexdump); trigger.force_update(); }, @@ -253,33 +227,27 @@ fn app(props: &AppProps) -> Html { let on_execute_stage_clicked = { let datapath = Rc::clone(&datapath); + let program_info_ref = Rc::clone(&program_info_ref); // Code editor - // let text_model = Rc::clone(&text_model); - let text_model = text_model.clone(); let editor_curr_line = editor_curr_line.clone(); - let trigger = use_force_update(); // Hex editor - // let memory_text_model = Rc::clone(&memory_text_model); let memory_text_model = memory_text_model.clone(); - // let last_memory_text_model = Rc::clone(&last_memory_text_model); - let last_memory_text_model = last_memory_text_model.clone(); let memory_curr_instr = memory_curr_instr.clone(); + let trigger = use_force_update(); + use_callback( move |_, (editor_curr_line, memory_curr_instr)| { let mut datapath = datapath.borrow_mut(); - // let memory_text_model = Rc::clone(&memory_text_model); let memory_text_model = memory_text_model.clone(); - // let last_memory_text_model = Rc::clone(&last_memory_text_model); - let last_memory_text_model = last_memory_text_model.clone(); if datapath.current_stage == Stage::InstructionDecode { // highlight on InstructionDecode since syscall stops at that stage. - let text_model = text_model.clone(); - let (programinfo, _) = parser(text_model.get_value()); + let programinfo = Rc::clone(&program_info_ref); + let programinfo = programinfo.borrow().clone(); let list_of_line_numbers = programinfo.address_to_line_number; let index = datapath.registers.pc as usize / 4; editor_curr_line.set(*list_of_line_numbers.get(index).unwrap_or(&0) as f64 + 1.0); @@ -293,7 +261,7 @@ fn app(props: &AppProps) -> Html { let hexdump = &datapath.memory.generate_formatted_hex(); memory_text_model.set_value(hexdump); - last_memory_text_model.set_value(hexdump); + trigger.force_update(); }, (editor_curr_line, memory_curr_instr), @@ -302,107 +270,104 @@ fn app(props: &AppProps) -> Html { let on_memory_clicked = { let datapath = Rc::clone(&datapath); - let trigger = use_force_update(); + let program_info_ref = Rc::clone(&program_info_ref); // Code editor - // let text_model = Rc::clone(&text_model); let text_model = text_model.clone(); // Hex editor - // let memory_text_model = Rc::clone(&memory_text_model); let memory_text_model = memory_text_model.clone(); - // let last_memory_text_model = Rc::clone(&last_memory_text_model); - let last_memory_text_model = last_memory_text_model.clone(); + + let trigger = use_force_update(); use_callback( move |_, _| { let mut datapath = datapath.borrow_mut(); let text_model = text_model.clone(); - let (programinfo, binary) = parser(text_model.get_value()); + let program_info_ref = Rc::clone(&program_info_ref); // Update memory - // let memory_text_model = Rc::clone(&memory_text_model); let memory_text_model = memory_text_model.clone(); - // let last_memory_text_model = Rc::clone(&last_memory_text_model); - let last_memory_text_model = last_memory_text_model.clone(); - let last_memory_text_model_value = last_memory_text_model.get_value(); let current_memory_text_model_value = memory_text_model.get_value(); - if current_memory_text_model_value != last_memory_text_model_value { - match datapath.memory.parse_hexdump(¤t_memory_text_model_value) { - Ok(instructions) => { - debug!("Memory parsed with no errors."); - match datapath.memory.store_hexdump(instructions) { - Ok(changed_lines) => { - debug!("Memory updated successfully. Changed lines:"); - debug!("{:?}", changed_lines); - let mut lines_beyond_counter = programinfo.address_to_line_number.len(); - let mut curr_value = text_model.get_value().to_owned(); - let mut add_new_lines = false; - for line in changed_lines { - if line.line_number < programinfo.address_to_line_number.len() { - debug!("{}", binary[line.line_number]); - debug!("{}", programinfo.address_to_line_number[line.line_number]); - let updated_line = programinfo.address_to_line_number[line.line_number] as f64 + 1.0; - let curr_model = text_model.as_ref(); - - let line_to_replace = curr_model.get_line_content(updated_line); - let mut start_line_column = 0.0; - let end_line_column = line_to_replace.len() as f64 + 2.0; - for (i, c) in line_to_replace.chars().enumerate() { - if c.is_alphanumeric() { - start_line_column = i as f64 + 1.0; - break; - } + match datapath.memory.parse_hexdump(¤t_memory_text_model_value) { + Ok(instructions) => { + // Memory parsed with no errors + match datapath.memory.store_hexdump(instructions) { + Ok(changed_lines) => { + // Memory updated successfully + let program_info = program_info_ref.borrow().clone(); + let mut lines_beyond_counter = program_info.address_to_line_number.len(); + let mut curr_value = text_model.get_value().to_owned(); + let mut add_new_lines = false; + for line in changed_lines { + // Check if we're updating or appending instruction + if line.line_number < program_info.address_to_line_number.len() { + let updated_line = program_info.address_to_line_number[line.line_number] as f64 + 1.0; + let curr_model = text_model.as_ref(); + + // Get the current line's contents in the code editor + let line_to_replace = curr_model.get_line_content(updated_line); + // Create the range to replace + let mut start_line_column = 0.0; + let end_line_column = line_to_replace.len() as f64 + 2.0; + for (i, c) in line_to_replace.chars().enumerate() { + if c.is_alphanumeric() { + start_line_column = i as f64 + 1.0; + break; } - debug!("Line to replace -> {:?}, {:?}: {:?}: {:?}: {:?}", line_to_replace, updated_line, start_line_column, updated_line, end_line_column); - - let edit_range = monaco::sys::Range::new(updated_line, start_line_column, updated_line, end_line_column); - let before_cursor_state = monaco::sys::Selection::new(updated_line, start_line_column, updated_line,end_line_column); - let edit_operations: monaco::sys::editor::IIdentifiedSingleEditOperation = Object::new().unchecked_into(); - edit_operations.set_range(&edit_range); - edit_operations.set_text(Some(&line.text)); - let edit_operations_array = js_sys::Array::new(); - edit_operations_array.push(&edit_operations); - let before_cursor_state_array = js_sys::Array::new(); - before_cursor_state_array.push(&before_cursor_state); - curr_model.push_edit_operations(&before_cursor_state_array, &edit_operations_array, None); - } else if line.line_number == lines_beyond_counter { - debug!("Adding new line: {}", &line.text); - // check if we've added new lines already - if !add_new_lines { - // start adding new lines by getting a copy of the current text model to append to - add_new_lines = true; - curr_value = text_model.get_value(); - } - curr_value.push_str("\n"); - curr_value.push_str(&line.text); - lines_beyond_counter += 1; } + let edit_range = monaco::sys::Range::new(updated_line, start_line_column, updated_line, end_line_column); + let before_cursor_state = monaco::sys::Selection::new(updated_line, start_line_column, updated_line,end_line_column); + // Create the edit operation using the range and new text + let edit_operations: monaco::sys::editor::IIdentifiedSingleEditOperation = Object::new().unchecked_into(); + edit_operations.set_range(&edit_range); + edit_operations.set_text(Some(&line.text)); + // Append it to JavaScript Array + let edit_operations_array = js_sys::Array::new(); + edit_operations_array.push(&edit_operations); + let before_cursor_state_array = js_sys::Array::new(); + before_cursor_state_array.push(&before_cursor_state); + // Do the edit! + curr_model.push_edit_operations(&before_cursor_state_array, &edit_operations_array, None); + } else if line.line_number == lines_beyond_counter { + // Append instruction + if !add_new_lines { + // If we've added new lines already, + // start adding new lines by getting a copy of the current text model to append to + add_new_lines = true; + curr_value = text_model.get_value(); + } + curr_value.push_str("\n"); + curr_value.push_str(&line.text); + lines_beyond_counter += 1; } - if add_new_lines { - text_model.set_value(&curr_value); - } - - }, - Err(err) => { - debug!("Error: {}", err) } - }; - () - }, - Err(err) => { - debug!("Error updating memory: {}", err) - } + if add_new_lines { + text_model.set_value(&curr_value); + } + + }, + Err(err) => { + debug!("Error: {}", err) + } + }; + () + }, + Err(err) => { + debug!("Error updating memory: {}", err) } } let hexdump = &datapath.memory.generate_formatted_hex(); memory_text_model.set_value(hexdump); - last_memory_text_model.set_value(hexdump); + + // Update the parsed info for text and data segment views + let (program_info, _) = parser(text_model.get_value()); + *program_info_ref.borrow_mut() = program_info.clone(); trigger.force_update(); @@ -422,10 +387,7 @@ fn app(props: &AppProps) -> Html { let editor_curr_line = editor_curr_line.clone(); // Hex editor - // let memory_text_model = Rc::clone(&memory_text_model); let memory_text_model = memory_text_model.clone(); - // let last_memory_text_model = Rc::clone(&last_memory_text_model); - let last_memory_text_model = last_memory_text_model.clone(); let memory_curr_instr = memory_curr_instr.clone(); use_callback( @@ -440,13 +402,9 @@ fn app(props: &AppProps) -> Html { datapath.reset(); // Clear hex editor content - // let memory_text_model = Rc::clone(&memory_text_model); let memory_text_model = memory_text_model.clone(); - // let last_memory_text_model = Rc::clone(&last_memory_text_model); - let last_memory_text_model = last_memory_text_model.clone(); memory_text_model.set_value(""); - last_memory_text_model.set_value(""); trigger.force_update(); }, @@ -456,7 +414,6 @@ fn app(props: &AppProps) -> Html { // Copies text to the user's clipboard let on_clipboard_clicked = { - // let text_model = Rc::clone(&text_model); let text_model = text_model.clone(); let clipboard = use_clipboard(); Callback::from(move |_: _| { @@ -466,71 +423,6 @@ fn app(props: &AppProps) -> Html { }) }; - // We'll have the Mouse Hover event running at all times. - { - // let text_model = Rc::clone(&text_model); - let text_model = text_model.clone(); - use_event_with_window("mouseover", move |_: MouseEvent| { - let hover_jsarray = hover_jsarray.clone(); - let hover_decor_array = hover_decor_array.clone(); - let text_model = text_model.clone(); - let curr_model = text_model.as_ref(); - let (program_info, _) = parser(text_model.get_value()); - - // Parse output from parser and create an instance of IModelDeltaDecoration for each line. - for (line_number, line_information) in program_info.monaco_line_info.iter().enumerate() - { - let decoration: IModelDeltaDecoration = new_object().into(); - - let hover_range = monaco::sys::Range::new( - (line_number + 1) as f64, - 0.0, - (line_number + 1) as f64, - 0.0, - ); - let hover_range_js = hover_range - .dyn_into::() - .expect("Range is not found."); - decoration.set_range(&monaco::sys::IRange::from(hover_range_js)); - - let hover_opts: IModelDecorationOptions = new_object().into(); - hover_opts.set_is_whole_line(true.into()); - let hover_message: IMarkdownString = new_object().into(); - js_sys::Reflect::set( - &hover_message, - &JsValue::from_str("value"), - &JsValue::from_str(&line_information.mouse_hover_string), - ) - .unwrap(); - hover_opts.set_hover_message(&hover_message); - decoration.set_options(&hover_opts); - let hover_js = decoration - .dyn_into::() - .expect("Hover is not found."); - hover_jsarray.push(&hover_js); - } - - // log!("This is the array after the push"); - // log!(hover_jsarray.clone()); - - // properly pass the handlers onto the array - let new_hover_decor_array = - curr_model.delta_decorations(&hover_decor_array.borrow_mut(), &hover_jsarray, None); - *hover_decor_array.borrow_mut() = new_hover_decor_array; - - // log!("These are the arrays after calling Delta Decorations"); - // log!(hover_jsarray.clone()); - // log!(hover_decor_array.borrow_mut().clone()); - - // empty out the array that hold the decorations - hover_jsarray.set_length(0); - - // log!("These are the arrays after calling popping the hover_jsarray"); - // log!(hover_jsarray.clone()); - // log!(hover_decor_array.borrow_mut().clone()); - }); - }; - // This is where we will have the user prompted to load in a file let upload_clicked_callback = use_callback( move |e: MouseEvent, _| { @@ -542,7 +434,6 @@ fn app(props: &AppProps) -> Html { // This is the callback to get the file's contents and load it onto the Editor let file_picked_callback = { - // let text_model = Rc::clone(&text_model); let text_model = text_model.clone(); use_callback( move |e: Event, _| { @@ -588,7 +479,7 @@ fn app(props: &AppProps) -> Html { // Editor
- +
// Console diff --git a/src/parser/parser_assembler_main.rs b/src/parser/parser_assembler_main.rs index 46ed9ab4e..922823859 100644 --- a/src/parser/parser_assembler_main.rs +++ b/src/parser/parser_assembler_main.rs @@ -50,7 +50,7 @@ pub fn parser(file_string: String) -> (ProgramInfo, Vec) { &mut program_info.monaco_line_info, ); - let binary = create_binary_vec(program_info.instructions.clone(), vec_of_data); + let (binary, data_starting_point) = create_binary_vec(program_info.instructions.clone(), vec_of_data); for entry in &program_info.monaco_line_info { program_info @@ -65,6 +65,7 @@ pub fn parser(file_string: String) -> (ProgramInfo, Vec) { } program_info.pc_starting_point = determine_pc_starting_point(labels); + program_info.data_starting_point = data_starting_point; (program_info.clone(), binary) } @@ -1531,13 +1532,15 @@ pub fn determine_pc_starting_point(labels: HashMap) -> usize { } ///Creates a vector of u32 from the data found in the parser / assembler to put into memory. -pub fn create_binary_vec(instructions: Vec, mut vec_of_data: Vec) -> Vec { +pub fn create_binary_vec(instructions: Vec, mut vec_of_data: Vec) -> (Vec, usize) { //push all instructions let mut binary: Vec = Vec::new(); for instruction in instructions { binary.push(instruction.binary); } + let data_starting_point = binary.len(); + //makes sure the byte array length is a multiple of 4 let mut mod4 = 4 - (vec_of_data.len() % 4); if mod4 == 4 { @@ -1563,5 +1566,5 @@ pub fn create_binary_vec(instructions: Vec, mut vec_of_data: Vec, pub data: Vec, pub pc_starting_point: usize, + pub data_starting_point: usize, } #[derive(Clone, Debug, Default, Eq, PartialEq)] diff --git a/src/tests/parser/parser_assembler_main.rs b/src/tests/parser/parser_assembler_main.rs index ea70768b2..ccbb5a155 100644 --- a/src/tests/parser/parser_assembler_main.rs +++ b/src/tests/parser/parser_assembler_main.rs @@ -886,7 +886,7 @@ fn create_binary_vec_works_with_data() { &mut program_info.monaco_line_info, ); - let result = create_binary_vec(program_info.instructions.clone(), vec_of_data); + let (result, _) = create_binary_vec(program_info.instructions.clone(), vec_of_data); assert_eq!(result[3], 0b01110100011010000110100101110011); assert_eq!(result[4], 0b00100000011010010111001100100000); diff --git a/src/ui/assembled_view/component.rs b/src/ui/assembled_view/component.rs index aaa8b5673..07827596f 100644 --- a/src/ui/assembled_view/component.rs +++ b/src/ui/assembled_view/component.rs @@ -27,6 +27,11 @@ pub struct DataSegmentProps { pub program_info: ProgramInfo, pub binary: Vec, pub lines_content: Rc>>, + pub memory_curr_instr: UseStateHandle, + pub editor_curr_line: UseStateHandle, + pub editor_active_tab: UseStateHandle, + pub console_active_tab: UseStateHandle, + pub pc_limit: usize } #[function_component] @@ -40,7 +45,7 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html { let executed_ref = use_node_ref(); { - // Always scroll to the executed row on re-render + // Always scroll to the executed row on execution let executed_row = executed_ref.cast::(); if let Some(executed_row) = executed_row { let mut options = web_sys::ScrollIntoViewOptions::new(); @@ -60,16 +65,18 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html { }); + // Go to the memory address in hex editor let on_address_click = { let memory_curr_instr = memory_curr_instr.clone(); let console_active_tab = console_active_tab.clone(); - use_callback(move |args: (MouseEvent, i64), memory_curr_instr| { + use_callback(move |args: (MouseEvent, usize), memory_curr_instr| { let (_e, address) = args; memory_curr_instr.set(address as u64); console_active_tab.set(ConsoleTabState::HexEditor); }, memory_curr_instr) }; + // Go to the line in code editor let on_assembled_click = { let editor_curr_line = editor_curr_line.clone(); let editor_active_tab = editor_active_tab.clone(); @@ -104,7 +111,7 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html { let line_number = instruction.line_number.clone(); let mut conditional_class = ""; - if props.pc as i64 == address { + if props.pc as i64 == address + 4 { conditional_class = "executedLine"; html!{ @@ -112,7 +119,7 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html {
- + {format!("0x{:08x}", address as u64)} @@ -121,7 +128,7 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html { {format!("0x{:08x}", instruction.binary)} - + {recreated_string} @@ -137,7 +144,7 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html {
- + {format!("0x{:08x}", address as u64)} @@ -146,11 +153,11 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html { {format!("0x{:08x}", instruction.binary)} - + {recreated_string} - {format!("{}: {:?}", line_number, lines_content.get(line_number).unwrap_or(&String::from("")))} + {format!("{}: {:?}", line_number + 1, lines_content.get(line_number).unwrap_or(&String::from("")))} } @@ -166,25 +173,32 @@ pub fn DataSegment(props: &DataSegmentProps) -> Html { let program_info = &props.program_info; let binary = &props.binary; let lines_content = props.lines_content.borrow_mut().clone(); + let memory_curr_instr = &props.memory_curr_instr; + let editor_curr_line = &props.editor_curr_line; + let editor_active_tab = &props.editor_active_tab; + let console_active_tab = &props.console_active_tab; - let on_address_click = Callback::from(move |args: (MouseEvent, usize)| { - let (_e, address) = args; - // let target = e.target(); - // let input = target.unwrap().unchecked_into::(); - - debug!("Go to address {:08x}", address); - debug!("Go to line {:?}", (address / 4) as f64); - - }); - - let on_assembled_click = Callback::from(move |args: (MouseEvent, usize)| { - let (_e, line_number) = args; - // let target = e.target(); - // let input = target.unwrap().unchecked_into::(); - - debug!("Go to line number {:08x}", line_number); + // Go to the memory address in hex editor + let on_address_click = { + let memory_curr_instr = memory_curr_instr.clone(); + let console_active_tab = console_active_tab.clone(); + use_callback(move |args: (MouseEvent, usize), memory_curr_instr| { + let (_e, address) = args; + memory_curr_instr.set(address as u64); + console_active_tab.set(ConsoleTabState::HexEditor); + }, memory_curr_instr) + }; - }); + // Go to the line in code editor + let on_assembled_click = { + let editor_curr_line = editor_curr_line.clone(); + let editor_active_tab = editor_active_tab.clone(); + use_callback(move |args: (MouseEvent, usize), _| { + let (_e, line_number) = args; + editor_curr_line.set(line_number as f64); + editor_active_tab.set(EditorTabState::Editor); + }, ()) + }; html! { @@ -198,11 +212,13 @@ pub fn DataSegment(props: &DataSegmentProps) -> Html { { if program_info.instructions.len() > 0 && binary.len() > 0 { let mut address = program_info.instructions.len() * 4 - 4; + let mut data_binary_index = program_info.data_starting_point - 1; program_info.data.iter().enumerate().map(|(index, data)| { let recreated_string = data.recreate_string(); let on_address_click = Callback::clone(&on_address_click); let on_assembled_click = Callback::clone(&on_assembled_click); address += 4; + data_binary_index += 1; html!{ @@ -210,13 +226,13 @@ pub fn DataSegment(props: &DataSegmentProps) -> Html { {format!("0x{:08x}", address as u64)} } diff --git a/src/ui/swim_editor/component.rs b/src/ui/swim_editor/component.rs index 73ae88b18..cd413f027 100644 --- a/src/ui/swim_editor/component.rs +++ b/src/ui/swim_editor/component.rs @@ -2,8 +2,9 @@ use std::{cell::RefCell, rc::Rc}; use monaco::{api::TextModel, sys::{editor::{ IEditorMinimapOptions, IEditorScrollbarOptions, IModelDecorationOptions, IModelDeltaDecoration, IStandaloneEditorConstructionOptions, ISuggestOptions, ScrollType -}, Range}, yew::{CodeEditor, CodeEditorLink}}; -use yew::{Callback, Properties}; +}, IMarkdownString, Range}, yew::{CodeEditor, CodeEditorLink}}; +use yew::{html, Callback, Properties}; +use yew_hooks::prelude::*; use yew::prelude::*; use wasm_bindgen::{JsCast, JsValue}; @@ -16,6 +17,7 @@ pub struct SwimEditorProps { pub program_info: ProgramInfo, pub binary: Vec, pub pc: u64, + pub pc_limit: usize, pub memory_curr_instr: UseStateHandle, pub editor_curr_line: UseStateHandle, pub editor_active_tab: UseStateHandle, @@ -63,6 +65,11 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html { let editor_active_tab = &props.editor_active_tab; let console_active_tab = &props.console_active_tab; + // Setup the array that would store hover decorations applied to the + // text model and initialize the options for it. + let hover_jsarray = js_sys::Array::new(); + let hover_decor_array = use_mut_ref(js_sys::Array::new); + let on_editor_created = { let curr_line = props.editor_curr_line.clone(); let lines_content = Rc::clone(&props.lines_content); @@ -73,16 +80,14 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html { let raw_editor = editor.as_ref(); let model = raw_editor.get_model().unwrap(); // store each line from the original code editor's contents for assembled view - let js_lines = model.get_lines_content(); - let mut string_lines = lines_content.borrow_mut(); - for js_string in js_lines.into_iter() { - let string_value = match js_string.as_string() { - Some(string) => string, - None => String::from("") - }; - string_lines.push(string_value); - - }; + let line_count = model.get_line_count() as usize; + let mut lines_content = lines_content.borrow_mut(); + let mut lines = Vec::new(); + for i in 1..line_count { + log::debug!("line {}: {}", i, model.get_line_content(i as f64)); + lines.push(model.get_line_content(i as f64)); + } + *lines_content = lines; // Scroll to current line raw_editor.reveal_line_in_center(**curr_line, Some(ScrollType::Smooth)); // Highlight current line using delta decorations @@ -133,6 +138,72 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html { editor_active_tab.set(new_tab); }) }; + + + // We'll have the Mouse Hover event running at all times. + { + let text_model = text_model.clone(); + let program_info = props.program_info.clone(); + use_event_with_window("mouseover", move |_: MouseEvent| { + let hover_jsarray = hover_jsarray.clone(); + let hover_decor_array = hover_decor_array.clone(); + let text_model = text_model.clone(); + let curr_model = text_model.as_ref(); + + // Parse output from parser and create an instance of IModelDeltaDecoration for each line. + for (line_number, line_information) in program_info.monaco_line_info.iter().enumerate() + { + let decoration: IModelDeltaDecoration = js_sys::Object::new().unchecked_into(); + + let hover_range = monaco::sys::Range::new( + (line_number + 1) as f64, + 0.0, + (line_number + 1) as f64, + 0.0, + ); + let hover_range_js = hover_range + .dyn_into::() + .expect("Range is not found."); + decoration.set_range(&monaco::sys::IRange::from(hover_range_js)); + + let hover_opts: IModelDecorationOptions = js_sys::Object::new().unchecked_into(); + hover_opts.set_is_whole_line(true.into()); + let hover_message: IMarkdownString = js_sys::Object::new().unchecked_into(); + js_sys::Reflect::set( + &hover_message, + &JsValue::from_str("value"), + &JsValue::from_str(&line_information.mouse_hover_string), + ) + .unwrap(); + hover_opts.set_hover_message(&hover_message); + decoration.set_options(&hover_opts); + let hover_js = decoration + .dyn_into::() + .expect("Hover is not found."); + hover_jsarray.push(&hover_js); + } + + // log!("This is the array after the push"); + // log!(hover_jsarray.clone()); + + // properly pass the handlers onto the array + let new_hover_decor_array = + curr_model.delta_decorations(&hover_decor_array.borrow_mut(), &hover_jsarray, None); + *hover_decor_array.borrow_mut() = new_hover_decor_array; + + // log!("These are the arrays after calling Delta Decorations"); + // log!(hover_jsarray.clone()); + // log!(hover_decor_array.borrow_mut().clone()); + + // empty out the array that hold the decorations + hover_jsarray.set_length(0); + + // log!("These are the arrays after calling popping the hover_jsarray"); + // log!(hover_jsarray.clone()); + // log!(hover_decor_array.borrow_mut().clone()); + }); + }; + html! { <> // Editor buttons @@ -160,7 +231,7 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html { } else if **editor_active_tab == EditorTabState::TextSegment { } else if **editor_active_tab == EditorTabState::DataSegment { - + } } diff --git a/static/styles/main.css b/static/styles/main.css index f7bf66afa..b3699f021 100644 --- a/static/styles/main.css +++ b/static/styles/main.css @@ -56,11 +56,11 @@ body { min-width: 100%; } .executedLine { - /* color: rgb(49, 212, 144) !important; */ + color: rgb(0 255 149) !important; font-weight: bold; - animation-name: flash_executed; - animation-duration: 3s; - animation-fill-mode: forwards; + /* animation-name: flash_executed; + animation-duration: 2s; + animation-fill-mode: forwards; */ } .updatedLine { /* color: rgb(49, 212, 144) !important; */ @@ -76,13 +76,13 @@ body { @keyframes flash_executed { from { - color: rgb(49, 212, 144); + color: transparent; } to { - color: rgb(49, 212, 144); + color: transparent; } to { - color: white; + color: rgb(0 255 149); } } From 299818d0e89572f2c7340b28b71a43a0806ac50c Mon Sep 17 00:00:00 2001 From: Cay Date: Sun, 4 Feb 2024 23:17:19 -0500 Subject: [PATCH 035/355] Start console i/o UI --- src/agent/datapath_communicator.rs | 4 + src/bin/main.rs | 16 +-- src/ui.rs | 5 +- src/ui/assembled_view/component.rs | 10 +- src/ui/console/component.rs | 164 +++++++++------------------ src/ui/console/mod.rs | 3 +- src/ui/footer/component.rs | 132 +++++++++++++++++++++ src/ui/{console => footer}/helper.rs | 0 src/ui/footer/mod.rs | 2 + src/ui/swim_editor/component.rs | 5 +- static/styles/main.css | 27 ++++- 11 files changed, 235 insertions(+), 133 deletions(-) create mode 100644 src/ui/footer/component.rs rename src/ui/{console => footer}/helper.rs (100%) create mode 100644 src/ui/footer/mod.rs diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index 693dc33d8..498ceeff2 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -159,4 +159,8 @@ impl DatapathCommunicator { ) -> Box { todo!() } + + pub fn get_accepting_input(&self) -> bool { + todo!() + } } diff --git a/src/bin/main.rs b/src/bin/main.rs index 09c573e43..80ea0ac85 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -6,13 +6,11 @@ use js_sys::Object; use monaco::{ api::TextModel, sys::{ - editor::{ - IMarkerData - }, + editor::IMarkerData, MarkerSeverity, } }; -use swim::{parser::parser_assembler_main::parser, ui::{console::component::ConsoleTabState, swim_editor::component::EditorTabState}}; +use swim::{parser::parser_assembler_main::parser, ui::{footer::component::FooterTabState, swim_editor::component::EditorTabState}}; use swim::parser::parser_structs_and_enums::ProgramInfo; use std::rc::Rc; use swim::agent::EmulationCoreAgent; @@ -20,7 +18,7 @@ use swim::agent::datapath_communicator::DatapathCommunicator; use swim::emulation_core::datapath::Datapath; use swim::emulation_core::mips::datapath::MipsDatapath; use swim::emulation_core::mips::datapath::Stage; -use swim::ui::console::component::Console; +use swim::ui::footer::component::Footer; use swim::ui::regview::component::Regview; use swim::ui::swim_editor::component::SwimEditor; use wasm_bindgen::{JsCast, JsValue}; @@ -73,8 +71,12 @@ fn app(props: &AppProps) -> Html { let memory_text_model = use_state_eq(|| TextModel::create(&memory_text_output, Some("ini"), None).unwrap()); + // Show input + let show_input = use_state_eq(|| bool::default()); + show_input.set(true); + // Store the currently selected tabs in windows - let console_active_tab = use_state_eq(ConsoleTabState::default); + let console_active_tab = use_state_eq(FooterTabState::default); let editor_active_tab = use_state_eq(EditorTabState::default); // Since we want the Datapath to be independent from all the @@ -483,7 +485,7 @@ fn app(props: &AppProps) -> Html { // Console - +
// Right column diff --git a/src/ui.rs b/src/ui.rs index ae0251e6f..5decab0cf 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -2,8 +2,9 @@ pub mod assembled_view; -pub mod console; +pub mod footer; pub mod hex_editor; pub mod regview; pub mod swim_editor; -pub mod visual_datapath; \ No newline at end of file +pub mod visual_datapath; +pub mod console; \ No newline at end of file diff --git a/src/ui/assembled_view/component.rs b/src/ui/assembled_view/component.rs index 07827596f..a4ac3a3fd 100644 --- a/src/ui/assembled_view/component.rs +++ b/src/ui/assembled_view/component.rs @@ -8,7 +8,7 @@ use yew::prelude::*; use wasm_bindgen::JsCast; use log::debug; use crate::parser::parser_structs_and_enums::ProgramInfo; -use crate::ui::console::component::ConsoleTabState; +use crate::ui::footer::component::FooterTabState; use crate::ui::swim_editor::component::EditorTabState; @@ -20,7 +20,7 @@ pub struct TextSegmentProps { pub editor_curr_line: UseStateHandle, pub pc: u64, pub editor_active_tab: UseStateHandle, - pub console_active_tab: UseStateHandle + pub console_active_tab: UseStateHandle } #[derive(PartialEq, Properties)] pub struct DataSegmentProps { @@ -30,7 +30,7 @@ pub struct DataSegmentProps { pub memory_curr_instr: UseStateHandle, pub editor_curr_line: UseStateHandle, pub editor_active_tab: UseStateHandle, - pub console_active_tab: UseStateHandle, + pub console_active_tab: UseStateHandle, pub pc_limit: usize } @@ -72,7 +72,7 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html { use_callback(move |args: (MouseEvent, usize), memory_curr_instr| { let (_e, address) = args; memory_curr_instr.set(address as u64); - console_active_tab.set(ConsoleTabState::HexEditor); + console_active_tab.set(FooterTabState::HexEditor); }, memory_curr_instr) }; @@ -185,7 +185,7 @@ pub fn DataSegment(props: &DataSegmentProps) -> Html { use_callback(move |args: (MouseEvent, usize), memory_curr_instr| { let (_e, address) = args; memory_curr_instr.set(address as u64); - console_active_tab.set(ConsoleTabState::HexEditor); + console_active_tab.set(FooterTabState::HexEditor); }, memory_curr_instr) }; diff --git a/src/ui/console/component.rs b/src/ui/console/component.rs index 46431702c..ba5c087ac 100644 --- a/src/ui/console/component.rs +++ b/src/ui/console/component.rs @@ -1,130 +1,70 @@ -//use crate::parser::parser_structs_and_enums::instruction_tokenization::ProgramInfo; -//use monaco::api::TextModel; -use wasm_bindgen::JsCast; -use web_sys::HtmlElement; +use crate::agent::datapath_communicator::DatapathCommunicator; +use web_sys::{KeyboardEvent, InputEvent, HtmlInputElement}; use yew::prelude::*; -use yew_hooks::prelude::*; -use monaco::api::TextModel; -use crate::emulation_core::mips::datapath::MipsDatapath; -use crate::ui::visual_datapath::{DatapathSize, VisualDatapath}; -use crate::ui::hex_editor::component::HexEditor; +use wasm_bindgen::JsCast; #[derive(PartialEq, Properties)] pub struct Consoleprops { - pub datapath: MipsDatapath, + pub communicator: &'static DatapathCommunicator, pub parsermsg: String, - pub memory_text_model: UseStateHandle, - pub memory_curr_instr: UseStateHandle, - pub active_tab: UseStateHandle, -} - -#[derive(Default, PartialEq)] -pub enum ConsoleTabState { - #[default] - Console, - Datapath, - HexEditor + pub show_input: UseStateHandle } #[function_component(Console)] pub fn console(props: &Consoleprops) -> Html { - let active_tab = &props.active_tab; - let zoom_datapath = use_bool_toggle(false); - let switch_datapath = use_bool_toggle(false); - let change_tab = { - let active_tab = active_tab.clone(); - Callback::from(move |event: MouseEvent| { - let target = event.target().unwrap().dyn_into::().unwrap(); - let tab_name = target - .get_attribute("label") - .unwrap_or(String::from("console")); - - let new_tab = match tab_name.as_str() { - "console" => ConsoleTabState::Console, - "datapath" => ConsoleTabState::Datapath, - "hex_editor" => ConsoleTabState::HexEditor, - _ => ConsoleTabState::default(), - }; - - active_tab.set(new_tab); - }) - }; - - let toggle_zoom = { - let zoom_datapath = zoom_datapath.clone(); - - Callback::from(move |_| { - zoom_datapath.toggle(); - }) - }; - - let datapath_size = match *zoom_datapath { - true => DatapathSize::Big, - false => DatapathSize::Small, - }; - - let switch_datapath_type = { - let switch_datapath = switch_datapath.clone(); - - Callback::from(move |_| { - switch_datapath.toggle(); - }) + let show_input = props.show_input.clone(); + let input_value = use_state_eq(String::new); + let error_msg = use_state_eq(|| ""); + + let on_keyup = { + let error_msg = error_msg.clone(); + let input_value = input_value.clone(); + use_callback(move |event: KeyboardEvent, (input_value, error_msg)| { + // let communicator = props.communicator; + let key_code = event.key_code(); + let error_msg = error_msg.clone(); + let input_value = input_value.clone(); + // If Enter was pressed parse and send input to emulator core + if key_code == 13 { + let input_value = &*input_value; + log::debug!("Input: {}", (input_value)); + // Parse based on syscall type (int, float, string) + let val: String = match input_value.parse() { + Ok(value) => { + value + }, + Err(_err) => { + error_msg.set("Invalid input"); + return + } + }; + // Send Input command + } + }, (input_value, error_msg)) }; - let svg_path = match *switch_datapath { - true => "static/datapath_full.svg", - false => "static/datapath_simple.svg", - }; + let on_input = Callback::from(move |event: InputEvent| { + // let communicator = props.communicator; + let target = event.target(); + let input = target.unwrap().unchecked_into::(); - let switch_datapath_button_label = match *switch_datapath { - true => "Switch to Simple Datapath", - false => "Switch to Full Datapath", - }; + input_value.set(input.value()); + }); html! { - <> - // Console buttons - if **active_tab == ConsoleTabState::Console { -
-                    { props.parsermsg.clone() }
-                
- } else if **active_tab == ConsoleTabState::Datapath { -
- -
- } else if **active_tab == ConsoleTabState::HexEditor { -
- +
+ {props.parsermsg.clone()} +
+ {*error_msg} +
+ if *show_input { +
+ + + +
} -
-
- if **active_tab == ConsoleTabState::Console { - - } else { - - } - - if **active_tab == ConsoleTabState::Datapath { - - } else { - - } - - if **active_tab == ConsoleTabState::HexEditor { - - } else { - - } -
- - if **active_tab == ConsoleTabState::Datapath { -
- - -
- } -
- +
} } diff --git a/src/ui/console/mod.rs b/src/ui/console/mod.rs index bff6cf38a..519c53d92 100644 --- a/src/ui/console/mod.rs +++ b/src/ui/console/mod.rs @@ -1,2 +1 @@ -pub mod component; -pub mod helper; +pub mod component; \ No newline at end of file diff --git a/src/ui/footer/component.rs b/src/ui/footer/component.rs new file mode 100644 index 000000000..e693aaf4c --- /dev/null +++ b/src/ui/footer/component.rs @@ -0,0 +1,132 @@ +use wasm_bindgen::JsCast; +use web_sys::HtmlElement; +use yew::prelude::*; +use yew_hooks::prelude::*; +use monaco::api::TextModel; +use crate::agent::datapath_communicator::DatapathCommunicator; +use crate::emulation_core::mips::datapath::MipsDatapath; +use crate::ui::visual_datapath::{DatapathSize, VisualDatapath}; +use crate::ui::hex_editor::component::HexEditor; +use crate::ui::console::component::Console; + +#[derive(PartialEq, Properties)] +pub struct Footerprops { + pub communicator: &'static DatapathCommunicator, + pub datapath: MipsDatapath, + pub parsermsg: String, + pub show_input: UseStateHandle, + pub memory_text_model: UseStateHandle, + pub memory_curr_instr: UseStateHandle, + pub active_tab: UseStateHandle, +} + +#[derive(Default, PartialEq)] +pub enum FooterTabState { + #[default] + Console, + Datapath, + HexEditor +} + +#[function_component(Footer)] +pub fn footer(props: &Footerprops) -> Html { + let active_tab = &props.active_tab; + let zoom_datapath = use_bool_toggle(false); + let switch_datapath = use_bool_toggle(false); + let change_tab = { + let active_tab = active_tab.clone(); + Callback::from(move |event: MouseEvent| { + let target = event.target().unwrap().dyn_into::().unwrap(); + let tab_name = target + .get_attribute("label") + .unwrap_or(String::from("console")); + + let new_tab = match tab_name.as_str() { + "console" => FooterTabState::Console, + "datapath" => FooterTabState::Datapath, + "hex_editor" => FooterTabState::HexEditor, + _ => FooterTabState::default(), + }; + + active_tab.set(new_tab); + }) + }; + + let toggle_zoom = { + let zoom_datapath = zoom_datapath.clone(); + + Callback::from(move |_| { + zoom_datapath.toggle(); + }) + }; + + let datapath_size = match *zoom_datapath { + true => DatapathSize::Big, + false => DatapathSize::Small, + }; + + let switch_datapath_type = { + let switch_datapath = switch_datapath.clone(); + + Callback::from(move |_| { + switch_datapath.toggle(); + }) + }; + + let svg_path = match *switch_datapath { + true => "static/datapath_full.svg", + false => "static/datapath_simple.svg", + }; + + let switch_datapath_button_label = match *switch_datapath { + true => "Switch to Simple Datapath", + false => "Switch to Full Datapath", + }; + + html! { + <> + // Console buttons + if **active_tab == FooterTabState::Console { +
+ +
+ } else if **active_tab == FooterTabState::Datapath { +
+ +
+ } else if **active_tab == FooterTabState::HexEditor { +
+ +
+ } +
+
+ if **active_tab == FooterTabState::Console { + + } else { + + } + + if **active_tab == FooterTabState::Datapath { + + } else { + + } + + if **active_tab == FooterTabState::HexEditor { + + } else { + + } +
+ + if **active_tab == FooterTabState::Datapath { +
+ + +
+ } +
+ + } +} diff --git a/src/ui/console/helper.rs b/src/ui/footer/helper.rs similarity index 100% rename from src/ui/console/helper.rs rename to src/ui/footer/helper.rs diff --git a/src/ui/footer/mod.rs b/src/ui/footer/mod.rs new file mode 100644 index 000000000..bff6cf38a --- /dev/null +++ b/src/ui/footer/mod.rs @@ -0,0 +1,2 @@ +pub mod component; +pub mod helper; diff --git a/src/ui/swim_editor/component.rs b/src/ui/swim_editor/component.rs index cd413f027..3d9e9d2ed 100644 --- a/src/ui/swim_editor/component.rs +++ b/src/ui/swim_editor/component.rs @@ -8,7 +8,7 @@ use yew_hooks::prelude::*; use yew::prelude::*; use wasm_bindgen::{JsCast, JsValue}; -use crate::{parser::parser_structs_and_enums::ProgramInfo, ui::{assembled_view::component::{DataSegment, TextSegment}, console::component::ConsoleTabState}}; +use crate::{parser::parser_structs_and_enums::ProgramInfo, ui::{assembled_view::component::{DataSegment, TextSegment}, footer::component::FooterTabState}}; #[derive(PartialEq, Properties)] pub struct SwimEditorProps { @@ -21,7 +21,7 @@ pub struct SwimEditorProps { pub memory_curr_instr: UseStateHandle, pub editor_curr_line: UseStateHandle, pub editor_active_tab: UseStateHandle, - pub console_active_tab: UseStateHandle + pub console_active_tab: UseStateHandle } #[derive(Default, PartialEq)] @@ -84,7 +84,6 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html { let mut lines_content = lines_content.borrow_mut(); let mut lines = Vec::new(); for i in 1..line_count { - log::debug!("line {}: {}", i, model.get_line_content(i as f64)); lines.push(model.get_line_content(i as f64)); } *lines_content = lines; diff --git a/static/styles/main.css b/static/styles/main.css index b3699f021..9a7794eb3 100644 --- a/static/styles/main.css +++ b/static/styles/main.css @@ -160,8 +160,8 @@ body { } } -/****** Console ******/ -.console { +/****** Footer ******/ +.console-wrapper { border: 3px groove #ccc; background: #012456; color: #ccc; @@ -176,6 +176,29 @@ body { max-height: 50%; } +.console-input { + display: flex; + align-items: center; + flex-direction: row; + color: white; + position: relative; +} + +.console-input input { + width: 100%; + background: #012456; + color: white !important; + margin-left: 25px; +} + +.console-arrow { + height: 15px; + width: 15px; + fill: white; + position: absolute; + left: 0px; +} + .hex-wrapper { border: 3px groove #ccc; background: #1E1E1E; From 019d12b1aaa5f9f375544dd2d082d49ae1eb859b Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Tue, 6 Feb 2024 20:39:46 -0500 Subject: [PATCH 036/355] Finish up basic commands implementation --- src/agent.rs | 21 ++++++++------------- src/emulation_core/datapath.rs | 25 +++---------------------- src/emulation_core/mips/datapath.rs | 6 ++++-- 3 files changed, 15 insertions(+), 37 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index a77b3c1c0..35c589d64 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -2,7 +2,7 @@ use crate::agent::messages::{Command, StateUpdate}; use crate::emulation_core::datapath::Datapath; -use crate::emulation_core::mips::datapath::{MipsDatapath, Stage}; +use crate::emulation_core::mips::datapath::MipsDatapath; use crate::emulation_core::mips::registers::GpRegisterType; use futures::{FutureExt, StreamExt}; use gloo_console::log; @@ -37,8 +37,7 @@ pub async fn emulation_core_agent(scope: ReactorScope) { } struct EmulatorCoreAgentState { - current_datapath: - Box>, + current_datapath: Box>, pub scope: ReactorScope, speed: u32, executing: bool, @@ -59,21 +58,17 @@ impl EmulatorCoreAgentState { Command::SetCore(_architecture) => { todo!() // Implement once we have a RISCV datapath } - Command::LoadInstructions(_mem) => { - // FIXME: Uncomment once refactoring is done on the trait - // self.current_datapath.load_instructions(mem); - todo!() + Command::LoadInstructions(mem) => { + self.current_datapath.load_instructions(&mem); } Command::SetExecuteSpeed(speed) => { self.speed = speed; } - Command::SetRegister(_register, _value) => { - todo!() + Command::SetRegister(register, value) => { + self.current_datapath.set_register_by_str(®ister, value); } - Command::SetMemory(_ptr, _data) => { - // FIXME: Uncomment once refectoring is done on the trait - // self.current_datapath.set_memory(ptr, &data); - todo!() + Command::SetMemory(ptr, data) => { + self.current_datapath.set_memory(ptr, &data); } Command::Execute => { self.executing = true; diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index 00081844a..b1a29d6e5 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -25,11 +25,6 @@ pub trait Datapath { /// at the discretion of the developer. type RegisterEnum; - /// This enum describes all possible stages in the datapath. This is - /// used primarily for the visual datapath view. Must be convertable - /// into a string for highlighting purposes. - type StageEnum: Into; - /// Execute a single instruction based on the current state of the /// datapath. Should the datapath support stages, if the datapath is /// midway through a stage, the current instruction will be finished @@ -48,10 +43,9 @@ pub trait Datapath { /// registers should be listed within [`Self::RegisterEnum`]. fn get_register_by_enum(&self, register: Self::RegisterEnum) -> Self::RegisterData; - /// Sets the data in the register indicated by the provided enum. - fn set_register_by_enum(&self, _register: Self::RegisterEnum, _data: Self::RegisterData) { - todo!() - } + /// Sets the data in the register indicated by the provided string. If it doesn't exist, + /// this function returns Err. + fn set_register_by_str(&mut self, register: &str, data: Self::RegisterData); /// Loads the instructions from the provided array into an emulation core's /// memory. This will also clear the memory of the emulation core and reset @@ -74,19 +68,6 @@ pub trait Datapath { /// Restore the datapath to its default state. fn reset(&mut self); - - // Information retrieval - - /// Get the program counter from an emulation core, regardless of what - /// it's called. - fn get_pc(&self) -> Self::RegisterData { - todo!() - } - - /// Gets the current stage the emulator core is in. - fn get_stage(&self) -> Self::StageEnum { - todo!() - } } /// A datapath that supports a visual diagram component. diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index e982d3c96..f2835a6c8 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -223,8 +223,6 @@ impl Datapath for MipsDatapath { type RegisterData = u64; type RegisterEnum = super::registers::GpRegisterType; - type StageEnum = Stage; - fn execute_instruction(&mut self) { loop { // Stop early if the datapath has halted. @@ -268,6 +266,10 @@ impl Datapath for MipsDatapath { self.registers[register] } + fn set_register_by_str(&mut self, _register: &str, _data: Self::RegisterData) { + todo!() + } + fn get_memory(&self) -> &Memory { &self.memory } From fc38ced725507408da005c4a0afa80f3e04c722d Mon Sep 17 00:00:00 2001 From: rharding8 Date: Wed, 7 Feb 2024 15:23:44 -0500 Subject: [PATCH 037/355] Updated some memory sections of the Datapath. Now moving onto branching and jumping handling. --- src/emulation_core.rs | 3 +- src/emulation_core/riscv.rs | 11 + src/emulation_core/riscv/control_signals.rs | 250 +------- src/emulation_core/riscv/coprocessor.rs | 619 -------------------- src/emulation_core/riscv/datapath.rs | 82 ++- src/emulation_core/riscv/line_info.rs | 4 +- src/emulation_core/riscv/memory.rs | 48 ++ 7 files changed, 100 insertions(+), 917 deletions(-) create mode 100644 src/emulation_core/riscv.rs delete mode 100644 src/emulation_core/riscv/coprocessor.rs diff --git a/src/emulation_core.rs b/src/emulation_core.rs index 6bc6a6d54..3eb1d02fe 100644 --- a/src/emulation_core.rs +++ b/src/emulation_core.rs @@ -1,4 +1,5 @@ //! The emulation core for the project. pub mod datapath; -pub mod mips; \ No newline at end of file +pub mod mips; +pub mod riscv; \ No newline at end of file diff --git a/src/emulation_core/riscv.rs b/src/emulation_core/riscv.rs new file mode 100644 index 000000000..7dcfbfd6c --- /dev/null +++ b/src/emulation_core/riscv.rs @@ -0,0 +1,11 @@ +//! All facets of this project's implementation of the MIPS64 ISA, including +//! the datapath, control signals, registers, and memory. + +pub mod constants; +pub mod control_signals; +pub mod datapath; +pub mod datapath_signals; +pub mod instruction; +pub mod line_info; +pub mod memory; +pub mod registers; diff --git a/src/emulation_core/riscv/control_signals.rs b/src/emulation_core/riscv/control_signals.rs index d5c4b151b..1c2dcd6f6 100644 --- a/src/emulation_core/riscv/control_signals.rs +++ b/src/emulation_core/riscv/control_signals.rs @@ -185,252 +185,4 @@ pub enum RegWriteEn { #[default] NoWrite = 0, YesWrite = 1, -} - -pub mod floating_point { - use super::super::constants::*; - - #[derive(Clone, Default, PartialEq)] - pub struct FpuControlSignals { - pub cc: Cc, - pub cc_write: CcWrite, - pub data_src: DataSrc, - pub data_write: DataWrite, - pub fpu_alu_op: FpuAluOp, - pub fpu_branch: FpuBranch, - pub fpu_mem_to_reg: FpuMemToReg, - pub fpu_reg_dst: FpuRegDst, - pub fpu_reg_width: FpuRegWidth, - pub fpu_reg_write: FpuRegWrite, - pub fpu_take_branch: FpuTakeBranch, - } - - /// Determines, given that [`CcWrite`] is set, which condition code register - /// should be written to or read from for a given operation. - /// - /// For the sake of this project, it will usually be assumed that this will - /// be 0, however the functionality is available to be extended. - #[derive(Clone, Default, PartialEq)] - pub enum Cc { - /// Use condition code register 0. Default in most operations. Can be - /// additionally used in the case where the condition code register is - /// irrelevant to the current instruction. - #[default] - Cc0 = 0, - } - - /// Determines if the condition code register file should be written to. - #[derive(Clone, Default, PartialEq)] - pub enum CcWrite { - #[default] - NoWrite = 0, - YesWrite = 1, - } - - /// Determines the source of the `Data` register in the floating-point unit. - /// - /// This is a special intermediary register that facilitates passing data between - /// the main processing unit and the floating-point unit. - #[derive(Clone, Default, PartialEq)] - pub enum DataSrc { - /// Use data from the main processing unit. Specifically, the data from register - /// `rt` from a given instruction. This value can additionally be used in the cases - /// where this register is not written to. - MainProcessorUnit = 0, - - /// Use data from the floating-point unit. Specifically, the data from register `fs` - /// from a given instruction. - #[default] - FloatingPointUnit = 1, - } - - /// Determines whether to write to the `Data` register in the floating-point unit. - /// - /// This acts as a toggle for the source of data to the main processing unit register - /// file. Additionally, it acts as a toggle for a source to the floating-point unit - /// register file (this could be overridden by the [`FpuMemToReg`] control signal). - /// For the latter two functions, it is imperative to unset the [`RegWrite`](super::RegWrite) and - /// [`FpuRegWrite`] control signals in cases where registers should not be modified - /// with unintended data. - #[derive(Clone, Default, PartialEq)] - pub enum DataWrite { - /// - Do not write to the data register. - /// - Source data to write to the main processing unit register file from the main - /// processing unit. This implies either the ALU result or the data read from memory - /// - Source data to write to the floating-point register file from the floating-point - /// ALU. - #[default] - NoWrite = 0, - - /// - Write to the data register. - /// - Source data to write to the main processing unit register file from the - /// floating-point unit. Specifically, this is the data stored in the `Data` register - /// in the FPU, likely from register `fs` from a given instruction. This data source - /// overrides the decision given by the [`MemToReg`](super::MemToReg) control signal. - /// - Source data to write to the floating-point register file from the `Data` register - /// in the FPU, likely from register `rt` from a given instruction. - YesWrite = 1, - } - - /// This doubly determines the operations sent to the floating-point ALU and the - /// floating-point comparator. - /// - /// Only one of these units are effectively utilized in any given instruction. - /// - /// The fifth bit of the control signal represents either a single-precision - /// floating-point operation (0), or a double-precision floating-point operation (1). - /// This fifth bit is determined by [`FpuRegWidth`]. - /// - /// *Implementation note:* The bits set for the comparator are intended to match - /// the bits used in the `cond` field of a `c.cond.fmt` instruction. - #[derive(Clone, Debug, Default, PartialEq)] - pub enum FpuAluOp { - #[default] - /// `_0000` (0): - /// - ALU: Perform an addition. - Addition = 0, - - /// `_0001` (1): - /// - ALU: Perform a subtraction. - Subtraction = 1, - - /// `_0010` (2): - /// - ALU: Perform a multiplication. - /// - Comparator: Set if equal. - MultiplicationOrEqual = 2, - - /// `_0011` (3): - /// - ALU: Perform a division. - Division = 3, - - /// `_0100` (4): - /// - ALU: Perform an "AND" operation. - And = 4, - - /// `_0101` (5): - /// - ALU: Perform an "OR" operation. - Or = 5, - - /// `_1100` (12): - /// - Comparator: Set if less than. - Slt = 12, - - /// `_1101` (13): - /// - Comparator: Set if not greater than or equal. - Snge = 13, - - /// `_1110` (14): - /// - Comparator: Set if less than or equal. - Sle = 14, - - /// `_1111` (15): - /// - Comparator: Set if not greater than. - Sngt = 15, - } - - impl FpuAluOp { - /// Get the corresponding control signal given a function code. - pub fn from_function(function: u8) -> Result { - match function { - FUNCTION_C_EQ => Ok(Self::MultiplicationOrEqual), - FUNCTION_C_LT => Ok(Self::Slt), - FUNCTION_C_NGE => Ok(Self::Snge), - FUNCTION_C_LE => Ok(Self::Sle), - FUNCTION_C_NGT => Ok(Self::Sngt), - _ => Err(format!("Unsupported function code `{function}`")), - } - } - } - - /// Determines if the floating-point unit should consider branching, based on the - /// contents of the condition code register. - /// - /// This directly overrides any branch decisions decided by the main processing unit. - /// The [`Branch`](super::Branch) control signal should not be set in addition to this signal. - #[derive(Clone, Default, PartialEq)] - pub enum FpuBranch { - /// Do not consider branching. - #[default] - NoBranch = 0, - - /// Consider branching. - YesBranch = 1, - } - - /// Determines, given that [`FpuRegWrite`] is set, what the source of a floating-point - /// register's new data will be. - /// - /// This decision, if set, overrides the decision from the [`DataWrite`] control signal. - #[derive(Clone, Default, PartialEq)] - pub enum FpuMemToReg { - /// Do not use data from memory. Use the result of the [`DataWrite`] control signal. - #[default] - UseDataWrite = 0, - - /// Use data from memory. - UseMemory = 1, - } - - /// Determines, given that [`FpuRegWrite`] is set, which destination register to write - /// to, which largely depends on the instruction format. - #[derive(Clone, Default, PartialEq)] - pub enum FpuRegDst { - /// Use register `ft`. - Reg1 = 0, - - /// Use register `fs`. - Reg2 = 1, - - /// Use register `fd`. - #[default] - Reg3 = 2, - } - - /// Determines the amount of data to be sent or received from registers and the ALU. - /// - /// While all buses carrying information are 64-bits wide, some bits of the bus may be - /// ignored in the case of this control signal. - #[derive(Clone, Default, PartialEq)] - pub enum FpuRegWidth { - /// Use words (32 bits). Equivalent to a single-precision floating-point value. - Word = 0, - - /// Use doublewords (64 bits). Equivalent to a double-precision floating-point value. - #[default] - DoubleWord = 1, - } - - impl FpuRegWidth { - /// Get the corresponding [`FpuRegWidth`] control signal based on - /// the `fmt` field in an instruction. - pub fn from_fmt(fmt: u8) -> Result { - match fmt { - FMT_SINGLE => Ok(Self::Word), - FMT_DOUBLE => Ok(Self::DoubleWord), - _ => Err(format!("`{fmt}` is an invalid fmt value")), - } - } - } - - /// Determines if the floating-point register file should be written to. - #[derive(Clone, Default, PartialEq)] - pub enum FpuRegWrite { - /// Do not write to the floating-point register file. - #[default] - NoWrite = 0, - - /// Write to the floating-point register file. - YesWrite = 1, - } - - /// After checking the [`FpuBranch`] and condition code, this signal determines whether - /// to follow through with a branch. - /// - /// This signal is what is sent to the main processor. - #[derive(Clone, Default, PartialEq)] - pub enum FpuTakeBranch { - #[default] - NoBranch = 0, - YesBranch = 1, - } -} +} \ No newline at end of file diff --git a/src/emulation_core/riscv/coprocessor.rs b/src/emulation_core/riscv/coprocessor.rs deleted file mode 100644 index c0c40fe85..000000000 --- a/src/emulation_core/riscv/coprocessor.rs +++ /dev/null @@ -1,619 +0,0 @@ -//! Implementation of a MIPS64 floating-point coprocessor. - -use super::constants::*; -use super::control_signals::floating_point::*; -use super::instruction::Instruction; - -/// An implementation of a floating-point coprocessor for the MIPS64 ISA. -/// -/// Different from the main processor, much of the functionality of the coprocessor -/// is controlled remotely using its available API calls. -#[derive(Clone, Default, PartialEq)] -pub struct MipsFpCoprocessor { - instruction: Instruction, - pub signals: FpuControlSignals, - pub state: FpuState, - pub is_halted: bool, - - pub fpr: [u64; 32], - pub condition_code: u64, - pub data: u64, -} - -#[derive(Clone, Default, PartialEq)] -pub struct FpuState { - pub instruction: u32, - pub op: u32, - pub fmt: u32, - pub fs: u32, - pub ft: u32, - pub fd: u32, - pub function: u32, - pub branch_flag: bool, - - /// The line that comes out of the condition code register file. Should contain - /// 1 for true or 0 for false. - pub condition_code_bit: u8, - /// The inversion of `condition_code_bit`. - pub condition_code_bit_inverted: u8, - /// The result of the multiplexer with `condition_code_bit` and `condition_code_bit_inverted`. - pub condition_code_mux: u8, - - pub data_from_main_processor: u64, - pub data_writeback: u64, - pub destination: usize, - pub fp_register_data_from_main_processor: u64, - pub read_data_1: u64, - pub read_data_2: u64, - pub register_write_data: u64, - pub register_write_mux_to_mux: u64, - pub sign_extend_data: u64, - - /// Data line that goes from `Read Data 2` to the multiplexer in the main processor - /// controlled by [`MemWriteSrc`](super::control_signals::MemWriteSrc). - /// This variable in a way in just a copy of read_data_2 - pub fp_register_to_memory: u64, - - pub alu_result: u64, - pub comparator_result: u64, -} - -impl MipsFpCoprocessor { - // ========================== Stages ========================== - pub fn stage_instruction_decode(&mut self) { - self.instruction_decode(); - self.set_control_signals(); - self.read_registers(); - } - - pub fn stage_execute(&mut self) { - self.alu(); - self.comparator(); - self.write_condition_code(); - self.write_fp_register_to_memory(); - self.set_condition_code_line(); - } - - pub fn stage_memory(&mut self) { - self.write_data(); - self.set_data_writeback(); - self.set_fpu_branch(); - } - - pub fn stage_writeback(&mut self) { - self.register_write(); - } - - // ===================== General Functions ===================== - /// Handle an otherwise irrecoverable error within the datapath. - pub fn error(&mut self, _message: &str) { - self.is_halted = true; - } - - // =================== API For Main Processor =================== - /// Set the internally-stored copy of the current instruction. This effectively - /// operates in lieu of any "instruction fetch" functionality since the coprocessor - /// does not fetch instructions. - pub fn set_instruction(&mut self, instruction_bits: u32) { - self.state.instruction = instruction_bits; - if let Ok(instruction) = Instruction::try_from(self.state.instruction) { - self.instruction = instruction; - } - } - - /// Sets the data line between the main processor and the `Data` register. This - /// is then used if deciding data from the main processor should go into the `Data` - /// register. - pub fn set_data_from_main_processor(&mut self, data: u64) { - self.state.data_from_main_processor = data; - } - - /// Gets the contents of the data line between the `Data` register and the multiplexer - /// in the main processor controlled by the [`DataWrite`] control signal. - pub fn get_data_writeback(&mut self) -> u64 { - self.state.data_writeback - } - - /// Sets the data line between the multiplexer controlled by [`MemToReg`](super::control_signals::MemToReg) - /// in the main processor and the multiplexer controlled by [`FpuMemToReg`] in the - /// floating-point coprocessor. - pub fn set_fp_register_data_from_main_processor(&mut self, data: u64) { - self.state.fp_register_data_from_main_processor = data; - } - - /// Gets the contents of the data line that goes from `Read Data 2` to the multiplexer - /// in the main processor controlled by [`MemWriteSrc`](super::control_signals::MemWriteSrc). - pub fn get_fp_register_to_memory(&mut self) -> u64 { - self.state.fp_register_to_memory - } - - // ================== Instruction Decode (ID) ================== - /// Decode an instruction into its individual fields. - fn instruction_decode(&mut self) { - // Set the data lines based on the contents of the instruction. - // Some lines will hold uninitialized values as a result. - match self.instruction { - Instruction::FpuRType(r) => { - self.state.op = r.op as u32; - self.state.fmt = r.fmt as u32; - self.state.fs = r.fs as u32; - self.state.ft = r.ft as u32; - self.state.fd = r.fd as u32; - self.state.function = r.function as u32; - } - Instruction::FpuIType(i) => { - self.state.ft = i.ft as u32; - } - Instruction::FpuRegImmType(i) => { - self.state.op = i.op as u32; - self.state.fmt = 0; // Not applicable - self.state.fs = i.fs as u32; - self.state.ft = 0; // Not applicable - self.state.fd = 0; // Not applicable - } - Instruction::FpuCompareType(c) => { - self.state.op = c.op as u32; - self.state.fmt = c.fmt as u32; - self.state.ft = c.ft as u32; - self.state.fs = c.fs as u32; - self.state.function = c.function as u32; - } - Instruction::FpuBranchType(b) => { - self.state.op = b.op as u32; - self.state.fmt = b.bcc1 as u32; - self.state.branch_flag = b.tf == 1; - } - // These types do not use the floating-point unit so they can be ignored. - Instruction::RType(_) - | Instruction::IType(_) - | Instruction::JType(_) - | Instruction::SyscallType(_) => (), - } - } - - /// Set the control signals of the processor based on the instruction opcode and function - /// control signals. - fn set_control_signals(&mut self) { - match self.instruction { - Instruction::FpuRType(r) => { - match r.op { - OPCODE_COP1 => match r.function { - FUNCTION_ADD => { - self.signals.cc = Cc::Cc0; - self.signals.cc_write = CcWrite::NoWrite; - self.signals.data_src = DataSrc::FloatingPointUnit; - self.signals.data_write = DataWrite::NoWrite; - self.signals.fpu_alu_op = FpuAluOp::Addition; - self.signals.fpu_branch = FpuBranch::NoBranch; - self.signals.fpu_mem_to_reg = FpuMemToReg::UseDataWrite; - self.signals.fpu_reg_dst = FpuRegDst::Reg3; - self.signals.fpu_reg_width = match FpuRegWidth::from_fmt(r.fmt) { - Ok(width) => width, - Err(message) => { - self.error(&message); - FpuRegWidth::default() - } - }; - self.signals.fpu_reg_write = FpuRegWrite::YesWrite; - } - FUNCTION_SUB => { - self.signals.cc = Cc::Cc0; - self.signals.cc_write = CcWrite::NoWrite; - self.signals.data_src = DataSrc::FloatingPointUnit; - self.signals.data_write = DataWrite::NoWrite; - self.signals.fpu_alu_op = FpuAluOp::Subtraction; - self.signals.fpu_branch = FpuBranch::NoBranch; - self.signals.fpu_mem_to_reg = FpuMemToReg::UseDataWrite; - self.signals.fpu_reg_dst = FpuRegDst::Reg3; - self.signals.fpu_reg_width = match FpuRegWidth::from_fmt(r.fmt) { - Ok(width) => width, - Err(message) => { - self.error(&message); - FpuRegWidth::default() - } - }; - self.signals.fpu_reg_write = FpuRegWrite::YesWrite; - } - FUNCTION_MUL => { - self.signals.cc = Cc::Cc0; - self.signals.cc_write = CcWrite::NoWrite; - self.signals.data_src = DataSrc::FloatingPointUnit; - self.signals.data_write = DataWrite::NoWrite; - self.signals.fpu_alu_op = FpuAluOp::MultiplicationOrEqual; - self.signals.fpu_branch = FpuBranch::NoBranch; - self.signals.fpu_mem_to_reg = FpuMemToReg::UseDataWrite; - self.signals.fpu_reg_dst = FpuRegDst::Reg3; - self.signals.fpu_reg_width = match FpuRegWidth::from_fmt(r.fmt) { - Ok(width) => width, - Err(message) => { - self.error(&message); - FpuRegWidth::default() - } - }; - self.signals.fpu_reg_write = FpuRegWrite::YesWrite; - } - FUNCTION_DIV => { - self.signals.cc = Cc::Cc0; - self.signals.cc_write = CcWrite::NoWrite; - self.signals.data_src = DataSrc::FloatingPointUnit; - self.signals.data_write = DataWrite::NoWrite; - self.signals.fpu_alu_op = FpuAluOp::Division; - self.signals.fpu_branch = FpuBranch::NoBranch; - self.signals.fpu_mem_to_reg = FpuMemToReg::UseDataWrite; - self.signals.fpu_reg_dst = FpuRegDst::Reg3; - self.signals.fpu_reg_width = match FpuRegWidth::from_fmt(r.fmt) { - Ok(width) => width, - Err(message) => { - self.error(&message); - FpuRegWidth::default() - } - }; - self.signals.fpu_reg_write = FpuRegWrite::YesWrite; - } - // Unrecognized format code. Perform no operation. - _ => self.error(&format!( - "COP1 instruction with function code `{}`", - r.function - )), - }, - // Unrecognized opcode. Perform no operation. - _ => self.error(&format!( - "Unsupported opcode `{}` for FPU R-type instruction", - r.op - )), - } - } - Instruction::FpuIType(i) => match i.op { - OPCODE_SWC1 => { - self.signals = FpuControlSignals { - cc_write: CcWrite::NoWrite, - data_write: DataWrite::NoWrite, - fpu_branch: FpuBranch::NoBranch, - fpu_reg_width: FpuRegWidth::Word, - fpu_reg_write: FpuRegWrite::NoWrite, - ..Default::default() - } - } - OPCODE_LWC1 => { - self.signals = FpuControlSignals { - cc_write: CcWrite::NoWrite, - data_write: DataWrite::NoWrite, - fpu_branch: FpuBranch::NoBranch, - fpu_mem_to_reg: FpuMemToReg::UseMemory, - fpu_reg_dst: FpuRegDst::Reg1, - fpu_reg_width: FpuRegWidth::Word, - fpu_reg_write: FpuRegWrite::YesWrite, - ..Default::default() - } - } - _ => self.error(&format!( - "Unsupported opcode `{}` for FPU I-type instruction", - i.op - )), - }, - Instruction::FpuRegImmType(i) => match i.sub { - SUB_MT => { - self.signals = FpuControlSignals { - cc_write: CcWrite::NoWrite, - data_src: DataSrc::MainProcessorUnit, - data_write: DataWrite::YesWrite, - fpu_branch: FpuBranch::NoBranch, - fpu_mem_to_reg: FpuMemToReg::UseDataWrite, - fpu_reg_dst: FpuRegDst::Reg2, - fpu_reg_width: FpuRegWidth::Word, - fpu_reg_write: FpuRegWrite::YesWrite, - ..Default::default() - } - } - SUB_DMT => { - self.signals = FpuControlSignals { - cc_write: CcWrite::NoWrite, - data_src: DataSrc::MainProcessorUnit, - data_write: DataWrite::YesWrite, - fpu_branch: FpuBranch::NoBranch, - fpu_mem_to_reg: FpuMemToReg::UseDataWrite, - fpu_reg_dst: FpuRegDst::Reg2, - fpu_reg_width: FpuRegWidth::DoubleWord, - fpu_reg_write: FpuRegWrite::YesWrite, - ..Default::default() - } - } - SUB_MF => { - self.signals = FpuControlSignals { - cc_write: CcWrite::NoWrite, - data_src: DataSrc::FloatingPointUnit, - data_write: DataWrite::YesWrite, - fpu_branch: FpuBranch::NoBranch, - fpu_reg_width: FpuRegWidth::Word, - fpu_reg_write: FpuRegWrite::NoWrite, - ..Default::default() - } - } - SUB_DMF => { - self.signals = FpuControlSignals { - cc_write: CcWrite::NoWrite, - data_src: DataSrc::FloatingPointUnit, - data_write: DataWrite::YesWrite, - fpu_branch: FpuBranch::NoBranch, - fpu_reg_width: FpuRegWidth::DoubleWord, - fpu_reg_write: FpuRegWrite::NoWrite, - ..Default::default() - } - } - _ => self.error(&format!( - "Unsupported sub code `{}` for FPU register-immediate instruction", - i.sub - )), - }, - Instruction::FpuCompareType(c) => { - self.signals = FpuControlSignals { - // All floating-point branch instructions are forced to use the same - // one condition code register, regardless of the CC field in the - // instruction. It should be noted that this differs from the - // real-world MIPS specification. - cc: Cc::Cc0, - cc_write: CcWrite::YesWrite, - data_write: DataWrite::NoWrite, - fpu_alu_op: match FpuAluOp::from_function(c.function) { - Ok(op) => op, - Err(message) => { - self.error(&message); - FpuAluOp::default() - } - }, - fpu_branch: FpuBranch::NoBranch, - fpu_reg_width: match FpuRegWidth::from_fmt(c.fmt) { - Ok(width) => width, - Err(message) => { - self.error(&message); - FpuRegWidth::default() - } - }, - fpu_reg_write: FpuRegWrite::NoWrite, - ..Default::default() - } - } - Instruction::FpuBranchType(_) => { - self.signals = FpuControlSignals { - // All floating-point branch instructions are forced to use the same - // one condition code register, regardless of the CC field in the - // instruction. It should be noted that this differs from the - // real-world MIPS specification. - cc: Cc::Cc0, - fpu_branch: FpuBranch::YesBranch, - ..Default::default() - } - } - // These types do not use the floating-point unit so they can be ignored. - Instruction::RType(_) - | Instruction::IType(_) - | Instruction::JType(_) - | Instruction::SyscallType(_) => self.signals = FpuControlSignals::default(), - } - } - - /// Read the registers as specified from the instruction and pass - /// the data into the datapath. - fn read_registers(&mut self) { - let reg1 = self.state.fs as usize; - let reg2 = self.state.ft as usize; - - self.state.read_data_1 = self.fpr[reg1]; - self.state.read_data_2 = self.fpr[reg2]; - - // Truncate the variable data if a 32-bit word is requested. - if let FpuRegWidth::Word = self.signals.fpu_reg_width { - self.state.read_data_1 = self.fpr[reg1] as u32 as u64; - self.state.read_data_2 = self.fpr[reg2] as u32 as u64; - } - } - - // ======================= Execute (EX) ======================= - /// Perform an ALU operation. - fn alu(&mut self) { - let input1 = self.state.read_data_1; - let input2 = self.state.read_data_2; - - let mut input1_f32 = 0f32; - let mut input2_f32 = 0f32; - let mut input1_f64 = 0f64; - let mut input2_f64 = 0f64; - - // Truncate the inputs if 32-bit operations are expected. - if let FpuRegWidth::Word = self.signals.fpu_reg_width { - input1_f32 = f32::from_bits(input1 as u32); - input2_f32 = f32::from_bits(input2 as u32); - } else { - input1_f64 = f64::from_bits(input1); - input2_f64 = f64::from_bits(input2); - } - - self.state.alu_result = match self.signals.fpu_alu_op { - FpuAluOp::Addition => match self.signals.fpu_reg_width { - FpuRegWidth::Word => f32::to_bits(input1_f32 + input2_f32) as u64, - FpuRegWidth::DoubleWord => f64::to_bits(input1_f64 + input2_f64), - }, - FpuAluOp::Subtraction => match self.signals.fpu_reg_width { - FpuRegWidth::Word => f32::to_bits(input1_f32 - input2_f32) as u64, - FpuRegWidth::DoubleWord => f64::to_bits(input1_f64 - input2_f64), - }, - FpuAluOp::MultiplicationOrEqual => match self.signals.fpu_reg_width { - FpuRegWidth::Word => f32::to_bits(input1_f32 * input2_f32) as u64, - FpuRegWidth::DoubleWord => f64::to_bits(input1_f64 * input2_f64), - }, - FpuAluOp::Division => match self.signals.fpu_reg_width { - FpuRegWidth::Word => { - if input2_f32 == 0f32 { - f32::to_bits(0f32) as u64 - } else { - f32::to_bits(input1_f32 / input2_f32) as u64 - } - } - FpuRegWidth::DoubleWord => { - if input2_f64 == 0.0 { - f64::to_bits(0.0) - } else { - f64::to_bits(input1_f64 / input2_f64) - } - } - }, - // No operation. - FpuAluOp::Slt | FpuAluOp::Snge | FpuAluOp::Sle | FpuAluOp::Sngt => 0, - _ => { - self.error(&format!( - "Unsupported operation in FPU `{:?}`", - self.signals.fpu_alu_op - )); - 0 - } - }; - } - - /// Perform a comparison. - fn comparator(&mut self) { - let input1 = self.state.read_data_1; - let input2 = self.state.read_data_2; - - let input1_f32 = f32::from_bits(input1 as u32); - let input2_f32 = f32::from_bits(input2 as u32); - let input1_f64 = f64::from_bits(input1); - let input2_f64 = f64::from_bits(input2); - - self.state.comparator_result = match self.signals.fpu_alu_op { - FpuAluOp::MultiplicationOrEqual => match self.signals.fpu_reg_width { - FpuRegWidth::Word => (input1_f32 == input2_f32) as u64, - FpuRegWidth::DoubleWord => (input1_f64 == input2_f64) as u64, - }, - FpuAluOp::Slt => match self.signals.fpu_reg_width { - FpuRegWidth::Word => (input1_f32 < input2_f32) as u64, - FpuRegWidth::DoubleWord => (input1_f64 < input2_f64) as u64, - }, - FpuAluOp::Sle => match self.signals.fpu_reg_width { - FpuRegWidth::Word => (input1_f32 <= input2_f32) as u64, - FpuRegWidth::DoubleWord => (input1_f64 <= input2_f64) as u64, - }, - FpuAluOp::Sngt => match self.signals.fpu_reg_width { - FpuRegWidth::Word => !input1_f32.gt(&input2_f32) as u64, - FpuRegWidth::DoubleWord => !input1_f64.gt(&input2_f64) as u64, - }, - FpuAluOp::Snge => match self.signals.fpu_reg_width { - FpuRegWidth::Word => !input1_f32.ge(&input2_f32) as u64, - FpuRegWidth::DoubleWord => !input1_f64.ge(&input2_f64) as u64, - }, - FpuAluOp::Addition | FpuAluOp::Subtraction | FpuAluOp::Division => 0, // No operation - _ => { - self.error(&format!( - "Unsupported operation in comparator `{:?}`", - self.signals.fpu_alu_op - )); - 0 - } - } - } - - /// Write to the `Data` register. This register is used to transfer data between - /// the main processor and the coprocessor. - fn write_data(&mut self) { - if let DataWrite::NoWrite = self.signals.data_write { - return; - } - - self.data = match self.signals.data_src { - DataSrc::FloatingPointUnit => self.state.read_data_1, - DataSrc::MainProcessorUnit => self.state.data_from_main_processor, - }; - } - - /// Set the condition code (CC) register based on the result from the comparator. - fn write_condition_code(&mut self) { - if let CcWrite::YesWrite = self.signals.cc_write { - self.condition_code = self.state.comparator_result; - } - } - - /// Set the data line that goes from `Read Data 2` to the multiplexer in the main processor - /// controlled by [`MemWriteSrc`](super::control_signals::MemWriteSrc). - fn write_fp_register_to_memory(&mut self) { - self.state.fp_register_to_memory = self.state.read_data_2; - } - - // ======================= Memory (MEM) ======================= - /// Set the data line that goes out of the condition code register file. - fn set_condition_code_line(&mut self) { - // The MIPS architecture supports more than one condition code, but SWIM - // manually uses only one. This stubs the possible use of more than one - // for future development. - let selected_register_data = match self.signals.cc { - Cc::Cc0 => self.condition_code, - }; - - // This only considers one bit of the selected condition code register. - self.state.condition_code_bit = match selected_register_data % 2 { - 0 => 0, - _ => 1, - }; - } - - /// Set the data line between the multiplexer after the `Data` register and the - /// multiplexer in the main processor controlled by the [`DataWrite`] control signal. - fn set_data_writeback(&mut self) { - self.state.sign_extend_data = self.data as i32 as i64 as u64; - self.state.data_writeback = match self.signals.fpu_reg_width { - FpuRegWidth::Word => self.state.sign_extend_data, - FpuRegWidth::DoubleWord => self.data, - } - } - - /// Simulate the logic between `self.state.condition_code_bit` and the FPU branch - /// AND gate. - fn set_fpu_branch(&mut self) { - // Invert the condition code. (In this case, instead of using a bitwise NOT, this - // will invert only the last digit and leave the rest as 0.) - self.state.condition_code_bit_inverted = match self.state.condition_code_bit % 2 { - 0 => 1, - _ => 0, - }; - - // Run the multiplexer. - self.state.condition_code_mux = match self.state.branch_flag { - // 0 - Use inverted condition code. - false => self.state.condition_code_bit_inverted, - // 1 - Use condition code value as-is. - true => self.state.condition_code_bit, - }; - - // Set the result of the AND gate. - self.signals.fpu_take_branch = if self.signals.fpu_branch == FpuBranch::YesBranch - && self.state.condition_code_mux == 1 - { - FpuTakeBranch::YesBranch - } else { - FpuTakeBranch::NoBranch - }; - } - - // ====================== Writeback (WB) ====================== - /// Write data to the floating-point register file. - fn register_write(&mut self) { - if let FpuRegWrite::NoWrite = self.signals.fpu_reg_write { - return; - } - - self.state.destination = match self.signals.fpu_reg_dst { - FpuRegDst::Reg1 => self.state.ft as usize, - FpuRegDst::Reg2 => self.state.fs as usize, - FpuRegDst::Reg3 => self.state.fd as usize, - }; - - self.state.register_write_mux_to_mux = match self.signals.data_write { - DataWrite::NoWrite => self.state.alu_result, - DataWrite::YesWrite => self.data, - }; - self.state.register_write_data = match self.signals.fpu_mem_to_reg { - FpuMemToReg::UseDataWrite => self.state.register_write_mux_to_mux, - FpuMemToReg::UseMemory => self.state.fp_register_data_from_main_processor, - }; - - self.fpr[self.state.destination] = self.state.register_write_data; - } -} diff --git a/src/emulation_core/riscv/datapath.rs b/src/emulation_core/riscv/datapath.rs index 068ebdeb5..2bd6d21d4 100644 --- a/src/emulation_core/riscv/datapath.rs +++ b/src/emulation_core/riscv/datapath.rs @@ -46,19 +46,20 @@ //! setting the boolean flag `is_halted`. //! - Invalid instructions will cause the datapath to set the `is_halted` flag. +use crate::tests::emulation_core::mips::add; + use super::super::datapath::Datapath; use super::constants::*; -use super::control_signals::{floating_point::*, *}; +use super::control_signals::*; use super::datapath_signals::*; use super::instruction::*; -use super::{coprocessor::MipsFpCoprocessor, memory::Memory, registers::GpRegisters}; +use super::{memory::Memory, registers::GpRegisters}; /// An implementation of a datapath for the MIPS64 ISA. #[derive(Clone, PartialEq)] pub struct RiscDatapath { pub registers: GpRegisters, pub memory: Memory, - pub coprocessor: MipsFpCoprocessor, pub instruction: Instruction, pub signals: ControlSignals, @@ -193,7 +194,6 @@ impl Default for RiscDatapath { let mut datapath = RiscDatapath { registers: GpRegisters::default(), memory: Memory::default(), - coprocessor: MipsFpCoprocessor::default(), instruction: Instruction::default(), signals: ControlSignals::default(), datapath_signals: DatapathSignals::default(), @@ -246,10 +246,6 @@ impl Datapath for RiscDatapath { Stage::WriteBack => self.stage_writeback(), } - // If the FPU has halted, reflect this in the main unit. - if self.coprocessor.is_halted { - self.is_halted = true; - } self.current_stage = Stage::get_next_stage(self.current_stage); } @@ -308,8 +304,6 @@ impl RiscDatapath { // Upper part of datapath, PC calculation self.pc_plus_4(); - - self.coprocessor.set_instruction(self.state.instruction); } /// Stage 2 of 5: Instruction Decode (ID) @@ -327,10 +321,6 @@ impl RiscDatapath { // Upper part of datapath, PC calculation self.construct_jump_address(); - self.coprocessor.stage_instruction_decode(); - self.coprocessor - .set_data_from_main_processor(self.state.read_data_2); - /* Finish this instruction out of the datapath and halt if this is a syscall. if let Instruction::SyscallType(_) = self.instruction { self.is_halted = true; @@ -344,31 +334,33 @@ impl RiscDatapath { self.alu(); self.calc_relative_pc_branch(); self.calc_cpu_branch_signal(); - self.coprocessor.stage_execute(); } /// Stage 4 of 5: Memory (MEM) /// /// Read or write to memory. fn stage_memory(&mut self) { - if let MemRead::YesRead = self.signals.mem_read { - self.memory_read(); - } - - if let MemWrite::YesWrite = self.signals.mem_write { - self.memory_write(); + match self.signals.read_write { + ReadWrite::LoadByte => self.memory_read(), + ReadWrite::LoadByteUnsigned => self.memory_read(), + ReadWrite::LoadHalf => self.memory_read(), + ReadWrite::LoadHalfUnsigned => self.memory_read(), + ReadWrite::LoadWord => self.memory_read(), + ReadWrite::NoLoadStore => (), + ReadWrite::StoreByte => self.memory_write(), + ReadWrite::StoreHalf => self.memory_write(), + ReadWrite::StoreWord => self.memory_write(), } // Determine what data will be sent to the registers: either // the result from the ALU, or data retrieved from memory. - self.state.data_result = match self.signals.mem_to_reg { - MemToReg::UseAlu => self.state.alu_result, - MemToReg::UseMemory => self.state.memory_data, - MemToReg::UsePcPlusFour => self.state.pc_plus_4, + self.state.data_result = match self.signals.wb_sel { + WBSel::UseAlu => self.state.alu_result, + WBSel::UseMemory => self.state.memory_data, + WBSel::UsePcPlusFour => self.state.pc_plus_4, + WBSel::UseImmediate => self.state.imm as u64, }; - self.coprocessor.stage_memory(); - // PC calculation stuff from upper part of datapath self.calc_general_branch_signal(); self.pick_pc_plus_4_or_relative_branch_addr_mux1(); @@ -380,11 +372,8 @@ impl RiscDatapath { /// Write the result of the instruction's operation to a register, /// if desired. Additionally, set the PC for the next instruction. fn stage_writeback(&mut self) { - self.coprocessor - .set_fp_register_data_from_main_processor(self.state.data_result); self.register_write(); self.set_pc(); - self.coprocessor.stage_writeback(); } // ================== Instruction Fetch (IF) ================== @@ -790,9 +779,13 @@ impl RiscDatapath { // Load memory, first choosing the correct load function by the // RegWidth control signal, then reading the result from this // memory access. - self.state.memory_data = match self.signals.reg_width { - RegWidth::Word => self.memory.load_word(address).unwrap_or(0) as u64, - RegWidth::DoubleWord => self.memory.load_double_word(address).unwrap_or(0), + self.state.memory_data = match self.signals.read_write { + ReadWrite::LoadByte => self.memory.load_byte(address).unwrap_or(0) as i64 as u64, + ReadWrite::LoadByteUnsigned => self.memory.load_byte(address).unwrap_or(0) as u64, + ReadWrite::LoadHalf => self.memory.load_half(address).unwrap_or(0) as i64 as u64, + ReadWrite::LoadHalfUnsigned => self.memory.load_half(address).unwrap_or(0) as u64, + ReadWrite::LoadWord => self.memory.load_word(address).unwrap_or(0) as u64, + _ => 0, }; } @@ -806,17 +799,17 @@ impl RiscDatapath { // Choose the correct store function based on the RegWidth // control signal. - match self.signals.reg_width { - RegWidth::Word => { - self.memory - .store_word(address, self.state.write_data as u32) - .ok(); + match self.signals.read_write { + ReadWrite::StoreByte => { + self.memory.store_byte(address, self.state.write_data as u8).ok(); } - RegWidth::DoubleWord => { - self.memory - .store_double_word(address, self.state.write_data) - .ok(); + ReadWrite::StoreHalf => { + self.memory.store_half(address, self.state.write_data as u16).ok(); } + ReadWrite::StoreWord => { + self.memory.store_word(address, self.state.write_data as u32).ok(); + } + _ => (), }; } @@ -828,10 +821,6 @@ impl RiscDatapath { self.datapath_signals.general_branch = GeneralBranch::YesBranch; return; } - - if let FpuTakeBranch::YesBranch = self.coprocessor.signals.fpu_take_branch { - self.datapath_signals.general_branch = GeneralBranch::YesBranch; - } } fn pick_pc_plus_4_or_relative_branch_addr_mux1(&mut self) { @@ -860,6 +849,7 @@ impl RiscDatapath { WBSel::UseAlu => self.state.alu_result, WBSel::UseMemory => self.state.memory_data, WBSel::UsePcPlusFour => self.state.pc_plus_4, + WBSel::UseImmediate => self.state.imm as u64, }; // Decide to retrieve data either from the main processor or the coprocessor. diff --git a/src/emulation_core/riscv/line_info.rs b/src/emulation_core/riscv/line_info.rs index c28c0a8aa..d17a5e319 100644 --- a/src/emulation_core/riscv/line_info.rs +++ b/src/emulation_core/riscv/line_info.rs @@ -2,7 +2,7 @@ //! and variables in the coded datapath. use super::super::datapath::VisualDatapath; -use super::datapath::MipsDatapath; +use super::datapath::RiscDatapath; /// A collection of data surrounding a line in the visual datapath. pub struct LineInformation { @@ -18,7 +18,7 @@ pub struct LineInformation { pub bits: u64, } -impl VisualDatapath for MipsDatapath { +impl VisualDatapath for RiscDatapath { type LineInformation = LineInformation; fn visual_line_to_data(&self, variable: &str) -> LineInformation { diff --git a/src/emulation_core/riscv/memory.rs b/src/emulation_core/riscv/memory.rs index 2abcf1921..14ac34618 100644 --- a/src/emulation_core/riscv/memory.rs +++ b/src/emulation_core/riscv/memory.rs @@ -46,6 +46,29 @@ impl Memory { } } + // A byte is 8 bits. + pub fn store_byte(&mut self, address: u64, data: u8) -> Result<(), String> { + let address = address as usize; + + self.check_valid_address(address)?; + + self.memory[address] = (data & 0b11111111) as u8; + + Ok(()) + } + + // A word is 32 bits. + pub fn store_half(&mut self, address: u64, data: u16) -> Result<(), String> { + let address = address as usize; + + self.check_valid_address(address)?; + + self.memory[address] = ((data >> 8) & 0b11111111) as u8; + self.memory[address + 1] = (data & 0b11111111) as u8; + + Ok(()) + } + // A word is 32 bits. pub fn store_word(&mut self, address: u64, data: u32) -> Result<(), String> { let address = address as usize; @@ -71,6 +94,31 @@ impl Memory { Ok(()) } + // A byte is 8 bits. + pub fn load_byte(&self, address: u64) -> Result { + let address = address as usize; + + self.check_valid_address(address)?; + + let mut result: u8 = 0; + result |= self.memory[address]; + + Ok(result) + } + + // A half-word is 16 bits. + pub fn load_half(&self, address: u64) -> Result { + let address = address as usize; + + self.check_valid_address(address)?; + + let mut result: u16 = 0; + result |= (self.memory[address] as u16) << 8; + result |= self.memory[address + 1] as u16; + + Ok(result) + } + // A word is 32 bits. pub fn load_word(&self, address: u64) -> Result { let address = address as usize; From fa0d1a78412a47969ad0de7a61faa56ce71cf614 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Wed, 7 Feb 2024 16:41:14 -0500 Subject: [PATCH 038/355] Implement naive state updates for MIPS --- src/agent.rs | 29 +++++++++++++--- src/agent/datapath_communicator.rs | 51 ++++++---------------------- src/agent/messages.rs | 14 ++++---- src/emulation_core/architectures.rs | 11 ++++++ src/emulation_core/datapath.rs | 3 ++ src/emulation_core/mips/datapath.rs | 8 ++++- src/emulation_core/mips/memory.rs | 4 ++- src/emulation_core/mips/registers.rs | 3 +- 8 files changed, 67 insertions(+), 56 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index 35c589d64..dde11710c 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -1,10 +1,11 @@ //! The agent responsible for running the emulator core on the worker thread and communication functionalities. -use crate::agent::messages::{Command, StateUpdate}; +use crate::agent::messages::{Command, MipsStateUpdate}; +use crate::emulation_core::architectures::{DatapathRef, DatapathUpdate}; use crate::emulation_core::datapath::Datapath; use crate::emulation_core::mips::datapath::MipsDatapath; use crate::emulation_core::mips::registers::GpRegisterType; -use futures::{FutureExt, StreamExt}; +use futures::{FutureExt, SinkExt, StreamExt}; use gloo_console::log; use std::time::Duration; use yew::platform::time::sleep; @@ -16,11 +17,12 @@ pub mod messages; /// The main logic for the emulation core agent. All code within this function runs on a worker thread as opposed to /// the UI thread. #[reactor(EmulationCoreAgent)] -pub async fn emulation_core_agent(scope: ReactorScope) { +pub async fn emulation_core_agent(scope: ReactorScope) { log!("Hello world!"); let mut state = EmulatorCoreAgentState::new(scope); loop { let execution_delay = state.get_delay(); + // Part 1: Delay/Command Handling futures::select! { // If we get a message, handle the command before attempting to execute. msg = state.scope.next() => match msg { @@ -31,20 +33,37 @@ pub async fn emulation_core_agent(scope: ReactorScope) { _ = sleep(Duration::from_millis(execution_delay)).fuse() => {}, } + // Part 2: Execution // Execute a single instruction if the emulator core should be executing. state.execute(); + + // Part 3: Processing State/Sending Updates to UI + // TODO: This is a very naive implementation. Optimization is probably a good idea. + match state.current_datapath.as_datapath_ref() { + DatapathRef::MIPS(datapath) => { + let state_update = + DatapathUpdate::MIPS(MipsStateUpdate::UpdateState(datapath.state.clone())); + let register_update = + DatapathUpdate::MIPS(MipsStateUpdate::UpdateRegisters(datapath.registers)); + let memory_update = + DatapathUpdate::MIPS(MipsStateUpdate::UpdateMemory(datapath.memory.clone())); + state.scope.send(state_update).await.unwrap(); + state.scope.send(register_update).await.unwrap(); + state.scope.send(memory_update).await.unwrap(); + } + } } } struct EmulatorCoreAgentState { current_datapath: Box>, - pub scope: ReactorScope, + pub scope: ReactorScope, speed: u32, executing: bool, } impl EmulatorCoreAgentState { - pub fn new(scope: ReactorScope) -> EmulatorCoreAgentState { + pub fn new(scope: ReactorScope) -> EmulatorCoreAgentState { EmulatorCoreAgentState { current_datapath: Box::::default(), scope, diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index 693dc33d8..c6936a9bd 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -1,7 +1,6 @@ use crate::agent::messages::Command; use crate::agent::EmulationCoreAgent; use crate::emulation_core::architectures::AvailableDatapaths; -use crate::emulation_core::datapath::VisualDatapath; use futures::stream::{SplitSink, SplitStream}; use futures::FutureExt; use futures::SinkExt; @@ -9,7 +8,6 @@ use futures::StreamExt; use gloo_console::log; use gloo_console::warn; use std::cell::RefCell; -use std::collections::HashMap; use yew::UseForceUpdateHandle; use yew_agent::reactor::ReactorBridge; @@ -90,19 +88,19 @@ impl DatapathCommunicator { } /// Loads the parsed/assembled instructions provided into the current emulator core. - pub fn load_instructions(&self, _instructions: &[u8]) { - todo!() + pub fn load_instructions(&self, instructions: Vec) { + self.send_message(Command::LoadInstructions(instructions)); } /// Sets the execution speed of the emulator core to the provided speed in hz. If set to zero, the emulator core /// will execute as fast as possible. - pub fn set_execute_speed(&self, _speed: u32) { - todo!() + pub fn set_execute_speed(&self, speed: u32) { + self.send_message(Command::SetExecuteSpeed(speed)); } /// Sets the register with the provided name to the provided value. - pub fn set_register(&self, _register: &str, _data: &str) { - todo!() + pub fn set_register(&self, register: String, data: u64) { + self.send_message(Command::SetRegister(register, data)); } /// Copies the contents of `data` to the emulator core's memory at `ptr`. Copies until either the end of `data` or @@ -118,45 +116,16 @@ impl DatapathCommunicator { /// Executes a single instruction on the emulator core and pauses. pub fn execute_instruction(&self) { - todo!() + self.send_message(Command::ExecuteInstruction); } /// Executes a single stage on the emulator core and pauses. pub fn execute_stage(&self) { - todo!() + self.send_message(Command::ExecuteStage); } /// Pauses the core. Does nothing if the emulator core is already paused. - pub fn pause_core(&self) {} - - // Getters for internal state - - /// Returns a list of all the registers on the current emulator core. - pub fn get_registers(&self) -> HashMap { - todo!() - } - - /// Returns the emulator core's memory as an array of bytes. - pub fn get_memory(&self) -> Vec { - todo!() - } - - /// Gets the current stage of the emulator core as a string. - pub fn get_current_stage(&self) -> String { - todo!() - } - - /// Gets the currently executing instruction on the emulator core. This is generally based on the value of the - /// program counter. - pub fn get_current_instruction(&self) -> usize { - todo!() - } - - /// Returns the appropriate visual datapath for the current architecture. Returns a boxed generic VisualDatapath. - pub fn get_visual_datapath( - &self, - _architecture: AvailableDatapaths, - ) -> Box { - todo!() + pub fn pause_core(&self) { + self.send_message(Command::Pause); } } diff --git a/src/agent/messages.rs b/src/agent/messages.rs index 059bc0532..62d59d9d9 100644 --- a/src/agent/messages.rs +++ b/src/agent/messages.rs @@ -1,4 +1,7 @@ use crate::emulation_core::architectures::AvailableDatapaths; +use crate::emulation_core::mips::datapath::DatapathState; +use crate::emulation_core::mips::memory::Memory; +use crate::emulation_core::mips::registers::GpRegisters; use serde::{Deserialize, Serialize}; /// Commands sent from the UI thread to the worker thread. @@ -17,11 +20,8 @@ pub enum Command { /// Information about the emulator core's state sent from the worker thread to the UI thread. #[derive(Clone, Debug, Serialize, Deserialize)] -pub enum StateUpdate { - UpdateRegister(u64), - UpdateMemory(usize, Vec), - SetCurrentStage(String), - SetCurrentInstruction(usize), - AddMemorySegment, - RemoveMemorySegment, +pub enum MipsStateUpdate { + UpdateState(DatapathState), + UpdateRegisters(GpRegisters), + UpdateMemory(Memory), } diff --git a/src/emulation_core/architectures.rs b/src/emulation_core/architectures.rs index bc29426d1..20cf13478 100644 --- a/src/emulation_core/architectures.rs +++ b/src/emulation_core/architectures.rs @@ -1,3 +1,5 @@ +use crate::agent::messages::MipsStateUpdate; +use crate::emulation_core::mips::datapath::MipsDatapath; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Serialize, Deserialize)] @@ -5,3 +7,12 @@ pub enum AvailableDatapaths { MIPS, RISCV, } + +pub enum DatapathRef<'a> { + MIPS(&'a MipsDatapath), +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum DatapathUpdate { + MIPS(MipsStateUpdate), +} diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index b1a29d6e5..156bf1262 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -1,5 +1,6 @@ //! Module for the API of a generic datapath. +use crate::emulation_core::architectures::DatapathRef; use crate::emulation_core::mips::line_info::LineInformation; use crate::emulation_core::mips::memory::Memory; @@ -68,6 +69,8 @@ pub trait Datapath { /// Restore the datapath to its default state. fn reset(&mut self); + + fn as_datapath_ref(&self) -> DatapathRef; } /// A datapath that supports a visual diagram component. diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index f2835a6c8..4bb23c693 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -52,6 +52,8 @@ use super::control_signals::{floating_point::*, *}; use super::datapath_signals::*; use super::instruction::*; use super::{coprocessor::MipsFpCoprocessor, memory::Memory, registers::GpRegisters}; +use crate::emulation_core::architectures::DatapathRef; +use serde::{Deserialize, Serialize}; /// An implementation of a datapath for the MIPS64 ISA. #[derive(Clone, PartialEq)] @@ -76,7 +78,7 @@ pub struct MipsDatapath { } /// A collection of all the data lines and wires in the datapath. -#[derive(Clone, Default, PartialEq)] +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] pub struct DatapathState { /// *Data line.* The currently loaded instruction. Initialized after the /// Instruction Fetch stage. @@ -281,6 +283,10 @@ impl Datapath for MipsDatapath { fn reset(&mut self) { std::mem::take(self); } + + fn as_datapath_ref(&self) -> DatapathRef { + DatapathRef::MIPS(self) + } } impl MipsDatapath { diff --git a/src/emulation_core/mips/memory.rs b/src/emulation_core/mips/memory.rs index 2abcf1921..6dae642cf 100644 --- a/src/emulation_core/mips/memory.rs +++ b/src/emulation_core/mips/memory.rs @@ -1,9 +1,11 @@ //! Data and instruction memory implementation and API. +use serde::{Deserialize, Serialize}; + // pub const CAPACITY_BYTES: usize = 2^12; // 4KB pub const CAPACITY_BYTES: usize = 64 * 1024; // 64 KB -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Memory { pub memory: Vec, } diff --git a/src/emulation_core/mips/registers.rs b/src/emulation_core/mips/registers.rs index efd218a83..a4171e87f 100644 --- a/src/emulation_core/mips/registers.rs +++ b/src/emulation_core/mips/registers.rs @@ -1,12 +1,13 @@ //! Register structure and API. +use serde::{Deserialize, Serialize}; use std::ops::{Index, IndexMut}; use std::str::FromStr; use strum::IntoEnumIterator; use strum_macros::{Display, EnumIter, EnumString}; /// Collection of general-purpose registers used by the datapath. -#[derive(Clone, Copy, Debug, Default, PartialEq)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)] pub struct GpRegisters { pub pc: u64, pub gpr: [u64; 32], From 4b391f87c88e0dd7bbb5836646ff7e175cc3097d Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 8 Feb 2024 20:13:02 -0500 Subject: [PATCH 039/355] Rename LoadInstructions to Initialize and get MIPS to start using it --- src/agent.rs | 24 ++++++++++++++++-------- src/agent/datapath_communicator.rs | 6 +++--- src/agent/messages.rs | 2 +- src/bin/main.rs | 2 +- src/emulation_core/datapath.rs | 10 +++------- src/emulation_core/mips/datapath.rs | 15 +++++++++++---- src/lib.rs | 1 + src/shims.rs | 19 +++++++++++++++++++ 8 files changed, 55 insertions(+), 24 deletions(-) create mode 100644 src/shims.rs diff --git a/src/agent.rs b/src/agent.rs index dde11710c..497a0b2fb 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -22,15 +22,23 @@ pub async fn emulation_core_agent(scope: ReactorScope) let mut state = EmulatorCoreAgentState::new(scope); loop { let execution_delay = state.get_delay(); + // Part 1: Delay/Command Handling - futures::select! { - // If we get a message, handle the command before attempting to execute. - msg = state.scope.next() => match msg { + if state.executing { + futures::select! { + // If we get a message, handle the command before attempting to execute. + msg = state.scope.next() => match msg { + Some(msg) => state.handle_command(msg), + None => return, + }, + // Delay to slow execution down to the intended speed. + _ = sleep(Duration::from_millis(execution_delay)).fuse() => {}, + } + } else { + match state.scope.next().await { Some(msg) => state.handle_command(msg), None => return, - }, - // Delay to slow execution down to the intended speed. - _ = sleep(Duration::from_millis(execution_delay)).fuse() => {}, + } } // Part 2: Execution @@ -77,8 +85,8 @@ impl EmulatorCoreAgentState { Command::SetCore(_architecture) => { todo!() // Implement once we have a RISCV datapath } - Command::LoadInstructions(mem) => { - self.current_datapath.load_instructions(&mem); + Command::Initialize(mem) => { + self.current_datapath.initialize(mem).unwrap(); } Command::SetExecuteSpeed(speed) => { self.speed = speed; diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index c6936a9bd..18c5d772e 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -87,9 +87,9 @@ impl DatapathCommunicator { todo!() } - /// Loads the parsed/assembled instructions provided into the current emulator core. - pub fn load_instructions(&self, instructions: Vec) { - self.send_message(Command::LoadInstructions(instructions)); + /// Resets and loads the parsed/assembled instructions provided into the current emulator core. + pub fn initialize(&self, instructions: Vec) { + self.send_message(Command::Initialize(instructions)); } /// Sets the execution speed of the emulator core to the provided speed in hz. If set to zero, the emulator core diff --git a/src/agent/messages.rs b/src/agent/messages.rs index 62d59d9d9..63a24a1cf 100644 --- a/src/agent/messages.rs +++ b/src/agent/messages.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Serialize, Deserialize)] pub enum Command { SetCore(AvailableDatapaths), - LoadInstructions(Vec), + Initialize(Vec), SetExecuteSpeed(u32), SetRegister(String, u64), SetMemory(usize, Vec), diff --git a/src/bin/main.rs b/src/bin/main.rs index 487c0254b..ddcb01140 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -158,7 +158,7 @@ fn app(props: &AppProps) -> Html { // Proceed with loading into memory and expand pseudo-instructions if there are no errors. if marker_jsarray.length() == 0 { // Load the binary into the datapath's memory - match datapath.initialize(assembled) { + match datapath.initialize_legacy(assembled) { Ok(_) => (), Err(msg) => { // In the case of an error, note this and stop early. diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index 156bf1262..47ceb3217 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -48,13 +48,9 @@ pub trait Datapath { /// this function returns Err. fn set_register_by_str(&mut self, register: &str, data: Self::RegisterData); - /// Loads the instructions from the provided array into an emulation core's - /// memory. This will also clear the memory of the emulation core and reset - /// the core's program counter. - fn load_instructions(&mut self, instructions: &[u8]) { - self.reset(); - self.set_memory(0, instructions); - } + /// Reset the datapath, load instructions into memory, and un-sets the `is_halted` + /// flag. If the process fails, an [`Err`] is returned. + fn initialize(&mut self, instructions: Vec) -> Result<(), String>; /// Retrieve all memory as-is. fn get_memory(&self) -> &Memory; diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index 4bb23c693..fbddacd88 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -41,7 +41,7 @@ //! # Notes on `is_halted` //! //! - The datapath starts with the `is_halted` flag set. -//! - [`MipsDatapath::initialize()`] should be used to un-set `is_halted`. +//! - [`MipsDatapath::initialize_legacy()`] should be used to un-set `is_halted`. //! - The `syscall` instruction simply performs a no-operation instruction, except for //! setting the boolean flag `is_halted`. //! - Invalid instructions will cause the datapath to set the `is_halted` flag. @@ -53,6 +53,7 @@ use super::datapath_signals::*; use super::instruction::*; use super::{coprocessor::MipsFpCoprocessor, memory::Memory, registers::GpRegisters}; use crate::emulation_core::architectures::DatapathRef; +use crate::shims; use serde::{Deserialize, Serialize}; /// An implementation of a datapath for the MIPS64 ISA. @@ -272,6 +273,14 @@ impl Datapath for MipsDatapath { todo!() } + fn initialize(&mut self, instructions: Vec) -> Result<(), String> { + self.reset(); + self.load_instructions(shims::convert_from_u8_bytes(instructions))?; + self.is_halted = false; + + Ok(()) + } + fn get_memory(&self) -> &Memory { &self.memory } @@ -291,9 +300,7 @@ impl Datapath for MipsDatapath { impl MipsDatapath { // ===================== General Functions ===================== - /// Reset the datapath, load instructions into memory, and un-sets the `is_halted` - /// flag. If the process fails, an [`Err`] is returned. - pub fn initialize(&mut self, instructions: Vec) -> Result<(), String> { + pub fn initialize_legacy(&mut self, instructions: Vec) -> Result<(), String> { self.reset(); self.load_instructions(instructions)?; self.is_halted = false; diff --git a/src/lib.rs b/src/lib.rs index 825d617f2..2ba0135bb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ pub mod agent; pub mod emulation_core; pub mod parser; +pub mod shims; #[cfg(test)] pub mod tests; pub mod ui; diff --git a/src/shims.rs b/src/shims.rs new file mode 100644 index 000000000..625c13684 --- /dev/null +++ b/src/shims.rs @@ -0,0 +1,19 @@ +//! Temporary shims to get things working for demos. These should NOT be used in the final version. + +pub fn convert_to_u8_bytes(input: Vec) -> Vec { + let mut res = Vec::new(); + for int in input { + for byte in int.to_le_bytes() { + res.push(byte); + } + } + res +} + +pub fn convert_from_u8_bytes(input: Vec) -> Vec { + let mut res = Vec::new(); + for int_bytes in input.chunks(4) { + res.push(u32::from_le_bytes(int_bytes.try_into().unwrap())); + } + res +} From bb8c3174f585b71d7fa5f3e70162d5f9cc3f51ff Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 8 Feb 2024 20:13:30 -0500 Subject: [PATCH 040/355] Fix tests --- src/tests/emulation_core/mips.rs | 284 +++++++++--------- .../integration/core_parser/arithmetic.rs | 8 +- .../core_parser/basic_immediate.rs | 20 +- .../core_parser/basic_operations.rs | 12 +- .../integration/core_parser/branch_jump.rs | 14 +- .../integration/core_parser/conditions.rs | 4 +- .../core_parser/coprocessor_move.rs | 12 +- .../core_parser/double_arithmetic.rs | 4 +- .../core_parser/double_immediate.rs | 10 +- .../integration/core_parser/fibonacci.rs | 2 +- .../core_parser/floating_point_arithmetic.rs | 4 +- .../core_parser/floating_point_branch.rs | 4 +- .../core_parser/floating_point_comparison.rs | 4 +- src/tests/integration/core_parser/mod.rs | 6 +- .../core_parser/store_load_word.rs | 10 +- 15 files changed, 199 insertions(+), 199 deletions(-) diff --git a/src/tests/emulation_core/mips.rs b/src/tests/emulation_core/mips.rs index f04ad427d..9483e3260 100644 --- a/src/tests/emulation_core/mips.rs +++ b/src/tests/emulation_core/mips.rs @@ -15,7 +15,7 @@ pub mod api { // Add instruction into emulation core memory. let instruction = String::from("ori $s0, $zero, 5"); let (_, instruction_bits) = parser(instruction); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.execute_instruction(); @@ -44,7 +44,7 @@ pub mod add { // $t1 = $t1 + $t1 // R-type t1 t1 t1 (shamt) ADD let instructions: Vec = vec![0b000000_01001_01001_01001_00000_100000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume the register $t1 has the value 5. datapath.registers[GpRegisterType::T1] = 5; @@ -63,7 +63,7 @@ pub mod add { // $s2 = $s0 + $s1 // R-type s0 s1 s2 (shamt) ADD let instructions: Vec = vec![0b000000_10000_10001_10010_00000_100000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 15; // $s0 datapath.registers.gpr[17] = 40; // $s1 @@ -85,7 +85,7 @@ pub mod add { // $zero = $t3 + $t3 // R-type t3 t3 zero (shamt) ADD let instructions: Vec = vec![0b000000_01011_01011_00000_00000_100000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[11] = 1234; // $t3 @@ -107,7 +107,7 @@ pub mod add { // $t1 = $t4 + $t4 // R-type t4 t4 t1 (shamt) ADD let instructions: Vec = vec![0b000000_01100_01100_01001_00000_100000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume register $t4 contains 2,454,267,026, a 32-bit integer. datapath.registers.gpr[12] = 0b10010010_01001001_00100100_10010010; @@ -133,7 +133,7 @@ pub mod add { // $t1 = $t4 + $t4 // R-type t4 t4 t1 (shamt) ADD let instructions: Vec = vec![0b000000_01100_01100_01001_00000_100000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume register $t4 contains 3,528,008,850, a 32-bit integer. datapath.registers.gpr[12] = 0b11010010_01001001_00100100_10010010; @@ -158,7 +158,7 @@ pub mod addu { // $t1 = $t1 + $t1 // R-type t1 t1 t1 (shamt) ADDU let instructions: Vec = vec![0b000000_01001_01001_01001_00000_100001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume the register $t1 has the value 5. datapath.registers[GpRegisterType::T1] = 5; @@ -177,7 +177,7 @@ pub mod addu { // $s2 = $s0 + $s1 // R-type s0 s1 s2 (shamt) ADDU let instructions: Vec = vec![0b000000_10000_10001_10010_00000_100001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 15; // $s0 datapath.registers.gpr[17] = 40; // $s1 @@ -199,7 +199,7 @@ pub mod addu { // $zero = $t3 + $t3 // R-type t3 t3 zero (shamt) ADDU let instructions: Vec = vec![0b000000_01011_01011_00000_00000_100001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[11] = 1234; // $t3 @@ -217,7 +217,7 @@ pub mod addu { // $t1 = $t4 + $t4 // R-type t4 t4 t1 (shamt) ADDU let instructions: Vec = vec![0b000000_01100_01100_01001_00000_100001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume register $t4 contains 2,454,267,026, a 32-bit integer. datapath.registers.gpr[12] = 0b10010010_01001001_00100100_10010010; @@ -239,7 +239,7 @@ pub mod addu { // $t1 = $t4 + $t4 // R-type t4 t4 t1 (shamt) ADDU let instructions: Vec = vec![0b000000_01100_01100_01001_00000_100001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume register $t4 contains 3,528,008,850, a 32-bit integer. datapath.registers.gpr[12] = 0b11010010_01001001_00100100_10010010; @@ -265,7 +265,7 @@ pub mod sub { // $s2 = $s3 - $s2 // R-type s3 s2 s2 (shamt) SUB let instructions: Vec = vec![0b000000_10011_10010_10010_00000_100010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[19] = 7; // $s3 datapath.registers.gpr[18] = 3; // $s2 @@ -284,7 +284,7 @@ pub mod sub { // $s0 = $s0 - $t0 // R-type s0 t0 s0 (shamt) SUB let instructions: Vec = vec![0b000000_10000_01000_10000_00000_100010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 5; // $s0 datapath.registers.gpr[8] = 20; // $t0 @@ -307,7 +307,7 @@ pub mod sub { // $s0 = $s0 - $t0 // R-type s0 t0 s0 (shamt) SUB let instructions: Vec = vec![0b000000_10000_01000_10000_00000_100010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 0; // $s0 datapath.registers.gpr[8] = 1; // $t0 @@ -333,7 +333,7 @@ pub mod mul { // $s5 = $t7 * $t6 // R-type t7 t6 s5 MUL SOP30 let instructions: Vec = vec![0b000000_01111_01110_10101_00010_011000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[15] = 8; // $t7 datapath.registers.gpr[14] = 95; // $t6 @@ -351,7 +351,7 @@ pub mod mul { // $s5 = $t7 * $t6 // R-type t7 t6 s5 MUL SOP30 let instructions: Vec = vec![0b000000_01111_01110_10101_00010_011000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[15] = 5; // $t7 datapath.registers.gpr[14] = -5_i64 as u64; // $t6 @@ -369,7 +369,7 @@ pub mod mul { // $s4 = $t6 * $t5 // R-type t6 t5 s4 MUL SOP30 let instructions: Vec = vec![0b000000_01110_01101_10100_00010_011000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[14] = 731_564_544; // $t6 datapath.registers.gpr[13] = 8; // $t5 @@ -397,7 +397,7 @@ pub mod div { // $s4 = $t6 / $t5 // R-type t6 t5 s4 DIV SOP32 let instructions: Vec = vec![0b000000_01110_01101_10100_00010_011010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[14] = 20; // $t6 datapath.registers.gpr[13] = 2; // $t5 @@ -415,7 +415,7 @@ pub mod div { // $s4 = $t6 / $t5 // R-type t6 t5 s4 DIV SOP32 let instructions: Vec = vec![0b000000_01110_01101_10100_00010_011010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[14] = 20; // $t6 datapath.registers.gpr[13] = -5_i64 as u64; // $t5 @@ -437,7 +437,7 @@ pub mod or { // $t1 = $t1 & $t1 // R-type t1 t1 t1 (shamt) OR let instructions: Vec = vec![0b000000_01001_01001_01001_00000_100101]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume the register $t1 has the value 5. datapath.registers[GpRegisterType::T1] = 0x5; @@ -454,7 +454,7 @@ pub mod or { // $s2 = $s0 & $s1 // R-type s0 s1 s2 (shamt) OR let instructions: Vec = vec![0b000000_10000_10001_10010_00000_100101]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 0x1234; // $s0 datapath.registers.gpr[17] = 0x4321; // $s1 @@ -474,7 +474,7 @@ pub mod or { // $s2 = $s0 & $s1 // R-type s0 s1 s2 (shamt) OR let instructions: Vec = vec![0b000000_10000_10001_10010_00000_100101]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 0x12341234; // $s0 datapath.registers.gpr[17] = 0x43214321; // $s1 @@ -494,7 +494,7 @@ pub mod or { // $s2 = $s0 & $s1 // R-type s0 s1 s2 (shamt) OR let instructions: Vec = vec![0b000000_10000_10001_10010_00000_100101]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 0x1234123412341234; // $s0 datapath.registers.gpr[17] = 0x4321432143214321; // $s1 @@ -516,7 +516,7 @@ pub mod or { // $zero = $t3 & $t3 // R-type t3 t3 zero (shamt) OR let instructions: Vec = vec![0b000000_01011_01011_00000_00000_100101]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[11] = 1234; // $t3 @@ -537,7 +537,7 @@ pub mod and { // $t1 = $t1 & $t1 // R-type t1 t1 t1 (shamt) AND let instructions: Vec = vec![0b000000_01001_01001_01001_00000_100100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume the register $t1 has the value 5. datapath.registers[GpRegisterType::T1] = 0x5; @@ -554,7 +554,7 @@ pub mod and { // $s2 = $s0 & $s1 // R-type s0 s1 s2 (shamt) AND let instructions: Vec = vec![0b000000_10000_10001_10010_00000_100100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 0x1234; // $s0 datapath.registers.gpr[17] = 0x4321; // $s1 @@ -574,7 +574,7 @@ pub mod and { // $s2 = $s0 & $s1 // R-type s0 s1 s2 (shamt) AND let instructions: Vec = vec![0b000000_10000_10001_10010_00000_100100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 0x12341234; // $s0 datapath.registers.gpr[17] = 0x43214321; // $s1 @@ -594,7 +594,7 @@ pub mod and { // $s2 = $s0 & $s1 // R-type s0 s1 s2 (shamt) AND let instructions: Vec = vec![0b000000_10000_10001_10010_00000_100100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 0x1234123412341234; // $s0 datapath.registers.gpr[17] = 0x4321432143214321; // $s1 @@ -616,7 +616,7 @@ pub mod and { // $zero = $t3 & $t3 // R-type t3 t3 zero (shamt) AND let instructions: Vec = vec![0b000000_01011_01011_00000_00000_100100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[11] = 1234; // $t3 @@ -638,7 +638,7 @@ pub mod sll { // something // R-type s1 s2 (shamt) SLL let instructions: Vec = vec![0b000000_00000_10001_10010_00000_000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[0b10001] = 123; datapath.registers.gpr[0b10010] = 321; @@ -655,7 +655,7 @@ pub mod sll { // Shift left by two logical // R-type s1 s2 (shamt) SLL let instructions: Vec = vec![0b000000_00000_10001_10010_00010_000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[0b10001] = 0b1010; datapath.registers.gpr[0b10010] = 0; @@ -672,7 +672,7 @@ pub mod sll { // Shift left by two logical // R-type s1 s2 (shamt) SLL let instructions: Vec = vec![0b000000_00000_10001_10010_00010_000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[0b10001] = 0x7fffffff; datapath.registers.gpr[0b10010] = 0x10101011; @@ -694,7 +694,7 @@ pub mod slt { // $s2 = $s0 < $s1 // R-type s0 s1 s2 (shamt) SLT let instructions: Vec = vec![0b000000_10000_10001_10010_00000_101010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::S0] = 1; datapath.registers[GpRegisterType::S1] = 123; @@ -712,7 +712,7 @@ pub mod slt { // $s2 = $s0 < $s1 // R-type s0 s1 s2 (shamt) SLT let instructions: Vec = vec![0b000000_10000_10001_10010_00000_101010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::S0] = 124; datapath.registers[GpRegisterType::S1] = 123; @@ -730,7 +730,7 @@ pub mod slt { // $s2 = $s0 < $s1 // R-type s0 s1 s2 (shamt) SLT let instructions: Vec = vec![0b000000_10000_10001_10010_00000_101010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::S0] = -124_i64 as u64; datapath.registers[GpRegisterType::S1] = 123; @@ -752,7 +752,7 @@ pub mod sltu { // $s2 = $s0 < $s1 // R-type s0 s1 s2 (shamt) SLTU let instructions: Vec = vec![0b000000_10000_10001_10010_00000_101011]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::S0] = 1; datapath.registers[GpRegisterType::S1] = 123; @@ -770,7 +770,7 @@ pub mod sltu { // $s2 = $s0 < $s1 // R-type s0 s1 s2 (shamt) SLTU let instructions: Vec = vec![0b000000_10000_10001_10010_00000_101011]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::S0] = 124; datapath.registers[GpRegisterType::S1] = 123; @@ -788,7 +788,7 @@ pub mod sltu { // $s2 = $s0 < $s1 // R-type s0 s1 s2 (shamt) SLTU let instructions: Vec = vec![0b000000_10000_10001_10010_00000_101011]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::S0] = -124_i64 as u64; datapath.registers[GpRegisterType::S1] = 123; @@ -809,7 +809,7 @@ pub mod andi { // $s0 = $zero & 12345 // andi $zero $s0 12345 let instructions: Vec = vec![0b001100_00000_10000_0011000000111001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); @@ -824,7 +824,7 @@ pub mod andi { // $s0 = $t0 & 12345 // andi $t0 $s0 12345 let instructions: Vec = vec![0b001100_01000_10000_0011000000111001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // In binary: 00111010 11011110 01101000 10110001 datapath.registers.gpr[8] = 987654321; // $t0 @@ -851,7 +851,7 @@ pub mod addi_addiu { // $s0 = $t0 + 0x4 // addi $t0 $s0 4 let instructions: Vec = vec![0b001000_01000_10000_0000000000000100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 1; datapath.registers[GpRegisterType::S0] = 123; datapath.execute_instruction(); @@ -871,7 +871,7 @@ pub mod addi_addiu { // $s0 = $t0 + 0x4 // addi $t0 $s0 4 let instructions: Vec = vec![0b001000_01000_10000_0000000000000100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 0xffffffff; datapath.registers[GpRegisterType::S0] = 123; datapath.execute_instruction(); @@ -888,7 +888,7 @@ pub mod addi_addiu { // $s0 = $t0 + 0x1 // addi $t0 $s0 1 let instructions: Vec = vec![0b001000_01000_10000_0000000000000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 0xfffffff1; datapath.execute_instruction(); @@ -903,7 +903,7 @@ pub mod addi_addiu { // $s0 = $t0 + 0x1 // addi $t0 $s0 1 let instructions: Vec = vec![0b001000_01000_10000_0000000000000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 0xfffffffe; datapath.execute_instruction(); @@ -918,7 +918,7 @@ pub mod addi_addiu { // $s0 = $t0 + 0x4 // addiu $t0 $s0 4 let instructions: Vec = vec![0b001001_01000_10000_0000000000000100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 1; datapath.registers[GpRegisterType::S0] = 123; datapath.execute_instruction(); @@ -934,7 +934,7 @@ pub mod addi_addiu { // $s0 = $t0 + 0x4 // addiu $t0 $s0 4 let instructions: Vec = vec![0b001001_01000_10000_0000000000000100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 0xffffffff; datapath.registers[GpRegisterType::S0] = 123; datapath.execute_instruction(); @@ -951,7 +951,7 @@ pub mod addi_addiu { // $s0 = $t0 + 0x1 // addi $t0 $s0 1 let instructions: Vec = vec![0b001000_01000_10000_0000000000000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 0xfffffff1; datapath.execute_instruction(); @@ -969,7 +969,7 @@ pub mod daddi_and_daddiu { // $s0 = $t0 + 0x4 // daddi $t0 $s0 4 let instructions: Vec = vec![0b011000_01000_10000_0000000000000100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 1; datapath.registers[GpRegisterType::S0] = 123; datapath.execute_instruction(); @@ -989,7 +989,7 @@ pub mod daddi_and_daddiu { // $s0 = $t0 + 0x1 // daddi $t0 $s0 1 let instructions: Vec = vec![0b011000_01000_10000_0000000000000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 0xffffffffffffffff; datapath.registers[GpRegisterType::S0] = 123; datapath.execute_instruction(); @@ -1005,7 +1005,7 @@ pub mod daddi_and_daddiu { // $s0 = $t0 + 0x1 // daddi $t0 $s0 1 let instructions: Vec = vec![0b011000_01000_10000_0000000000000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 0xfffffffffffffff1; datapath.execute_instruction(); @@ -1020,7 +1020,7 @@ pub mod daddi_and_daddiu { // $s0 = $t0 + 0x1 // daddi $t0 $s0 1 let instructions: Vec = vec![0b011000_01000_10000_0000000000000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 0xfffffffffffffffe; datapath.execute_instruction(); @@ -1035,7 +1035,7 @@ pub mod daddi_and_daddiu { // $s0 = $t0 + 0x4 // daddiu $t0 $s0 4 let instructions: Vec = vec![0b011001_01000_10000_0000000000000100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 1; datapath.registers[GpRegisterType::S0] = 123; datapath.execute_instruction(); @@ -1051,7 +1051,7 @@ pub mod daddi_and_daddiu { // $s0 = $t0 + 0x4 // daddiu $t0 $s0 4 let instructions: Vec = vec![0b011001_01000_10000_0000000000000100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 0xffffffffffffffff; datapath.registers[GpRegisterType::S0] = 123; datapath.execute_instruction(); @@ -1069,7 +1069,7 @@ pub mod daddi_and_daddiu { // $s0 = $t0 + 0x1 // daddiu $t0 $s0 1 let instructions: Vec = vec![0b011001_01000_10000_0000000000000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 0xfffffffffffffff1; datapath.execute_instruction(); @@ -1087,7 +1087,7 @@ pub mod ori { // $s0 = $zero | 12345 // ori $zero $s0 12345 let instructions: Vec = vec![0b001101_00000_10000_0011000000111001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); @@ -1102,7 +1102,7 @@ pub mod ori { // $s0 = $t0 | 12345 // ori $t0 $s0 12345 let instructions: Vec = vec![0b001101_01000_10000_0011000000111001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // In binary: 00111010 11011110 01101000 10110001 datapath.registers.gpr[8] = 987654321; // $t0 @@ -1133,7 +1133,7 @@ pub mod dadd_daddu { // SPECIAL rs rt rd 0 DADD // 13 13 2 let instructions: Vec = vec![0b000000_01101_01101_00010_00000_101100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume register $t5 contains 969,093,589,304, which is an integer // that takes up 39 bits. @@ -1159,7 +1159,7 @@ pub mod dadd_daddu { // SPECIAL rs rt rd 0 DADD // 13 13 2 let instructions: Vec = vec![0b000000_01101_01101_00010_00000_101100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume register $t5 contains 18,134,889,837,812,767,690, which is an integer // that takes up 64 bits. @@ -1182,7 +1182,7 @@ pub mod dadd_daddu { // SPECIAL rs rt rd 0 DADDU // 16 17 18 let instructions: Vec = vec![0b000000_10000_10001_10010_00000_101101]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 1_069_193_590_294; // $s0 datapath.registers.gpr[17] = 34_359_738_368; // $s1 @@ -1210,7 +1210,7 @@ pub mod dsub_dsubu { // $s4 $s3 $s5 DSUB // 18 17 19 let instructions: Vec = vec![0b000000_10010_10001_10011_00000_101110]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume registers $s3 and $s4 contain numbers larger than 32 bits, // but smaller than 64 bits. @@ -1240,7 +1240,7 @@ pub mod dsub_dsubu { // $s4 $s3 $s5 DSUB // 18 17 19 let instructions: Vec = vec![0b000000_10010_10001_10011_00000_101110]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume registers $s4 is the minimum possible integer and $s4 is 1. datapath.registers.gpr[18] = 0; // $s4 @@ -1263,7 +1263,7 @@ pub mod dsub_dsubu { // SPECIAL rs rt rd 0 DSUBU // 16 17 18 let instructions: Vec = vec![0b000000_10000_10001_10010_00000_101111]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 92_975_612_771_919; // $s0 datapath.registers.gpr[17] = 13_810_775_572_047; // $s1 @@ -1290,7 +1290,7 @@ pub mod dmul_dmulu { // SPECIAL $t8 $t9 $a0 DMUL SOP34 // 24 25 4 let instructions: Vec = vec![0b000000_11000_11001_00100_00010_011100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume register $t8 contains a number larger than 32 bits, // but smaller than 64 bits. @@ -1315,7 +1315,7 @@ pub mod dmul_dmulu { // SPECIAL $t7 $t6 $s7 DMUL SOP34 // 15 14 23 let instructions: Vec = vec![0b000000_01111_01110_10111_00010_011100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume register $t7 contains a number larger than 32 bits, // but smaller than 64 bits. @@ -1340,7 +1340,7 @@ pub mod dmul_dmulu { // SPECIAL $s4 $s3 $s2 DMUL SOP34 // 20 19 18 let instructions: Vec = vec![0b000000_10100_10011_10010_00010_011100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume registers $s4 and $s3 contain numbers larger than 32 bits, // but smaller than 64 bits. @@ -1369,7 +1369,7 @@ pub mod dmul_dmulu { // SPECIAL $s0 $s1 $s2 DMULU SOP35 // 16 17 18 let instructions: Vec = vec![0b000000_10000_10001_10010_00010_011101]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 17_592_186_044_416; // $s0 datapath.registers.gpr[17] = 1_000; // $s1 @@ -1397,7 +1397,7 @@ pub mod ddiv_ddivu { // 17 18 16 let instructions: Vec = vec![0b000000_10001_10010_10000_00010_011110]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume register $s1 contains a number larger than 32 bits, // but smaller than 64 bits. @@ -1425,7 +1425,7 @@ pub mod ddiv_ddivu { // 6 5 7 let instructions: Vec = vec![0b000000_00110_00101_00111_00010_011110]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume register $a2 contains a number larger than 32 bits, // but smaller than 64 bits. @@ -1453,7 +1453,7 @@ pub mod ddiv_ddivu { // 16 17 18 let instructions: Vec = vec![0b000000_10000_10001_10010_00010_011111]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 10_213_202_487_240; // $s0 datapath.registers.gpr[17] = 11; // $s1 @@ -1479,7 +1479,7 @@ pub mod dahi_dati { // op rs rt immediate // REGIMM $a0 DAHI 1 let instructions: Vec = vec![0b000001_00100_00110_0000000000000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[4] = 0xABCD; // $a0 @@ -1501,7 +1501,7 @@ pub mod dahi_dati { // op rs rt immediate // REGIMM $a1 DATI 1 let instructions: Vec = vec![0b000001_00101_11110_0000000000000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[5] = 0xABCD; // $a1 @@ -1523,7 +1523,7 @@ pub mod load_word { // lw $t0 $s0 offset = 0 let instructions: Vec = vec![0b100011_01000_10000_0000000000000000]; - datapath.initialize(instructions.clone())?; + datapath.initialize_legacy(instructions.clone())?; datapath.execute_instruction(); assert_eq!(datapath.registers.gpr[16], instructions[0] as u64); Ok(()) @@ -1537,7 +1537,7 @@ pub mod load_word { // lw $t0 $s0 offset = 4 let instructions: Vec = vec![0b100011_01000_10000_0000000000000100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // place data at address datapath.memory.store_word(0b100, 0x10000)?; @@ -1556,7 +1556,7 @@ pub mod load_word { // lw $t0 $s0 offset = 0 let instructions: Vec = vec![0b100011_01000_10000_0000000000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // place data at address datapath.memory.store_word(0b100, 0x10000)?; @@ -1575,7 +1575,7 @@ pub mod load_word { // lw $t0 $s0 offset = 0 let instructions: Vec = vec![0b100011_01000_10000_0000000000000100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // place data at address datapath.memory.store_word(0b1000, 0x10000)?; @@ -1594,7 +1594,7 @@ pub mod load_word { // lw $t0 $s0 offset = 0 let instructions: Vec = vec![0b100011_01000_10000_1111111111111100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // place data at address datapath.memory.store_word(0b1000, 0x10000)?; @@ -1615,7 +1615,7 @@ pub mod load_upper_imm { // lui $t0 $s0 offset = 42 let instructions: Vec = vec![0b001111_01000_10000_0010101010101010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); let t = datapath.registers[GpRegisterType::S0]; @@ -1629,7 +1629,7 @@ pub mod load_upper_imm { // lui $t0 $s0 offset = 42 let instructions: Vec = vec![0b001111_01000_10000_1010101010101010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); let t = datapath.registers[GpRegisterType::S0]; @@ -1645,7 +1645,7 @@ pub mod store_word { // sw $t0 $s0 offset = 0 let instructions: Vec = vec![0b101011_01000_10000_0000000000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); let t = datapath.memory.load_word(0)?; @@ -1659,7 +1659,7 @@ pub mod store_word { // sw $t0 $s0 offset = 4 let instructions: Vec = vec![0b101011_01000_10000_0000000000000100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[8] = 0; datapath.registers.gpr[16] = 0xff; @@ -1676,7 +1676,7 @@ pub mod store_word { // sw $t0 $s0 offset = 4 let instructions: Vec = vec![0b101011_01000_10000_0000000000000100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[8] = 4; datapath.registers.gpr[16] = 0xff; @@ -1693,7 +1693,7 @@ pub mod store_word { // sw $t0 $s0 offset = -4 let instructions: Vec = vec![0b101011_01000_10000_1111111111111100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[8] = 12; datapath.registers.gpr[16] = 0xff; @@ -1719,7 +1719,7 @@ pub mod coprocessor { // COP1 fmt ft fs fd function // s $f0 $f1 $f2 ADD let instructions: Vec = vec![0b010001_10000_00000_00001_00010_000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[0] = f32::to_bits(0.25f32) as u64; datapath.coprocessor.fpr[1] = f32::to_bits(0.5f32) as u64; @@ -1742,7 +1742,7 @@ pub mod coprocessor { // COP1 fmt ft fs fd function // d $f0 $f1 $f2 ADD let instructions: Vec = vec![0b010001_10001_00000_00001_00010_000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[0] = f64::to_bits(123.125); datapath.coprocessor.fpr[1] = f64::to_bits(0.5); @@ -1766,7 +1766,7 @@ pub mod coprocessor { // COP1 fmt ft fs fd function // s $f0 $f1 $f2 SUB let instructions: Vec = vec![0b010001_10000_00000_00001_00010_000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[0] = f32::to_bits(5.625f32) as u64; datapath.coprocessor.fpr[1] = f32::to_bits(3.125f32) as u64; @@ -1788,7 +1788,7 @@ pub mod coprocessor { // COP1 fmt ft fs fd function // d $f0 $f1 $f2 SUB let instructions: Vec = vec![0b010001_10001_00000_00001_00010_000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[0] = f64::to_bits(438.125); datapath.coprocessor.fpr[1] = f64::to_bits(98765.5); @@ -1810,7 +1810,7 @@ pub mod coprocessor { // COP1 fmt ft fs fd function // s $f4 $f5 $f9 MUL let instructions: Vec = vec![0b010001_10000_00100_00101_01001_000010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[5] = f32::to_bits(24.5f32) as u64; datapath.coprocessor.fpr[4] = f32::to_bits(0.5f32) as u64; @@ -1832,7 +1832,7 @@ pub mod coprocessor { // COP1 fmt ft fs fd function // d $f9 $f6 $f4 MUL let instructions: Vec = vec![0b010001_10001_01001_00110_00100_000010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[6] = f64::to_bits(-150.0625); datapath.coprocessor.fpr[9] = f64::to_bits(9.5); @@ -1854,7 +1854,7 @@ pub mod coprocessor { // COP1 fmt ft fs fd function // s $f17 $f16 $f15 DIV let instructions: Vec = vec![0b010001_10000_10001_10000_01111_000011]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[16] = f32::to_bits(901f32) as u64; datapath.coprocessor.fpr[17] = f32::to_bits(2f32) as u64; @@ -1879,7 +1879,7 @@ pub mod coprocessor { // COP1 fmt ft fs fd function // d $f20 $f10 $f1 DIV let instructions: Vec = vec![0b010001_10001_10100_01010_00001_000011]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[10] = f64::to_bits(95405.375); datapath.coprocessor.fpr[20] = f64::to_bits(2.0); @@ -1901,7 +1901,7 @@ pub mod coprocessor { // SWC1 base ft offset // $s1 $f3 0 let instructions: Vec = vec![0b111001_10001_00011_0000000000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[17] = 1028; // $s1 datapath.coprocessor.fpr[3] = f32::to_bits(1.0625f32) as u64; @@ -1927,7 +1927,7 @@ pub mod coprocessor { // SWC1 base ft offset // $s0 $f5 32 let instructions: Vec = vec![0b111001_10000_00101_0000000000100000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 2000; // $s0 datapath.coprocessor.fpr[5] = f32::to_bits(3.5f32) as u64; @@ -1957,7 +1957,7 @@ pub mod coprocessor { // SWC1 base ft offset // $s2 $f0 0 let instructions: Vec = vec![0b111001_10010_00000_0000000000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[18] = 1000; // $s2 datapath.coprocessor.fpr[0] = f64::to_bits(9853114.625); @@ -1982,7 +1982,7 @@ pub mod coprocessor { // LWC1 base ft offset // $t0 $f10 0 let instructions: Vec = vec![0b110001_01000_01010_0000000000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[8] = 500; // $t0 @@ -2013,7 +2013,7 @@ pub mod coprocessor { // LWC1 base ft offset // $t1 $f11 200 let instructions: Vec = vec![0b110001_01001_01011_0000000011001000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[9] = 1000; // $t1 @@ -2044,7 +2044,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // s $f2 $f1 0 EQ let instructions: Vec = vec![0b010001_10000_00010_00001_000_00_110010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[1] = f32::to_bits(15.5f32) as u64; datapath.coprocessor.fpr[2] = f32::to_bits(15.5f32) as u64; @@ -2067,7 +2067,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // s $f3 $f14 0 EQ let instructions: Vec = vec![0b010001_10000_00011_01110_000_00_110010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[14] = f32::to_bits(20.125f32) as u64; datapath.coprocessor.fpr[3] = f32::to_bits(100f32) as u64; @@ -2090,7 +2090,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // d $f9 $f5 0 EQ let instructions: Vec = vec![0b010001_10001_01001_00101_000_00_110010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[5] = f64::to_bits(12951.625); datapath.coprocessor.fpr[9] = f64::to_bits(12951.625); @@ -2113,7 +2113,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // d $f19 $f15 0 EQ let instructions: Vec = vec![0b010001_10001_10011_01111_000_00_110010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[15] = f64::to_bits(6016.25); datapath.coprocessor.fpr[19] = f64::to_bits(820.43); @@ -2136,7 +2136,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // s $f0 $f19 0 LT let instructions: Vec = vec![0b010001_10000_00000_10011_000_00_111100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[19] = f32::to_bits(2.875f32) as u64; datapath.coprocessor.fpr[0] = f32::to_bits(70.6f32) as u64; @@ -2159,7 +2159,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // s $f31 $f30 0 LT let instructions: Vec = vec![0b010001_10000_11111_11110_000_00_111100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[30] = f32::to_bits(90.7f32) as u64; datapath.coprocessor.fpr[31] = f32::to_bits(-87.44f32) as u64; @@ -2182,7 +2182,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // d $f29 $f12 0 LT let instructions: Vec = vec![0b010001_10001_11101_01100_000_00_111100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[12] = f64::to_bits(4.0); datapath.coprocessor.fpr[29] = f64::to_bits(30000.6); @@ -2205,7 +2205,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // d $f5 $f4 0 LT let instructions: Vec = vec![0b010001_10001_00101_00100_000_00_111100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[4] = f64::to_bits(413.420); datapath.coprocessor.fpr[5] = f64::to_bits(-6600.9); @@ -2228,7 +2228,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // s $f1 $f0 0 LE let instructions: Vec = vec![0b010001_10000_00001_00000_000_00_111110]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[0] = f32::to_bits(171.937f32) as u64; datapath.coprocessor.fpr[1] = f32::to_bits(9930.829f32) as u64; @@ -2251,7 +2251,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // s $f3 $f2 0 LE let instructions: Vec = vec![0b010001_10000_00011_00010_000_00_111110]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[2] = f32::to_bits(6.5f32) as u64; datapath.coprocessor.fpr[3] = f32::to_bits(6.5f32) as u64; @@ -2274,7 +2274,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // s $f5 $f4 0 LE let instructions: Vec = vec![0b010001_10000_00101_00100_000_00_111110]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[4] = f32::to_bits(5742.006f32) as u64; datapath.coprocessor.fpr[5] = f32::to_bits(1336.568f32) as u64; @@ -2297,7 +2297,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // d $f7 $f6 0 LE let instructions: Vec = vec![0b010001_10001_00111_00110_000_00_111110]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[6] = f64::to_bits(3483.70216); datapath.coprocessor.fpr[7] = f64::to_bits(7201.56625); @@ -2320,7 +2320,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // d $f9 $f8 0 LE let instructions: Vec = vec![0b010001_10001_01001_01000_000_00_111110]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[8] = f64::to_bits(77.4009); datapath.coprocessor.fpr[9] = f64::to_bits(77.4009); @@ -2343,7 +2343,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // d $f11 $f10 0 LE let instructions: Vec = vec![0b010001_10001_01011_01010_000_00_111110]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[10] = f64::to_bits(9190.43309); datapath.coprocessor.fpr[11] = f64::to_bits(2869.57622); @@ -2366,7 +2366,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // s $f13 $f12 0 NGT let instructions: Vec = vec![0b010001_10000_01101_01100_000_00_111111]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[12] = f32::to_bits(2469.465f32) as u64; datapath.coprocessor.fpr[13] = f32::to_bits(3505.57f32) as u64; @@ -2389,7 +2389,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // s $f15 $f14 0 NGT let instructions: Vec = vec![0b010001_10000_01111_01110_000_00_111111]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[14] = f32::to_bits(7099.472f32) as u64; datapath.coprocessor.fpr[15] = f32::to_bits(87.198f32) as u64; @@ -2412,7 +2412,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // d $f17 $f16 0 NGT let instructions: Vec = vec![0b010001_10001_10001_10000_000_00_111111]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[16] = f64::to_bits(7726.4794015); datapath.coprocessor.fpr[17] = f64::to_bits(9345.7753943); @@ -2435,7 +2435,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // d $f19 $f18 0 NGT let instructions: Vec = vec![0b010001_10001_10011_10010_000_00_111111]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[18] = f64::to_bits(4688.2854359); datapath.coprocessor.fpr[19] = f64::to_bits(819.7956308); @@ -2458,7 +2458,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // s $f21 $f20 0 NGE let instructions: Vec = vec![0b010001_10000_10101_10100_000_00_111101]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[20] = f32::to_bits(3090.244f32) as u64; datapath.coprocessor.fpr[21] = f32::to_bits(7396.444f32) as u64; @@ -2481,7 +2481,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // s $f23 $f22 0 NGE let instructions: Vec = vec![0b010001_10000_10111_10110_000_00_111101]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[22] = f32::to_bits(6269.823f32) as u64; datapath.coprocessor.fpr[23] = f32::to_bits(3089.393f32) as u64; @@ -2504,7 +2504,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // d $f25 $f24 0 NGE let instructions: Vec = vec![0b010001_10001_11001_11000_000_00_111101]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[24] = f64::to_bits(819.7956308); datapath.coprocessor.fpr[25] = f64::to_bits(4688.2854359); @@ -2527,7 +2527,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // d $f27 $f26 0 NGE let instructions: Vec = vec![0b010001_10001_11011_11010_000_00_111101]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[26] = f64::to_bits(9776.3465875); datapath.coprocessor.fpr[27] = f64::to_bits(1549.8268716); @@ -2557,7 +2557,7 @@ pub mod coprocessor { // 0 -1 (which becomes -4) 0b010001_01000_000_0_1_1111111111111110, ]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[5] = f64::to_bits(12951.625); datapath.coprocessor.fpr[9] = f64::to_bits(12951.625); @@ -2588,7 +2588,7 @@ pub mod coprocessor { // 0 -1 (which becomes -4) 0b010001_01000_000_0_1_1111111111111110, ]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[5] = f64::to_bits(12952.625); datapath.coprocessor.fpr[9] = f64::to_bits(12951.625); @@ -2619,7 +2619,7 @@ pub mod coprocessor { // 0 -1 (which becomes -4) 0b010001_01000_000_0_0_1111111111111110, ]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[4] = f32::to_bits(5742.006f32) as u64; datapath.coprocessor.fpr[5] = f32::to_bits(1336.568f32) as u64; @@ -2650,7 +2650,7 @@ pub mod coprocessor { // 0 -1 (which becomes -4) 0b010001_01000_000_0_0_1111111111111110, ]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[4] = f32::to_bits(742.006f32) as u64; datapath.coprocessor.fpr[5] = f32::to_bits(1336.568f32) as u64; @@ -2674,7 +2674,7 @@ pub mod coprocessor { // COP1 sub rt fs 0 // MT $s0 $f0 let instructions: Vec = vec![0b010001_00100_10000_00000_00000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 25; @@ -2696,7 +2696,7 @@ pub mod coprocessor { // COP1 sub rt fs 0 // MT $s1 $f1 let instructions: Vec = vec![0b010001_00100_10001_00001_00000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[17] = 0x1234_5678_ABCD_BEEF; @@ -2718,7 +2718,7 @@ pub mod coprocessor { // COP1 sub rt fs 0 // DMT $t0 $f30 let instructions: Vec = vec![0b010001_00101_01000_11110_00000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[8] = 0xDEAD_BEEF_FEED_DEED; @@ -2740,7 +2740,7 @@ pub mod coprocessor { // COP1 sub rt fs 0 // MF $s5 $f18 let instructions: Vec = vec![0b010001_00000_10101_10010_00000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[18] = 123; @@ -2762,7 +2762,7 @@ pub mod coprocessor { // COP1 sub rt fs 0 // MF $s6 $f19 let instructions: Vec = vec![0b010001_00000_10110_10011_00000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[19] = 0xABBA_BABB_3ABA_4444; @@ -2784,7 +2784,7 @@ pub mod coprocessor { // COP1 sub rt fs 0 // MF $s7 $f20 let instructions: Vec = vec![0b010001_00000_10111_10100_00000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[20] = 0xBADA_BEEF_BADA_B00E; @@ -2806,7 +2806,7 @@ pub mod coprocessor { // COP1 sub rt fs 0 // DMF $t8 $f21 let instructions: Vec = vec![0b010001_00001_11000_10101_00000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[21] = 0xADDA_DADD_1BAA_CAFE; @@ -2826,7 +2826,7 @@ pub mod jump_tests { // J let instructions: Vec = vec![0b000010_00_00000000_00000000_00000010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); assert_eq!(datapath.registers.pc, 8); @@ -2839,7 +2839,7 @@ pub mod jump_tests { // J let instructions: Vec = vec![0x0800_0fff]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); assert_eq!(datapath.registers.pc, 0x3ffc); @@ -2853,7 +2853,7 @@ pub mod jump_tests { // J low_26 let instructions: Vec = vec![0x0800_0000 | 0x03ff_ffff]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); assert_eq!(datapath.registers.pc, 0x0fff_fffc); @@ -2870,7 +2870,7 @@ pub mod jump_and_link_tests { // J let instructions: Vec = vec![0b000011_00_00000000_00000000_00000010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); assert_eq!(datapath.registers.pc, 8); @@ -2885,7 +2885,7 @@ pub mod jump_and_link_tests { // J let instructions: Vec = vec![0x0c00_0fff]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); assert_eq!(datapath.registers.pc, 0x3ffc); @@ -2901,7 +2901,7 @@ pub mod jump_and_link_tests { // J low_26 let instructions: Vec = vec![0x0c00_0000 | 0x03ff_ffff]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); assert_eq!(datapath.registers.pc, 0x0fff_fffc); @@ -2919,7 +2919,7 @@ pub mod jr_and_jalr_tests { // JR $r8 // Special $r8 $zero $zero JALR let instructions: Vec = vec![0b000000_01000_00000_00000_00000_001001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[0b01000] = 24; datapath.execute_instruction(); @@ -2935,7 +2935,7 @@ pub mod jr_and_jalr_tests { // JALR $r8 // Special $r8 $zero $ra JALR let instructions: Vec = vec![0, 0, 0b000000_01000_00000_11111_00000_001001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.pc = 8; let initial_pc = datapath.registers.pc; datapath.registers.gpr[0b01000] = 24; @@ -2955,7 +2955,7 @@ pub mod beq_tests { // beq let instructions: Vec = vec![0b000100_01000_10000_0000000000000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; let initial_pc = datapath.registers.pc; datapath.execute_instruction(); @@ -2973,7 +2973,7 @@ pub mod beq_tests { 0b000100_01000_10000_0000000000000001, 0b000100_01000_10000_0000000000000001, ]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[0b01000] = 1234; datapath.registers.gpr[0b10000] = 4321; @@ -2997,7 +2997,7 @@ pub mod beq_tests { 0, // 0x0c 0b000100_01000_10000_1111111111111011, // 0x10, Branch to 0x00 ]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[0b01000] = 1234; datapath.registers.gpr[0b10000] = 1234; @@ -3046,7 +3046,7 @@ pub mod bne_tests { let instructions: Vec = vec![0b000101_01000_10000_0000000000000001]; datapath.registers.gpr[0b01000] = 1234; datapath.registers.gpr[0b10000] = 1234; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); let expt_result = 4; // PC + 4, PC starts at 0 with the bne instruction at address 0, no branch acures assert_eq!(datapath.registers.pc, expt_result); @@ -3074,7 +3074,7 @@ pub mod bne_tests { 0, // 0x1c 0b000101_01000_10000_1111111111111001, // 0x20, bne r8, r16, -24, (branch -28 relative to next addres), branch to 0x08 ]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[0b01000] = 1234; datapath.registers.gpr[0b10000] = 4321; @@ -3133,7 +3133,7 @@ pub mod syscall { // SPECIAL (code) SYSCALL 0b000000_00000000000000000000_001100, ]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; assert!(!datapath.is_halted()); datapath.registers.gpr[9] = 5; // $t1 diff --git a/src/tests/integration/core_parser/arithmetic.rs b/src/tests/integration/core_parser/arithmetic.rs index be7583455..bf09ce6f0 100644 --- a/src/tests/integration/core_parser/arithmetic.rs +++ b/src/tests/integration/core_parser/arithmetic.rs @@ -9,7 +9,7 @@ fn basic_addu() -> Result<(), String> { let instructions = String::from("addu r20, r19, r18"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[18] = 6849841; datapath.registers.gpr[19] = 99816512; @@ -33,7 +33,7 @@ sll $s1, $s1, 3"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); @@ -54,7 +54,7 @@ move $s5, $s4"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); @@ -72,7 +72,7 @@ fn basic_nop() -> Result<(), String> { let instructions = String::from(r#"nop"#); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; let mut expected_registers = datapath.registers; expected_registers.pc = 4; diff --git a/src/tests/integration/core_parser/basic_immediate.rs b/src/tests/integration/core_parser/basic_immediate.rs index e7653d7c1..46ca3a88e 100644 --- a/src/tests/integration/core_parser/basic_immediate.rs +++ b/src/tests/integration/core_parser/basic_immediate.rs @@ -11,7 +11,7 @@ fn basic_addi() -> Result<(), String> { let instructions = String::from("addi r11, r15, 2"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[15] = 100; @@ -31,7 +31,7 @@ fn basic_addiu() -> Result<(), String> { let instructions = String::from("addiu r14, r17, 5"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[17] = 500; @@ -51,7 +51,7 @@ fn basic_subi() -> Result<(), String> { let instructions = String::from("subi r11, r15, 2"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[15] = 100; @@ -71,7 +71,7 @@ fn basic_muli() -> Result<(), String> { let instructions = String::from("muli r11, r15, 2"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[15] = 100; @@ -91,7 +91,7 @@ fn basic_divi() -> Result<(), String> { let instructions = String::from("divi r11, r15, 2"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[15] = 100; @@ -111,7 +111,7 @@ fn basic_ori() -> Result<(), String> { let instructions = String::from("ori r11, r15, 2"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[15] = 100; @@ -131,7 +131,7 @@ fn basic_andi() -> Result<(), String> { let instructions = String::from("andi r11, r15, 4"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[15] = 100; @@ -151,7 +151,7 @@ fn basic_li() -> Result<(), String> { let instructions = String::from("li r15, 56"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); @@ -170,7 +170,7 @@ fn basic_lui() -> Result<(), String> { let instructions = String::from("lui r20, 65530"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); @@ -190,7 +190,7 @@ fn basic_aui() -> Result<(), String> { let instructions = String::from("aui r15, r18, 4612"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[18] = 0x0000_0000_0030_ABCD; diff --git a/src/tests/integration/core_parser/basic_operations.rs b/src/tests/integration/core_parser/basic_operations.rs index fd2150e3b..4ea6f6728 100644 --- a/src/tests/integration/core_parser/basic_operations.rs +++ b/src/tests/integration/core_parser/basic_operations.rs @@ -9,7 +9,7 @@ fn basic_add() -> Result<(), String> { let instructions = String::from("add r11, r7, r8"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[7] = 51; datapath.registers.gpr[8] = 5; @@ -30,7 +30,7 @@ fn basic_sub() -> Result<(), String> { let instructions = String::from("sub r12, r7, r8"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[7] = 51; datapath.registers.gpr[8] = 5; @@ -51,7 +51,7 @@ fn basic_mul() -> Result<(), String> { let instructions = String::from("mul r13, r7, r8"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[7] = 51; datapath.registers.gpr[8] = 5; @@ -72,7 +72,7 @@ fn basic_div() -> Result<(), String> { let instructions = String::from("div r14, r7, r8"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[7] = 51; datapath.registers.gpr[8] = 5; @@ -93,7 +93,7 @@ fn basic_or() -> Result<(), String> { let instructions = String::from("or r15, r7, r8"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[7] = 51; datapath.registers.gpr[8] = 5; @@ -114,7 +114,7 @@ fn basic_and() -> Result<(), String> { let instructions = String::from("and r16, r7, r8"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[7] = 51; datapath.registers.gpr[8] = 5; diff --git a/src/tests/integration/core_parser/branch_jump.rs b/src/tests/integration/core_parser/branch_jump.rs index 72d55ab65..0cbbcedd5 100644 --- a/src/tests/integration/core_parser/branch_jump.rs +++ b/src/tests/integration/core_parser/branch_jump.rs @@ -17,7 +17,7 @@ j loop"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; // Execute the ori instruction. datapath.execute_instruction(); @@ -45,7 +45,7 @@ jr r15"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; // Execute 2 instructions. for _ in 0..2 { @@ -70,7 +70,7 @@ function: ori $t0, $zero, 5831"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); @@ -96,7 +96,7 @@ function: ori $t1, $zero, 9548"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; // Execute 3 instructions. for _ in 0..3 { @@ -145,7 +145,7 @@ change10: daddiu $s2, $s2, 10"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); @@ -186,7 +186,7 @@ changez: daddiu $s2, $s2, 20"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); @@ -218,7 +218,7 @@ bne $s0, $s2, loop"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; let mut iterations = 0; diff --git a/src/tests/integration/core_parser/conditions.rs b/src/tests/integration/core_parser/conditions.rs index 91d957f12..774cafe66 100644 --- a/src/tests/integration/core_parser/conditions.rs +++ b/src/tests/integration/core_parser/conditions.rs @@ -27,7 +27,7 @@ akin! { let instructions = String::from("*instruction_name r*destination_register, r5, r6"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[5] = *true_value1; datapath.registers.gpr[6] = *true_value2; @@ -46,7 +46,7 @@ akin! { let instructions = String::from("*instruction_name r*destination_register, r5, r6"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[5] = *false_value1; datapath.registers.gpr[6] = *false_value2; diff --git a/src/tests/integration/core_parser/coprocessor_move.rs b/src/tests/integration/core_parser/coprocessor_move.rs index 38de80480..bcff12b7f 100644 --- a/src/tests/integration/core_parser/coprocessor_move.rs +++ b/src/tests/integration/core_parser/coprocessor_move.rs @@ -8,7 +8,7 @@ fn basic_mtc1() -> Result<(), String> { let instructions = String::from("mtc1 $t2, $f5"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[10] = 658461658; // $t2 @@ -26,7 +26,7 @@ fn truncate_32_bit_mtc1() -> Result<(), String> { let instructions = String::from("mtc1 $t3, $f6"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[11] = 0x0000_02F2_AC71_AC41; // $t3 @@ -44,7 +44,7 @@ fn basic_mfc1() -> Result<(), String> { let instructions = String::from("mfc1 $t3, $f5"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.coprocessor.fpr[5] = 657861659; @@ -62,7 +62,7 @@ fn truncate_32_bit_mfc1() -> Result<(), String> { let instructions = String::from("mfc1 $t4, $f6"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.coprocessor.fpr[6] = 0x0003_7F80_E5E7_D785; @@ -80,7 +80,7 @@ fn basic_dmtc1() -> Result<(), String> { let instructions = String::from("dmtc1 $t3, $f6"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[11] = 0x0120_02F2_AC71_AC41; // $t3 @@ -98,7 +98,7 @@ fn basic_dmfc1() -> Result<(), String> { let instructions = String::from("dmfc1 $t4, $f6"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.coprocessor.fpr[6] = 0x0003_7F90_E5E7_D785; diff --git a/src/tests/integration/core_parser/double_arithmetic.rs b/src/tests/integration/core_parser/double_arithmetic.rs index 83ee30fdd..9c2c46e2e 100644 --- a/src/tests/integration/core_parser/double_arithmetic.rs +++ b/src/tests/integration/core_parser/double_arithmetic.rs @@ -17,7 +17,7 @@ akin! { let instructions = String::from(*instruction); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[16] = *value1; datapath.registers.gpr[17] = *value2; @@ -46,7 +46,7 @@ akin! { let instructions = String::from(*instruction); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[25] = *value1; datapath.registers.gpr[26] = *value2; diff --git a/src/tests/integration/core_parser/double_immediate.rs b/src/tests/integration/core_parser/double_immediate.rs index 4bd27b211..531f3795e 100644 --- a/src/tests/integration/core_parser/double_immediate.rs +++ b/src/tests/integration/core_parser/double_immediate.rs @@ -8,7 +8,7 @@ fn basic_dahi() -> Result<(), String> { let instructions = String::from("dahi r3, 123"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[3] = 0; @@ -29,7 +29,7 @@ fn dahi_sign_extend() -> Result<(), String> { let instructions = String::from("dahi r5, 43158"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[5] = 0; @@ -50,7 +50,7 @@ fn basic_dati() -> Result<(), String> { let instructions = String::from("dati r10, 4321"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[10] = 0; @@ -78,7 +78,7 @@ akin! { let instructions = String::from(*instruction); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[20] = *rs_value; @@ -104,7 +104,7 @@ akin! { let instructions = String::from(*instruction); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[20] = *rs_value; diff --git a/src/tests/integration/core_parser/fibonacci.rs b/src/tests/integration/core_parser/fibonacci.rs index de64e4399..f380aeaee 100644 --- a/src/tests/integration/core_parser/fibonacci.rs +++ b/src/tests/integration/core_parser/fibonacci.rs @@ -75,7 +75,7 @@ fn recursive_fibonacci() -> Result<(), String> { ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); diff --git a/src/tests/integration/core_parser/floating_point_arithmetic.rs b/src/tests/integration/core_parser/floating_point_arithmetic.rs index c88473c28..7f3466d48 100644 --- a/src/tests/integration/core_parser/floating_point_arithmetic.rs +++ b/src/tests/integration/core_parser/floating_point_arithmetic.rs @@ -19,7 +19,7 @@ akin! { let instructions = String::from(*instruction); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.coprocessor.fpr[15] = *value1; datapath.coprocessor.fpr[16] = *value2; @@ -50,7 +50,7 @@ akin! { let instructions = String::from(*instruction); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.coprocessor.fpr[15] = *value1; datapath.coprocessor.fpr[16] = *value2; diff --git a/src/tests/integration/core_parser/floating_point_branch.rs b/src/tests/integration/core_parser/floating_point_branch.rs index 59db68d78..fb74fd44f 100644 --- a/src/tests/integration/core_parser/floating_point_branch.rs +++ b/src/tests/integration/core_parser/floating_point_branch.rs @@ -31,7 +31,7 @@ bc1t loop"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); @@ -74,7 +74,7 @@ bc1f loop"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); diff --git a/src/tests/integration/core_parser/floating_point_comparison.rs b/src/tests/integration/core_parser/floating_point_comparison.rs index 6b663a17d..45e9ed632 100644 --- a/src/tests/integration/core_parser/floating_point_comparison.rs +++ b/src/tests/integration/core_parser/floating_point_comparison.rs @@ -17,7 +17,7 @@ akin! { let instructions = String::from(*instruction); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.coprocessor.fpr[15] = *value1; datapath.coprocessor.fpr[16] = *value2; @@ -46,7 +46,7 @@ akin! { let instructions = String::from(*instruction); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.coprocessor.fpr[15] = *value1; datapath.coprocessor.fpr[16] = *value2; diff --git a/src/tests/integration/core_parser/mod.rs b/src/tests/integration/core_parser/mod.rs index 1951eeb01..79b7166a5 100644 --- a/src/tests/integration/core_parser/mod.rs +++ b/src/tests/integration/core_parser/mod.rs @@ -31,7 +31,7 @@ add $s1, $s0, $s0"#, // Parse instructions and load into emulation core memory. let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; // Execute 2 instructions. for _ in 0..2 { @@ -70,7 +70,7 @@ dati r1, 43982"#, // Parse instructions and load into emulation core memory. let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; // Execute 4 instructions. for _ in 0..4 { @@ -97,7 +97,7 @@ dmuli r8, r7, 2"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); diff --git a/src/tests/integration/core_parser/store_load_word.rs b/src/tests/integration/core_parser/store_load_word.rs index 68e4473e3..00e7811ec 100644 --- a/src/tests/integration/core_parser/store_load_word.rs +++ b/src/tests/integration/core_parser/store_load_word.rs @@ -13,7 +13,7 @@ sw r25, 0(r14)"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); @@ -34,7 +34,7 @@ lw r25, 0(r14)"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.memory.memory[403] = 36; @@ -62,7 +62,7 @@ sw $s2, secret_number"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); @@ -89,7 +89,7 @@ swc1 $f25, 0($s0)"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); @@ -110,7 +110,7 @@ lwc1 $f12, 0($t4)"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.memory.memory[403] = 36; From a95d54f0fe7cd115aad49d394417fd32b4d51972 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 8 Feb 2024 20:27:13 -0500 Subject: [PATCH 041/355] Send assembled code to the worker thread when the assemble button is clicked --- src/agent.rs | 4 ++-- src/agent/datapath_communicator.rs | 4 ++-- src/agent/messages.rs | 2 +- src/bin/main.rs | 9 ++++++++- src/emulation_core/datapath.rs | 2 +- src/emulation_core/mips/datapath.rs | 4 +++- 6 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index 497a0b2fb..666e0f9a1 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -85,8 +85,8 @@ impl EmulatorCoreAgentState { Command::SetCore(_architecture) => { todo!() // Implement once we have a RISCV datapath } - Command::Initialize(mem) => { - self.current_datapath.initialize(mem).unwrap(); + Command::Initialize(initial_pc, mem) => { + self.current_datapath.initialize(initial_pc, mem).unwrap(); } Command::SetExecuteSpeed(speed) => { self.speed = speed; diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index 18c5d772e..d9cccbec6 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -88,8 +88,8 @@ impl DatapathCommunicator { } /// Resets and loads the parsed/assembled instructions provided into the current emulator core. - pub fn initialize(&self, instructions: Vec) { - self.send_message(Command::Initialize(instructions)); + pub fn initialize(&self, initial_pc: usize, instructions: Vec) { + self.send_message(Command::Initialize(initial_pc, instructions)); } /// Sets the execution speed of the emulator core to the provided speed in hz. If set to zero, the emulator core diff --git a/src/agent/messages.rs b/src/agent/messages.rs index 63a24a1cf..26cad3db9 100644 --- a/src/agent/messages.rs +++ b/src/agent/messages.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Serialize, Deserialize)] pub enum Command { SetCore(AvailableDatapaths), - Initialize(Vec), + Initialize(usize, Vec), SetExecuteSpeed(u32), SetRegister(String, u64), SetMemory(usize, Vec), diff --git a/src/bin/main.rs b/src/bin/main.rs index ddcb01140..27fae92fa 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -19,6 +19,7 @@ use swim::emulation_core::datapath::Datapath; use swim::emulation_core::mips::datapath::MipsDatapath; use swim::emulation_core::mips::datapath::Stage; use swim::parser::parser_assembler_main::parser; +use swim::shims; use swim::ui::console::component::Console; use swim::ui::regview::component::Regview; use wasm_bindgen::{JsCast, JsValue}; @@ -103,6 +104,7 @@ fn app(props: &AppProps) -> Html { let datapath = Rc::clone(&datapath); let parser_text_output = parser_text_output.clone(); let trigger = use_force_update(); + let communicator = props.communicator; let executed_line = executed_line.clone(); let not_highlighted = not_highlighted.clone(); @@ -158,7 +160,7 @@ fn app(props: &AppProps) -> Html { // Proceed with loading into memory and expand pseudo-instructions if there are no errors. if marker_jsarray.length() == 0 { // Load the binary into the datapath's memory - match datapath.initialize_legacy(assembled) { + match datapath.initialize_legacy(assembled.clone()) { Ok(_) => (), Err(msg) => { // In the case of an error, note this and stop early. @@ -168,6 +170,11 @@ fn app(props: &AppProps) -> Html { // log!(datapath.memory.to_string()); text_model.set_value(&program_info.updated_monaco_string); // Expands pseudo-instructions to their hardware counterpart. datapath.registers.pc = program_info.pc_starting_point as u64; + // Send the binary over to the emulation core thread + communicator.initialize( + program_info.pc_starting_point, + shims::convert_to_u8_bytes(assembled), + ) } trigger.force_update(); diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index 47ceb3217..fbcb96e55 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -50,7 +50,7 @@ pub trait Datapath { /// Reset the datapath, load instructions into memory, and un-sets the `is_halted` /// flag. If the process fails, an [`Err`] is returned. - fn initialize(&mut self, instructions: Vec) -> Result<(), String>; + fn initialize(&mut self, initial_pc: usize, instructions: Vec) -> Result<(), String>; /// Retrieve all memory as-is. fn get_memory(&self) -> &Memory; diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index fbddacd88..6f6a5612d 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -273,9 +273,10 @@ impl Datapath for MipsDatapath { todo!() } - fn initialize(&mut self, instructions: Vec) -> Result<(), String> { + fn initialize(&mut self, initial_pc: usize, instructions: Vec) -> Result<(), String> { self.reset(); self.load_instructions(shims::convert_from_u8_bytes(instructions))?; + self.registers.pc = initial_pc as u64; self.is_halted = false; Ok(()) @@ -300,6 +301,7 @@ impl Datapath for MipsDatapath { impl MipsDatapath { // ===================== General Functions ===================== + /// Legacy initialize function, to be removed later. pub fn initialize_legacy(&mut self, instructions: Vec) -> Result<(), String> { self.reset(); self.load_instructions(instructions)?; From de92fb4779504d4dac07081ceb1697771310530f Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 8 Feb 2024 21:22:04 -0500 Subject: [PATCH 042/355] Utilize the new reducer from the UI in the register view --- src/agent.rs | 4 +++ src/agent/datapath_communicator.rs | 19 +++++++--- src/agent/datapath_reducer.rs | 58 ++++++++++++++++++++++++++++++ src/agent/messages.rs | 1 + src/bin/main.rs | 15 ++++++-- 5 files changed, 89 insertions(+), 8 deletions(-) create mode 100644 src/agent/datapath_reducer.rs diff --git a/src/agent.rs b/src/agent.rs index 666e0f9a1..fe2cbeb67 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -12,6 +12,7 @@ use yew::platform::time::sleep; use yew_agent::prelude::*; pub mod datapath_communicator; +pub mod datapath_reducer; pub mod messages; /// The main logic for the emulation core agent. All code within this function runs on a worker thread as opposed to @@ -109,6 +110,9 @@ impl EmulatorCoreAgentState { Command::Pause => { self.executing = false; } + Command::Reset => { + self.current_datapath.reset(); + } } } diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index d9cccbec6..b10dc6d1d 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -1,3 +1,4 @@ +use crate::agent::datapath_reducer::DatapathReducer; use crate::agent::messages::Command; use crate::agent::EmulationCoreAgent; use crate::emulation_core::architectures::AvailableDatapaths; @@ -8,7 +9,7 @@ use futures::StreamExt; use gloo_console::log; use gloo_console::warn; use std::cell::RefCell; -use yew::UseForceUpdateHandle; +use yew::UseReducerDispatcher; use yew_agent::reactor::ReactorBridge; /// This struct provides an abstraction over all communication with the worker thread. Any commands to the worker @@ -46,7 +47,10 @@ impl DatapathCommunicator { /// from the main app component. After updating internal state, the component this was called from will be force /// updated. #[allow(clippy::await_holding_refcell_ref)] - pub async fn listen_for_updates(&self, update_handle: UseForceUpdateHandle) { + pub async fn listen_for_updates( + &self, + dispatcher_handle: UseReducerDispatcher, + ) { let mut reader = match self.reader.try_borrow_mut() { Ok(reader) => reader, Err(_) => { @@ -59,10 +63,10 @@ impl DatapathCommunicator { log!("Waiting..."); let update = reader.next().await; log!(format!("Got update {:?}", update)); - if update.is_none() { - return; + match update { + None => return, + Some(update) => dispatcher_handle.dispatch(update), } - update_handle.force_update(); } } @@ -128,4 +132,9 @@ impl DatapathCommunicator { pub fn pause_core(&self) { self.send_message(Command::Pause); } + + /// Resets the current core to its default state. + pub fn reset(&self) { + self.send_message(Command::Reset); + } } diff --git a/src/agent/datapath_reducer.rs b/src/agent/datapath_reducer.rs new file mode 100644 index 000000000..e102cfbf1 --- /dev/null +++ b/src/agent/datapath_reducer.rs @@ -0,0 +1,58 @@ +use crate::agent::messages::MipsStateUpdate; +use crate::emulation_core::architectures::AvailableDatapaths::MIPS; +use crate::emulation_core::architectures::{AvailableDatapaths, DatapathUpdate}; +use crate::emulation_core::mips::datapath::DatapathState; +use crate::emulation_core::mips::memory::Memory; +use crate::emulation_core::mips::registers::GpRegisters; +use std::rc::Rc; +use yew::Reducible; + +pub struct DatapathReducer { + pub current_architecture: AvailableDatapaths, + pub mips: MipsState, +} + +#[derive(Default)] +pub struct MipsState { + pub state: DatapathState, + pub registers: GpRegisters, + pub memory: Memory, +} + +impl Default for DatapathReducer { + fn default() -> Self { + Self { + current_architecture: MIPS, + mips: MipsState::default(), + } + } +} + +impl Reducible for DatapathReducer { + type Action = DatapathUpdate; + + fn reduce(self: Rc, action: Self::Action) -> Rc { + Rc::from(match action { + DatapathUpdate::MIPS(update) => Self { + current_architecture: AvailableDatapaths::MIPS, + mips: match update { + MipsStateUpdate::UpdateState(state) => MipsState { + state, + registers: self.mips.registers, + memory: self.mips.memory.clone(), + }, + MipsStateUpdate::UpdateRegisters(registers) => MipsState { + state: self.mips.state.clone(), + registers, + memory: self.mips.memory.clone(), + }, + MipsStateUpdate::UpdateMemory(memory) => MipsState { + state: self.mips.state.clone(), + registers: self.mips.registers, + memory, + }, + }, + }, + }) + } +} diff --git a/src/agent/messages.rs b/src/agent/messages.rs index 26cad3db9..b92c23208 100644 --- a/src/agent/messages.rs +++ b/src/agent/messages.rs @@ -16,6 +16,7 @@ pub enum Command { ExecuteInstruction, ExecuteStage, Pause, + Reset, } /// Information about the emulator core's state sent from the worker thread to the UI thread. diff --git a/src/bin/main.rs b/src/bin/main.rs index 27fae92fa..8136bd1c2 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -14,6 +14,7 @@ use monaco::{ }; use std::rc::Rc; use swim::agent::datapath_communicator::DatapathCommunicator; +use swim::agent::datapath_reducer::DatapathReducer; use swim::agent::EmulationCoreAgent; use swim::emulation_core::datapath::Datapath; use swim::emulation_core::mips::datapath::MipsDatapath; @@ -86,13 +87,15 @@ fn app(props: &AppProps) -> Html { // the ability to access and change its contents be mutable. let datapath = use_mut_ref(MipsDatapath::default); + let datapath_state = use_reducer(DatapathReducer::default); + // Start listening for messages from the communicator. This effectively links the worker thread to the main thread // and will force updates whenever its internal state changes. { - let trigger = use_force_update(); + let dispatcher = datapath_state.dispatcher(); use_effect_with_deps( move |communicator| { - spawn_local(communicator.listen_for_updates(trigger)); + spawn_local(communicator.listen_for_updates(dispatcher)); }, props.communicator, ); @@ -193,6 +196,7 @@ fn app(props: &AppProps) -> Html { let text_model = Rc::clone(&text_model); let datapath = Rc::clone(&datapath); let trigger = use_force_update(); + let communicator = props.communicator; let executed_line = executed_line.clone(); let not_highlighted = not_highlighted.clone(); @@ -248,6 +252,7 @@ fn app(props: &AppProps) -> Html { // log!(not_highlighted.at(0)); datapath.execute_instruction(); + communicator.execute_instruction(); // done with the highlight, prepare for the next one. executed_line.pop(); @@ -269,6 +274,7 @@ fn app(props: &AppProps) -> Html { let not_highlighted = not_highlighted.clone(); let highlight_decor = highlight_decor; let trigger = use_force_update(); + let communicator = props.communicator; use_callback( move |_, _| { @@ -305,6 +311,7 @@ fn app(props: &AppProps) -> Html { } else { datapath.execute_stage(); } + communicator.execute_stage(); trigger.force_update(); }, (), @@ -318,6 +325,7 @@ fn app(props: &AppProps) -> Html { let datapath = Rc::clone(&datapath); let trigger = use_force_update(); let parser_text_output = parser_text_output.clone(); + let communicator = props.communicator; let executed_line = executed_line; let not_highlighted = not_highlighted; @@ -336,6 +344,7 @@ fn app(props: &AppProps) -> Html { ); parser_text_output.set("".to_string()); datapath.reset(); + communicator.reset(); trigger.force_update(); }, (), @@ -481,7 +490,7 @@ fn app(props: &AppProps) -> Html {
// Right column - + } From 0e059a939fc2d4f4ec3ad5cd9a28d5fa558ba36f Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 8 Feb 2024 21:34:07 -0500 Subject: [PATCH 043/355] Add some documentation and clean up code --- src/agent.rs | 4 +++- src/emulation_core/datapath.rs | 6 +++--- src/emulation_core/mips/datapath.rs | 6 +++++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index fe2cbeb67..add746df6 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -36,6 +36,7 @@ pub async fn emulation_core_agent(scope: ReactorScope) _ = sleep(Duration::from_millis(execution_delay)).fuse() => {}, } } else { + // If we're not currently executing, wait indefinitely until the next message comes in. match state.scope.next().await { Some(msg) => state.handle_command(msg), None => return, @@ -48,6 +49,7 @@ pub async fn emulation_core_agent(scope: ReactorScope) // Part 3: Processing State/Sending Updates to UI // TODO: This is a very naive implementation. Optimization is probably a good idea. + // TODO: Add support for the FP coprocessor updates in MIPS match state.current_datapath.as_datapath_ref() { DatapathRef::MIPS(datapath) => { let state_update = @@ -96,7 +98,7 @@ impl EmulatorCoreAgentState { self.current_datapath.set_register_by_str(®ister, value); } Command::SetMemory(ptr, data) => { - self.current_datapath.set_memory(ptr, &data); + self.current_datapath.set_memory(ptr, data); } Command::Execute => { self.executing = true; diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index fbcb96e55..4529ab819 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -55,9 +55,7 @@ pub trait Datapath { /// Retrieve all memory as-is. fn get_memory(&self) -> &Memory; - fn set_memory(&mut self, _ptr: usize, _data: &[u8]) { - todo!() - } + fn set_memory(&mut self, ptr: usize, data: Vec); /// Returns if the datapath is in a "halted" or "stopped" state. This may /// be true in the case where an error had occurred previously. @@ -66,6 +64,8 @@ pub trait Datapath { /// Restore the datapath to its default state. fn reset(&mut self); + /// Obtain a reference to the concrete datapath type. Used when datapath-specific logic is + /// needed while dealing with a datapath as a trait object. fn as_datapath_ref(&self) -> DatapathRef; } diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index 6f6a5612d..322fb262d 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -41,7 +41,7 @@ //! # Notes on `is_halted` //! //! - The datapath starts with the `is_halted` flag set. -//! - [`MipsDatapath::initialize_legacy()`] should be used to un-set `is_halted`. +//! - [`MipsDatapath::initialize()`] should be used to un-set `is_halted`. //! - The `syscall` instruction simply performs a no-operation instruction, except for //! setting the boolean flag `is_halted`. //! - Invalid instructions will cause the datapath to set the `is_halted` flag. @@ -286,6 +286,10 @@ impl Datapath for MipsDatapath { &self.memory } + fn set_memory(&mut self, _ptr: usize, _data: Vec) { + todo!() + } + fn is_halted(&self) -> bool { self.is_halted } From a8ef0c67123be5690bb23cb5d151496d513ad92b Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 8 Feb 2024 21:48:33 -0500 Subject: [PATCH 044/355] Rename MipsState to MipsCoreState --- src/agent/datapath_reducer.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/agent/datapath_reducer.rs b/src/agent/datapath_reducer.rs index e102cfbf1..55f073675 100644 --- a/src/agent/datapath_reducer.rs +++ b/src/agent/datapath_reducer.rs @@ -9,11 +9,11 @@ use yew::Reducible; pub struct DatapathReducer { pub current_architecture: AvailableDatapaths, - pub mips: MipsState, + pub mips: MipsCoreState, } #[derive(Default)] -pub struct MipsState { +pub struct MipsCoreState { pub state: DatapathState, pub registers: GpRegisters, pub memory: Memory, @@ -23,7 +23,7 @@ impl Default for DatapathReducer { fn default() -> Self { Self { current_architecture: MIPS, - mips: MipsState::default(), + mips: MipsCoreState::default(), } } } @@ -34,19 +34,19 @@ impl Reducible for DatapathReducer { fn reduce(self: Rc, action: Self::Action) -> Rc { Rc::from(match action { DatapathUpdate::MIPS(update) => Self { - current_architecture: AvailableDatapaths::MIPS, + current_architecture: MIPS, mips: match update { - MipsStateUpdate::UpdateState(state) => MipsState { + MipsStateUpdate::UpdateState(state) => MipsCoreState { state, registers: self.mips.registers, memory: self.mips.memory.clone(), }, - MipsStateUpdate::UpdateRegisters(registers) => MipsState { + MipsStateUpdate::UpdateRegisters(registers) => MipsCoreState { state: self.mips.state.clone(), registers, memory: self.mips.memory.clone(), }, - MipsStateUpdate::UpdateMemory(memory) => MipsState { + MipsStateUpdate::UpdateMemory(memory) => MipsCoreState { state: self.mips.state.clone(), registers: self.mips.registers, memory, From 9ae036d1f51a6db4e6dfda7d175c76e5ff1125fe Mon Sep 17 00:00:00 2001 From: Cay Date: Fri, 9 Feb 2024 12:47:10 -0500 Subject: [PATCH 045/355] Update Register View to use DatapathCommunicator --- src/bin/main.rs | 4 +- src/emulation_core/mips/datapath.rs | 5 +- src/emulation_core/mips/registers.rs | 25 +++++++ src/ui/regview/component.rs | 108 ++++++++------------------- static/styles/main.css | 4 + 5 files changed, 64 insertions(+), 82 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index 94ca2b1b8..6def0765f 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -37,7 +37,7 @@ use yew_hooks::prelude::*; // To load in the Fibonacci example, uncomment the CONTENT and fib_model lines // and comment the code, language, and text_model lines. IMPORTANT: // rename fib_model to text_model to have it work. -const CONTENT: &str = include_str!("../../static/assembly_examples/fibonacci.asm"); +const CONTENT: &str = include_str!("../../static/assembly_examples/data.asm"); #[derive(Properties, Clone, PartialEq)] struct AppProps { @@ -510,7 +510,7 @@ fn app(props: &AppProps) -> Html { // Right column - + } diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index 322fb262d..bd6b18585 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -51,7 +51,7 @@ use super::constants::*; use super::control_signals::{floating_point::*, *}; use super::datapath_signals::*; use super::instruction::*; -use super::{coprocessor::MipsFpCoprocessor, memory::Memory, registers::GpRegisters}; +use super::{coprocessor::MipsFpCoprocessor, memory::Memory, registers::{GpRegisters, GpRegisterType}}; use crate::emulation_core::architectures::DatapathRef; use crate::shims; use serde::{Deserialize, Serialize}; @@ -270,7 +270,8 @@ impl Datapath for MipsDatapath { } fn set_register_by_str(&mut self, _register: &str, _data: Self::RegisterData) { - todo!() + let register = &mut self.registers[_register]; + *register = _data; } fn initialize(&mut self, initial_pc: usize, instructions: Vec) -> Result<(), String> { diff --git a/src/emulation_core/mips/registers.rs b/src/emulation_core/mips/registers.rs index a4171e87f..341352876 100644 --- a/src/emulation_core/mips/registers.rs +++ b/src/emulation_core/mips/registers.rs @@ -6,6 +6,8 @@ use std::str::FromStr; use strum::IntoEnumIterator; use strum_macros::{Display, EnumIter, EnumString}; +use super::memory::CAPACITY_BYTES; + /// Collection of general-purpose registers used by the datapath. #[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)] pub struct GpRegisters { @@ -54,6 +56,29 @@ pub enum GpRegisterType { Ra = 31, } +impl GpRegisterType { + pub fn get_gpr_name(&self) -> String { + match self { + GpRegisterType::Pc => self.to_string(), + _ => format!("{} (r{})", self, *self as u32), + } + } + pub fn is_valid_register_value(&self, value: u64, pc_limit: usize) -> bool { + match self { + GpRegisterType::Zero => false, // Zero register is immutable + GpRegisterType::Pc => { + // Check if PC is more than the number of instructions or not word-aligned + value <= pc_limit as u64 && value % 4 == 0 + }, + GpRegisterType::Sp => { + // Check if SP is more than memory capacity or not word-aligned + value <= CAPACITY_BYTES as u64 && value % 4 == 0 + }, + _ => true, // Other registers are always considered valid + } + } +} + impl ToString for GpRegisters { fn to_string(&self) -> String { let mut output = String::new(); diff --git a/src/ui/regview/component.rs b/src/ui/regview/component.rs index b48550d51..f4b5fd190 100644 --- a/src/ui/regview/component.rs +++ b/src/ui/regview/component.rs @@ -1,22 +1,14 @@ use crate::agent::datapath_communicator::DatapathCommunicator; -use crate::emulation_core::mips::datapath::MipsDatapath; -use crate::emulation_core::mips::memory::CAPACITY_BYTES; -use crate::emulation_core::mips::registers::{GpRegisterType, GpRegisters}; -//use gloo::console::log; +use crate::emulation_core::mips::registers::GpRegisters; use wasm_bindgen::JsCast; use web_sys::{InputEvent, HtmlInputElement}; use yew::prelude::*; use yew::{html, Html}; -use std::rc::Rc; -use std::cell::RefCell; -// use log::debug; -// datapath.coprocessor.fpr #[derive(PartialEq, Properties)] pub struct Regviewprops { pub gp: GpRegisters, pub fp: [u64; 32], - pub datapath: Rc>, pub pc_limit: usize, pub communicator: &'static DatapathCommunicator } @@ -24,7 +16,8 @@ pub struct Regviewprops { pub struct Regrowprops { pub gp: GpRegisters, pub fp: [u64; 32], - pub on_input: Callback<(InputEvent, GpRegisterType)> + pub pc_limit: usize, + pub communicator: &'static DatapathCommunicator } #[derive(PartialEq, Properties)] pub struct Viewswitch { @@ -40,12 +33,6 @@ enum UnitState { Float, Double, } - -// #[derive(Debug)] -// enum Msg { -// UpdateRegister(GpRegisterType, i64), -// } - pub struct InputData { pub value: String, pub event: InputEvent, @@ -53,16 +40,36 @@ pub struct InputData { //Convert register to html through iterator pub fn generate_gpr_rows(props: &Regrowprops) -> Html { + let communicator = props.communicator; + let pc_limit = props.pc_limit; props.gp.into_iter() .map(|(register, data)| { - let on_input = Callback::clone(&props.on_input); html! {
- + @@ -75,7 +82,7 @@ pub fn generate_gpr_rows_hex(gp: GpRegisters) -> Html { .map(|(register, data)| { html! { - + } @@ -87,7 +94,7 @@ pub fn generate_gpr_rows_bin(gp: GpRegisters) -> Html { .map(|(register, data)| { html! { - + } @@ -162,22 +169,11 @@ pub fn generate_fpr_rows_double(fp: [u64; 32]) -> Html { .collect::() } -/// Returns the text to be shown for a general-purpose register. -pub fn get_gpr_name(register: GpRegisterType) -> String { - if register == GpRegisterType::Pc { - register.to_string() - } else { - format!("{} (r{})", register, register as u32) - } -} - #[function_component(Regview)] pub fn regview(props: &Regviewprops) -> Html { let active_view = use_state_eq(UnitState::default); let switch_flag = use_state_eq(|| true); - let datapath = Rc::clone(&props.datapath); - let pc_limit = props.pc_limit; let change_view = { let active_view = active_view.clone(); Callback::from(move |event: Event| { @@ -219,55 +215,11 @@ pub fn regview(props: &Regviewprops) -> Html { ) }; - let on_input = Callback::from(move |args: (InputEvent, GpRegisterType)| { - let (e, register) = args; - // let communicator = props.communicator; - let target = e.target(); - let input = target.unwrap().unchecked_into::(); - let val: i64 = match input.value().parse() { - Ok(value) => { - input.style().set_property("color", "black").unwrap_or_default(); - value - }, - Err(_err) => { - input.style().set_property("color", "red").unwrap_or_default(); - return - } - }; - // let msg = Msg::UpdateRegister(register, val); - - let mut datapath = datapath.borrow_mut(); - - let write_destination: usize = register as usize; - if register == GpRegisterType::Pc { - // check if pc is more than the number of instructions - // or if it's not word aligned - if val > pc_limit as i64 || val % 4 != 0 - { - input.style().set_property("color", "red").unwrap_or_default(); - return - } - - datapath.registers.pc = val as u64; - // communicator.send_test_message(val); - } - // check if pc is more than memory capacity - // or if it's not word aligned - else if register == GpRegisterType::Sp { - if val > CAPACITY_BYTES as i64 || val < 0 || val % 4 != 0 { - input.style().set_property("color", "red").unwrap_or_default(); - return - } - } - else { - datapath.registers.gpr[write_destination] = val as u64; - } - }); - let rowprops = Regrowprops { gp: props.gp, fp: props.fp, - on_input + pc_limit: props.pc_limit, + communicator: props.communicator }; //log!("This is ", *switch_flag); diff --git a/static/styles/main.css b/static/styles/main.css index 9a7794eb3..e1c4eeaee 100644 --- a/static/styles/main.css +++ b/static/styles/main.css @@ -263,6 +263,10 @@ th, td { padding: 2px 16px 2px 16px; } +td input.invalid { + color: red; +} + th:not(:last-child), td:not(:last-child) { border-right: 1px solid black; } From 33e0f18357f892953abe8a0b0ed3d39d57405e4f Mon Sep 17 00:00:00 2001 From: Cay Date: Fri, 9 Feb 2024 13:45:52 -0500 Subject: [PATCH 046/355] remove regrowprops --- src/emulation_core/registers.rs | 1 + src/ui/regview/component.rs | 19 ++----------------- 2 files changed, 3 insertions(+), 17 deletions(-) create mode 100644 src/emulation_core/registers.rs diff --git a/src/emulation_core/registers.rs b/src/emulation_core/registers.rs new file mode 100644 index 000000000..604b46fe4 --- /dev/null +++ b/src/emulation_core/registers.rs @@ -0,0 +1 @@ +pub trait IsRegisterType {} \ No newline at end of file diff --git a/src/ui/regview/component.rs b/src/ui/regview/component.rs index f4b5fd190..c5bff9728 100644 --- a/src/ui/regview/component.rs +++ b/src/ui/regview/component.rs @@ -13,13 +13,6 @@ pub struct Regviewprops { pub communicator: &'static DatapathCommunicator } #[derive(PartialEq, Properties)] -pub struct Regrowprops { - pub gp: GpRegisters, - pub fp: [u64; 32], - pub pc_limit: usize, - pub communicator: &'static DatapathCommunicator -} -#[derive(PartialEq, Properties)] pub struct Viewswitch { pub switch_view: bool, } @@ -39,7 +32,7 @@ pub struct InputData { } //Convert register to html through iterator -pub fn generate_gpr_rows(props: &Regrowprops) -> Html { +pub fn generate_gpr_rows(props: &Regviewprops) -> Html { let communicator = props.communicator; let pc_limit = props.pc_limit; @@ -214,14 +207,6 @@ pub fn regview(props: &Regviewprops) -> Html { switch_flag, ) }; - - let rowprops = Regrowprops { - gp: props.gp, - fp: props.fp, - pc_limit: props.pc_limit, - communicator: props.communicator - }; - //log!("This is ", *switch_flag); html! {
@@ -272,7 +257,7 @@ pub fn regview(props: &Regviewprops) -> Html { else if *active_view == UnitState::Hex { {generate_gpr_rows_hex(props.gp)} } else { - {generate_gpr_rows(&rowprops)} + {generate_gpr_rows(&props)} } } else { if *active_view == UnitState::Bin { From 0c8569358097f3df6f1bc7a570217d818af69160 Mon Sep 17 00:00:00 2001 From: Cay Date: Fri, 9 Feb 2024 15:41:59 -0500 Subject: [PATCH 047/355] Start using communicator to update memory --- src/agent/datapath_communicator.rs | 2 +- src/agent/messages.rs | 2 +- src/bin/main.rs | 147 ++++++++++++++++------------ src/emulation_core/datapath.rs | 2 +- src/emulation_core/mips/datapath.rs | 4 +- src/emulation_core/mips/memory.rs | 92 ++++++++--------- src/ui/hex_editor/component.rs | 26 +++++ static/assembly_examples/data.asm | 2 + 8 files changed, 159 insertions(+), 118 deletions(-) diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index c1f5def1e..c5a9249e2 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -109,7 +109,7 @@ impl DatapathCommunicator { /// Copies the contents of `data` to the emulator core's memory at `ptr`. Copies until either the end of `data` or /// the end of the emulaot core's memory. - pub fn set_memory(&self, ptr: usize, data: Vec) { + pub fn set_memory(&self, ptr: u64, data: u32) { self.send_message(Command::SetMemory(ptr, data)); } diff --git a/src/agent/messages.rs b/src/agent/messages.rs index b92c23208..f0c381f2a 100644 --- a/src/agent/messages.rs +++ b/src/agent/messages.rs @@ -11,7 +11,7 @@ pub enum Command { Initialize(usize, Vec), SetExecuteSpeed(u32), SetRegister(String, u64), - SetMemory(usize, Vec), + SetMemory(u64, u32), Execute, ExecuteInstruction, ExecuteStage, diff --git a/src/bin/main.rs b/src/bin/main.rs index 6def0765f..03e525f9e 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -10,7 +10,7 @@ use monaco::{ MarkerSeverity, } }; -use swim::ui::{footer::component::FooterTabState, swim_editor::component::EditorTabState}; +use swim::{emulation_core::{architectures::AvailableDatapaths, mips::instruction::get_string_version}, ui::{footer::component::FooterTabState, hex_editor::component::{parse_hexdump, UpdatedLine}, swim_editor::component::EditorTabState}}; use swim::parser::parser_structs_and_enums::ProgramInfo; use std::rc::Rc; use swim::agent::datapath_communicator::DatapathCommunicator; @@ -298,10 +298,13 @@ fn app(props: &AppProps) -> Html { let trigger = use_force_update(); let communicator = props.communicator; + let datapath_state = datapath_state.clone(); use_callback( move |_, _| { - let mut datapath = datapath.borrow_mut(); + let datapath = datapath.borrow_mut(); + + let communicator = communicator.clone(); let text_model = text_model.clone(); let program_info_ref = Rc::clone(&program_info_ref); @@ -311,78 +314,100 @@ fn app(props: &AppProps) -> Html { let current_memory_text_model_value = memory_text_model.get_value(); - match datapath.memory.parse_hexdump(¤t_memory_text_model_value) { + match parse_hexdump(¤t_memory_text_model_value) { Ok(instructions) => { - // Memory parsed with no errors - match datapath.memory.store_hexdump(instructions) { - Ok(changed_lines) => { - // Memory updated successfully - let program_info = program_info_ref.borrow().clone(); - let mut lines_beyond_counter = program_info.address_to_line_number.len(); - let mut curr_value = text_model.get_value().to_owned(); - let mut add_new_lines = false; - for line in changed_lines { - // Check if we're updating or appending instruction - if line.line_number < program_info.address_to_line_number.len() { - let updated_line = program_info.address_to_line_number[line.line_number] as f64 + 1.0; - let curr_model = text_model.as_ref(); - - // Get the current line's contents in the code editor - let line_to_replace = curr_model.get_line_content(updated_line); - // Create the range to replace - let mut start_line_column = 0.0; - let end_line_column = line_to_replace.len() as f64 + 2.0; - for (i, c) in line_to_replace.chars().enumerate() { - if c.is_alphanumeric() { - start_line_column = i as f64 + 1.0; - break; - } - } - let edit_range = monaco::sys::Range::new(updated_line, start_line_column, updated_line, end_line_column); - let before_cursor_state = monaco::sys::Selection::new(updated_line, start_line_column, updated_line,end_line_column); - // Create the edit operation using the range and new text - let edit_operations: monaco::sys::editor::IIdentifiedSingleEditOperation = Object::new().unchecked_into(); - edit_operations.set_range(&edit_range); - edit_operations.set_text(Some(&line.text)); - // Append it to JavaScript Array - let edit_operations_array = js_sys::Array::new(); - edit_operations_array.push(&edit_operations); - let before_cursor_state_array = js_sys::Array::new(); - before_cursor_state_array.push(&before_cursor_state); - // Do the edit! - curr_model.push_edit_operations(&before_cursor_state_array, &edit_operations_array, None); - } else if line.line_number == lines_beyond_counter { - // Append instruction - if !add_new_lines { - // If we've added new lines already, - // start adding new lines by getting a copy of the current text model to append to - add_new_lines = true; - curr_value = text_model.get_value(); - } - curr_value.push_str("\n"); - curr_value.push_str(&line.text); - lines_beyond_counter += 1; + + let mut changed_lines: Vec = vec![]; + for (i, data) in instructions.iter().enumerate() { + let address = i as u64; + // change string version based on architecture + let string_version = match datapath_state.current_architecture { + AvailableDatapaths::MIPS => { + match get_string_version(*data) { + Ok(string) => string, + Err(string) => string, } + }, + AvailableDatapaths::RISCV => { + String::from("") } - if add_new_lines { - text_model.set_value(&curr_value); + }; + + let curr_word = match datapath.memory.load_word(address * 4) { + Ok(data) => data, + Err(e) => { + debug!("{:?}", e); + 0 } + }; + if curr_word != *data { + debug!("address: {:?}", address * 4); + log::debug!("curr word: {}, new word: {}", curr_word, data); + changed_lines.push(UpdatedLine::new(string_version, i)); - }, - Err(err) => { - debug!("Error: {}", err) + communicator.set_memory(address * 4, *data); } - }; - () + } + // Memory updated successfully + let program_info = program_info_ref.borrow().clone(); + let mut lines_beyond_counter = program_info.address_to_line_number.len(); + let mut curr_value = text_model.get_value().to_owned(); + let mut add_new_lines = false; + for line in changed_lines { + // Check if we're updating or appending instruction + if line.line_number < program_info.address_to_line_number.len() { + let updated_line = program_info.address_to_line_number[line.line_number] as f64 + 1.0; + let curr_model = text_model.as_ref(); + + // Get the current line's contents in the code editor + let line_to_replace = curr_model.get_line_content(updated_line); + // Create the range to replace + let mut start_line_column = 0.0; + let end_line_column = line_to_replace.len() as f64 + 2.0; + for (i, c) in line_to_replace.chars().enumerate() { + if c.is_alphanumeric() { + start_line_column = i as f64 + 1.0; + break; + } + } + let edit_range = monaco::sys::Range::new(updated_line, start_line_column, updated_line, end_line_column); + let before_cursor_state = monaco::sys::Selection::new(updated_line, start_line_column, updated_line,end_line_column); + // Create the edit operation using the range and new text + let edit_operations: monaco::sys::editor::IIdentifiedSingleEditOperation = Object::new().unchecked_into(); + edit_operations.set_range(&edit_range); + edit_operations.set_text(Some(&line.text)); + // Append it to JavaScript Array + let edit_operations_array = js_sys::Array::new(); + edit_operations_array.push(&edit_operations); + let before_cursor_state_array = js_sys::Array::new(); + before_cursor_state_array.push(&before_cursor_state); + // Do the edit! + curr_model.push_edit_operations(&before_cursor_state_array, &edit_operations_array, None); + } else if line.line_number == lines_beyond_counter { + // Append instruction + if !add_new_lines { + // If we've added new lines already, + // start adding new lines by getting a copy of the current text model to append to + add_new_lines = true; + curr_value = text_model.get_value(); + } + curr_value.push_str("\n"); + curr_value.push_str(&line.text); + lines_beyond_counter += 1; + } + } + if add_new_lines { + text_model.set_value(&curr_value); + } }, Err(err) => { debug!("Error updating memory: {}", err) } } - let hexdump = &datapath.memory.generate_formatted_hex(); + let hexdump = datapath.memory.generate_formatted_hex(); - memory_text_model.set_value(hexdump); + memory_text_model.set_value(&hexdump); // Update the parsed info for text and data segment views let (program_info, _) = parser(text_model.get_value()); diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index 4529ab819..106e8495b 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -55,7 +55,7 @@ pub trait Datapath { /// Retrieve all memory as-is. fn get_memory(&self) -> &Memory; - fn set_memory(&mut self, ptr: usize, data: Vec); + fn set_memory(&mut self, ptr: u64, data: u32); /// Returns if the datapath is in a "halted" or "stopped" state. This may /// be true in the case where an error had occurred previously. diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index bd6b18585..d9848ae3b 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -287,8 +287,8 @@ impl Datapath for MipsDatapath { &self.memory } - fn set_memory(&mut self, _ptr: usize, _data: Vec) { - todo!() + fn set_memory(&mut self, _ptr: u64, _data: u32) { + self.memory.store_word(_ptr, _data); } fn is_halted(&self) -> bool { diff --git a/src/emulation_core/mips/memory.rs b/src/emulation_core/mips/memory.rs index 5b4217a60..42a317aab 100644 --- a/src/emulation_core/mips/memory.rs +++ b/src/emulation_core/mips/memory.rs @@ -12,20 +12,20 @@ pub struct Memory { pub memory: Vec, } -#[derive(Clone, Debug, PartialEq)] -pub struct UpdatedLine { - pub text: String, - pub line_number: usize -} - -impl UpdatedLine { - pub fn new(text: String, line_number: usize) -> Self { - UpdatedLine { - text, - line_number - } - } -} +// #[derive(Clone, Debug, PartialEq)] +// pub struct UpdatedLine { +// pub text: String, +// pub line_number: usize +// } + +// impl UpdatedLine { +// pub fn new(text: String, line_number: usize) -> Self { +// UpdatedLine { +// text, +// line_number +// } +// } +// } impl Default for Memory { fn default() -> Self { @@ -128,44 +128,32 @@ impl Memory { Ok(result) } - pub fn parse_hexdump(&mut self, input: &str) -> Result, String> { - let mut words = Vec::new(); - for line in input.lines() { - let parts: Vec<&str> = line.split('\t').collect(); - for &part in &parts[2..6] { - let data = u32::from_str_radix(part, 16).map_err(|e| e.to_string())?; - words.push(data); - } - } - Ok(words) - } - - // Returns instructions that were updated with their string versions and line numbers - pub fn store_hexdump(&mut self, instructions: Vec) -> Result, String> { - let mut changed_lines: Vec = vec![]; - for (i, data) in instructions.iter().enumerate() { - let address = i as u64; - let line = match get_string_version(*data) { - Ok(string) => string, - Err(string) => string, - }; - let curr_word = match self.load_word(address * 4) { - Ok(data) => data, - Err(e) => { - debug!("{:?}", e); - 0 - } - }; - if curr_word != *data { - changed_lines.push(UpdatedLine::new(line, i)); - self.store_word(address * 4, *data)? - } - } - - Ok(changed_lines) - } - - pub fn generate_formatted_hex(&mut self) -> String { + // // Returns instructions that were updated with their string versions and line numbers + // pub fn store_hexdump(&mut self, instructions: Vec) -> Result, String> { + // let mut changed_lines: Vec = vec![]; + // for (i, data) in instructions.iter().enumerate() { + // let address = i as u64; + // let line = match get_string_version(*data) { + // Ok(string) => string, + // Err(string) => string, + // }; + // let curr_word = match self.load_word(address * 4) { + // Ok(data) => data, + // Err(e) => { + // debug!("{:?}", e); + // 0 + // } + // }; + // if curr_word != *data { + // changed_lines.push(UpdatedLine::new(line, i)); + // self.store_word(address * 4, *data)? + // } + // } + + // Ok(changed_lines) + // } + + pub fn generate_formatted_hex(&self) -> String { let iterator = MemoryIter::new(&self); let mut string: String = "".to_string(); diff --git a/src/ui/hex_editor/component.rs b/src/ui/hex_editor/component.rs index 819eb7574..0bbc72f26 100644 --- a/src/ui/hex_editor/component.rs +++ b/src/ui/hex_editor/component.rs @@ -33,6 +33,20 @@ pub struct HexEditorProps { pub instruction_num: UseStateHandle, } +#[derive(Clone, Debug, PartialEq)] +pub struct UpdatedLine { + pub text: String, + pub line_number: usize +} +impl UpdatedLine { + pub fn new(text: String, line_number: usize) -> Self { + UpdatedLine { + text, + line_number + } + } +} + #[function_component(HexEditor)] pub fn hex_editor(props: &HexEditorProps) -> Html { let editor_link = CodeEditorLink::new(); @@ -204,3 +218,15 @@ fn get_options() -> IStandaloneEditorConstructionOptions { options } + +pub fn parse_hexdump(input: &str) -> Result, String> { + let mut words = Vec::new(); + for line in input.lines() { + let parts: Vec<&str> = line.split('\t').collect(); + for &part in &parts[2..6] { + let data = u32::from_str_radix(part, 16).map_err(|e| e.to_string())?; + words.push(data); + } + } + Ok(words) +} \ No newline at end of file diff --git a/static/assembly_examples/data.asm b/static/assembly_examples/data.asm index c89613710..4f2ad3957 100644 --- a/static/assembly_examples/data.asm +++ b/static/assembly_examples/data.asm @@ -1,5 +1,7 @@ .text addi $t0, $zero, 300 +addi $t1, $zero, 340 +addi $t2, $zero, 380 syscall .data a_secret: .ascii "hi" From 747ee8a919c5b7f92fcf76e4017f577166be29cb Mon Sep 17 00:00:00 2001 From: Cay Date: Mon, 12 Feb 2024 21:27:22 -0500 Subject: [PATCH 048/355] Add input fields to all register types --- index.html | 6 +- src/bin/main.rs | 5 +- src/emulation_core/mips/datapath.rs | 4 +- src/emulation_core/mips/memory.rs | 17 -- src/ui/assembled_view/component.rs | 4 +- src/ui/console/component.rs | 35 +++- src/ui/footer/component.rs | 3 +- src/ui/regview/component.rs | 251 ++++++++++++++++++++++++---- static/styles/main.css | 26 ++- 9 files changed, 281 insertions(+), 70 deletions(-) diff --git a/index.html b/index.html index 05a930938..9fd7457b5 100644 --- a/index.html +++ b/index.html @@ -9,8 +9,8 @@ - @@ -18,7 +18,7 @@ - + SWIM diff --git a/src/bin/main.rs b/src/bin/main.rs index 03e525f9e..9ebb01539 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -37,7 +37,7 @@ use yew_hooks::prelude::*; // To load in the Fibonacci example, uncomment the CONTENT and fib_model lines // and comment the code, language, and text_model lines. IMPORTANT: // rename fib_model to text_model to have it work. -const CONTENT: &str = include_str!("../../static/assembly_examples/data.asm"); +const CONTENT: &str = include_str!("../../static/assembly_examples/floating_point.asm"); #[derive(Properties, Clone, PartialEq)] struct AppProps { @@ -77,6 +77,7 @@ fn app(props: &AppProps) -> Html { // Show input let show_input = use_state_eq(|| bool::default()); show_input.set(true); + let command = use_state_eq(|| String::from("(Test) Enter a string")); // Store the currently selected tabs in windows let console_active_tab = use_state_eq(FooterTabState::default); @@ -531,7 +532,7 @@ fn app(props: &AppProps) -> Html {
// Console -
+
// Right column diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index d9848ae3b..3215e2aea 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -51,7 +51,7 @@ use super::constants::*; use super::control_signals::{floating_point::*, *}; use super::datapath_signals::*; use super::instruction::*; -use super::{coprocessor::MipsFpCoprocessor, memory::Memory, registers::{GpRegisters, GpRegisterType}}; +use super::{coprocessor::MipsFpCoprocessor, memory::Memory, registers::GpRegisters}; use crate::emulation_core::architectures::DatapathRef; use crate::shims; use serde::{Deserialize, Serialize}; @@ -288,7 +288,7 @@ impl Datapath for MipsDatapath { } fn set_memory(&mut self, _ptr: u64, _data: u32) { - self.memory.store_word(_ptr, _data); + self.memory.store_word(_ptr, _data).unwrap_or_default(); } fn is_halted(&self) -> bool { diff --git a/src/emulation_core/mips/memory.rs b/src/emulation_core/mips/memory.rs index 42a317aab..6f3be6ab8 100644 --- a/src/emulation_core/mips/memory.rs +++ b/src/emulation_core/mips/memory.rs @@ -3,8 +3,6 @@ use serde::{Deserialize, Serialize}; // pub const CAPACITY_BYTES: usize = 2^12; // 4KB -use log::debug; -use super::instruction::get_string_version; pub const CAPACITY_BYTES: usize = 64 * 1024; // 64 KB #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -12,21 +10,6 @@ pub struct Memory { pub memory: Vec, } -// #[derive(Clone, Debug, PartialEq)] -// pub struct UpdatedLine { -// pub text: String, -// pub line_number: usize -// } - -// impl UpdatedLine { -// pub fn new(text: String, line_number: usize) -> Self { -// UpdatedLine { -// text, -// line_number -// } -// } -// } - impl Default for Memory { fn default() -> Self { Self { diff --git a/src/ui/assembled_view/component.rs b/src/ui/assembled_view/component.rs index a4ac3a3fd..bef4bfc46 100644 --- a/src/ui/assembled_view/component.rs +++ b/src/ui/assembled_view/component.rs @@ -82,7 +82,7 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html { let editor_active_tab = editor_active_tab.clone(); use_callback(move |args: (MouseEvent, usize), _| { let (_e, line_number) = args; - editor_curr_line.set(line_number as f64); + editor_curr_line.set(line_number as f64 + 1.0); editor_active_tab.set(EditorTabState::Editor); }, ()) }; @@ -112,7 +112,7 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html { let mut conditional_class = ""; if props.pc as i64 == address + 4 { - conditional_class = "executedLine"; + conditional_class = "executing"; html!{
- + } }) .collect::() } -pub fn generate_gpr_rows_bin(gp: GpRegisters) -> Html { - gp.into_iter() +pub fn generate_gpr_rows_bin(props: &Regviewprops) -> Html { + let communicator = props.communicator; + let pc_limit = props.pc_limit; + + props.gp.into_iter() .map(|(register, data)| { html! { - + } }) .collect::() } -pub fn generate_fpr_rows(fp: [u64; 32]) -> Html { - fp.iter() + +// ============= Coprocessor Registers ============= +pub fn generate_fpr_rows(props: &Regviewprops) -> Html { + // let communicator = props.communicator; + + props.fp.iter() .enumerate() .map(|(register, data)| { html! { - + } }) .collect::() } -pub fn generate_fpr_rows_hex(fp: [u64; 32]) -> Html { - fp.iter() +pub fn generate_fpr_rows_hex(props: &Regviewprops) -> Html { + // let communicator = props.communicator; + + props.fp.iter() .enumerate() .map(|(register, data)| { html! { - + } }) .collect::() } -pub fn generate_fpr_rows_bin(fp: [u64; 32]) -> Html { - fp.iter() +pub fn generate_fpr_rows_bin(props: &Regviewprops) -> Html { + // let communicator = props.communicator; + + props.fp.iter() .enumerate() .map(|(register, data)| { html! { - + } }) .collect::() } -pub fn generate_fpr_rows_float(fp: [u64; 32]) -> Html { - fp.iter() +pub fn generate_fpr_rows_float(props: &Regviewprops) -> Html { + // let communicator = props.communicator; + + props.fp.iter() .enumerate() .map(|(register, data)| { html! { - + } }) .collect::() } -pub fn generate_fpr_rows_double(fp: [u64; 32]) -> Html { - fp.iter() +pub fn generate_fpr_rows_double(props: &Regviewprops) -> Html { + // let communicator = props.communicator; + + props.fp.iter() .enumerate() .map(|(register, data)| { html! { - + } }) @@ -232,9 +423,9 @@ pub fn regview(props: &Regviewprops) -> Html { UnitState::Double => "Double" } }> - - + + if !*switch_flag { @@ -252,24 +443,24 @@ pub fn regview(props: &Regviewprops) -> Html { if *switch_flag{ if *active_view == UnitState::Bin { - {generate_gpr_rows_bin(props.gp)} + {generate_gpr_rows_bin(&props)} } else if *active_view == UnitState::Hex { - {generate_gpr_rows_hex(props.gp)} + {generate_gpr_rows_hex(&props)} } else { {generate_gpr_rows(&props)} } } else { if *active_view == UnitState::Bin { - {generate_fpr_rows_bin(props.fp)} + {generate_fpr_rows_bin(&props)} } else if *active_view == UnitState::Hex{ - {generate_fpr_rows_hex(props.fp)} + {generate_fpr_rows_hex(&props)} } else if *active_view == UnitState::Float{ - {generate_fpr_rows_float(props.fp)} + {generate_fpr_rows_float(&props)} } else if *active_view == UnitState::Double{ - {generate_fpr_rows_double(props.fp)} + {generate_fpr_rows_double(&props)} } else if *active_view == UnitState::Dec { - {generate_fpr_rows(props.fp)} + {generate_fpr_rows(&props)} } } diff --git a/static/styles/main.css b/static/styles/main.css index e1c4eeaee..f98a1660d 100644 --- a/static/styles/main.css +++ b/static/styles/main.css @@ -114,7 +114,8 @@ body { } .executing { - color:rgb(49, 212, 144); + background-color:rgb(0 160 93 / 17%); + box-shadow: inset 0px 0px 20px 0px #12ff77; } .assembled-string { @@ -174,6 +175,7 @@ body { padding-left: 25px; min-height: max(20%, 8em); max-height: 50%; + z-index: 1; } .console-input { @@ -182,13 +184,18 @@ body { flex-direction: row; color: white; position: relative; + width: 100%; +} + +.console-input .command { + margin-left: 25px; } .console-input input { - width: 100%; background: #012456; color: white !important; - margin-left: 25px; + margin-left: 10px; + outline: none; } .console-arrow { @@ -206,6 +213,7 @@ body { word-break: break-all; min-height: max(20%, 8em); max-height: 50%; + z-index: 1; } .memory-view { @@ -219,6 +227,7 @@ body { width: 100%; flex-basis: 50%; background-color: #FFF; + z-index: 1; } .button-bar { @@ -278,7 +287,14 @@ table { overflow-y: auto; color: #fff; } -tr:nth-child(even) +tr { + background-color: #1e1e1e; + input { + + background-color: #1e1e1e; + } +} +/* tr:nth-child(even) { background-color: #1e1e1e; input { @@ -293,7 +309,7 @@ tr:nth-child(odd) background-color: #101010; } -} +} */ td:nth-child(2) { font-family: 'Iosevka', 'Droid Sans Mono', 'Consolas', monospace; From 1a3978205d2b8e5655522734b5e8d3161d3236b6 Mon Sep 17 00:00:00 2001 From: rharding8 Date: Wed, 14 Feb 2024 15:15:05 -0500 Subject: [PATCH 049/355] Added branching and jumping logic. Fixed some typos. datapath.rs is error-free, but must be expanded with RV64I and more. --- src/emulation_core/riscv/datapath.rs | 52 +++++++++++++++------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/src/emulation_core/riscv/datapath.rs b/src/emulation_core/riscv/datapath.rs index 2bd6d21d4..d43fbc62e 100644 --- a/src/emulation_core/riscv/datapath.rs +++ b/src/emulation_core/riscv/datapath.rs @@ -46,8 +46,6 @@ //! setting the boolean flag `is_halted`. //! - Invalid instructions will cause the datapath to set the `is_halted` flag. -use crate::tests::emulation_core::mips::add; - use super::super::datapath::Datapath; use super::constants::*; use super::control_signals::*; @@ -318,9 +316,6 @@ impl RiscDatapath { self.set_immediate(); self.read_registers(); - // Upper part of datapath, PC calculation - self.construct_jump_address(); - /* Finish this instruction out of the datapath and halt if this is a syscall. if let Instruction::SyscallType(_) = self.instruction { self.is_halted = true; @@ -488,7 +483,7 @@ impl RiscDatapath { } }; - if (self.signals.imm_select == ImmSelect::IUnsigned) { + if self.signals.imm_select == ImmSelect::IUnsigned { signed_imm = signed_imm & 0x00000fff; } @@ -570,7 +565,7 @@ impl RiscDatapath { 3 => self.signals.alu_op = AluOp::SetOnLessThanUnsigned, 4 => self.signals.alu_op = AluOp::Xor, 5 => { - match (i.imm >> 5) { + match i.imm >> 5 { 0b0000000 => self.signals.alu_op = AluOp::ShiftRightLogical(self.state.shamt), 0b0100000 => self.signals.alu_op = AluOp::ShiftRightArithmetic(self.state.shamt), }; @@ -665,11 +660,6 @@ impl RiscDatapath { self.state.read_data_2 = self.registers.gpr[self.state.rs2 as usize]; } - fn construct_jump_address(&mut self) { - self.state.jump_address = (self.state.pc_plus_4 & 0xffff_ffff_f000_0000) - | self.state.lower_26_shifted_left_by_2 as u64; - } - // ======================= Execute (EX) ======================= /// Perform an ALU operation. /// @@ -677,7 +667,7 @@ impl RiscDatapath { /// does not handle exceptions due to integer overflow. fn alu(&mut self) { // Left shift the immediate value based on the ImmShift control signal. - let alu_immediate = self.state.sign_extend; + let alu_immediate = self.state.imm; // Specify the inputs for the operation. The first will always // be the first register, but the second may be either the @@ -730,6 +720,10 @@ impl RiscDatapath { _ => 0, }; + if self.signals.branch_jump == BranchJump::J { + self.construct_jump_address(); + } + // Set the zero bit/signal. self.datapath_signals.alu_z = match self.state.alu_result { 0 => AluZ::YesZero, @@ -737,12 +731,16 @@ impl RiscDatapath { }; } + fn construct_jump_address(&mut self) { + self.state.rd = self.state.pc_plus_4 as u32; + self.state.jump_address = match self.state.instruction { + IType => (self.state.imm as u64 + self.state.read_data_1) & 0xfffffffffffffff0, + JType => self.state.imm as u64 + self.registers.pc, + } + } + fn calc_relative_pc_branch(&mut self) { - self.state.sign_extend_shift_left_by_2 = self.state.sign_extend << 2; - self.state.relative_pc_branch = self - .state - .sign_extend_shift_left_by_2 - .wrapping_add(self.state.pc_plus_4); + self.state.relative_pc_branch = ((self.state.imm & 0x00000fff) as u64) + self.registers.pc; } /// Determine the value of the [`CpuBranch`] signal. @@ -758,11 +756,16 @@ impl RiscDatapath { // Depending on the branch type, this may use the ALU's Zero signal // as-is or inverted. let condition_is_true = match self.signals.branch_jump { - BranchJump::Beq => self.datapath_signals.alu_z == AluZ::YesZero, - _ => self.datapath_signals.alu_z == AluZ::NoZero, + BranchJump::Beq => self.state.read_data_1 == self.state.read_data_2, + BranchJump::Bne => self.state.read_data_1 != self.state.read_data_2, + BranchJump::Bge => self.state.read_data_1 as i64 >= self.state.read_data_2 as i64, + BranchJump::Bgeu => self.state.read_data_1 as u64 >= self.state.read_data_2 as u64, + BranchJump::Blt => (self.state.read_data_1 as i64) < (self.state.read_data_2 as i64), + BranchJump::Bltu => (self.state.read_data_1 as u64) < (self.state.read_data_2 as u64), + _ => false, }; - if self.signals.branch_jump != BranchJump::NoBranch && condition_is_true { + if condition_is_true { self.datapath_signals.cpu_branch = CpuBranch::YesBranch; } } @@ -832,10 +835,9 @@ impl RiscDatapath { } fn set_new_pc_mux2(&mut self) { - self.state.new_pc = match self.signals.jump { - Jump::NoJump => self.state.mem_mux1_to_mem_mux2, - Jump::YesJump => self.state.jump_address, - Jump::YesJumpJalr => self.state.read_data_1, + self.state.new_pc = match self.signals.branch_jump { + BranchJump::J => self.state.jump_address, + _ => self.state.mem_mux1_to_mem_mux2, }; } From 5e6c3c65b98d6cb84300254874fc13eac01469f1 Mon Sep 17 00:00:00 2001 From: Geetis <59862178+Geetis@users.noreply.github.com> Date: Fri, 16 Feb 2024 14:46:26 -0500 Subject: [PATCH 050/355] Instruction encoding for all targeted extensions --- src/parser/assembling.rs | 13 +- src/parser/parser_assembler_main.rs | 3236 ++++++++++++++++++++++- static/assembly_examples/riscv_test.asm | 5 +- 3 files changed, 3172 insertions(+), 82 deletions(-) diff --git a/src/parser/assembling.rs b/src/parser/assembling.rs index 3ecef308d..065bec1f7 100644 --- a/src/parser/assembling.rs +++ b/src/parser/assembling.rs @@ -194,7 +194,8 @@ pub fn read_operands_riscv( expected_operands: Vec, concat_order: Vec, labels_option: Option>, - funct3: Option + funct3: Option, + fmt: Option ) -> &mut Instruction { //if the number of operands in the instruction does not match the expected number, there is an error if instruction.operands.len() != expected_operands.len() { @@ -302,7 +303,7 @@ pub fn read_operands_riscv( instruction.operands[i].token_type = TokenType::RegisterFP; bit_lengths.push(5); - let register_results = read_register( + let register_results = read_register_riscv( &instruction.operands[i].token_name, instruction.operands[i].start_end_columns, FloatingPoint, @@ -367,9 +368,13 @@ pub fn read_operands_riscv( binary_representation[element - 1], bit_lengths[element - 1], ); - if index == 1 && funct3.is_some() // Set funct3 value before the final argument + if index == concat_order.len() - 2 && funct3.is_some() // Set funct3 value before the final argument + { + instruction.binary = append_binary(instruction.binary, funct3.unwrap_or(0), 3) + } + else if index == 0 && fmt.is_some() { - instruction.binary = append_binary(instruction.binary, funct3.unwrap_or(0), 3) // Shift amount may need to be adjusted using function argument + instruction.binary = append_binary(instruction.binary, fmt.unwrap_or(0), 2) } } diff --git a/src/parser/parser_assembler_main.rs b/src/parser/parser_assembler_main.rs index 0b6db0a39..c8bba9499 100644 --- a/src/parser/parser_assembler_main.rs +++ b/src/parser/parser_assembler_main.rs @@ -1572,7 +1572,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, RegisterGP, RegisterGP], vec![1, 2, 3], None, - Some(0b000) + Some(0b000), + None ); // Opcode @@ -1604,7 +1605,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, RegisterGP, RegisterGP], vec![1, 2, 3], None, - Some(0b000) + Some(0b000), + None ); // Opcode @@ -1636,7 +1638,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, RegisterGP, RegisterGP], vec![1, 2, 3], None, - Some(0b001) + Some(0b001), + None ); // Opcode @@ -1668,7 +1671,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, RegisterGP, RegisterGP], vec![1, 2, 3], None, - Some(0b010) + Some(0b010), + None ); // Opcode @@ -1700,7 +1704,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, RegisterGP, RegisterGP], vec![1, 2, 3], None, - Some(0b011) + Some(0b011), + None ); // Opcode @@ -1732,7 +1737,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, RegisterGP, RegisterGP], vec![1, 2, 3], None, - Some(0b100) + Some(0b100), + None ); // Opcode @@ -1764,7 +1770,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, RegisterGP, RegisterGP], vec![1, 2, 3], None, - Some(0b101) + Some(0b101), + None ); // Opcode @@ -1796,7 +1803,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, RegisterGP, RegisterGP], vec![1, 2, 3], None, - Some(0b101) + Some(0b101), + None ); // Opcode @@ -1828,7 +1836,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, RegisterGP, RegisterGP], vec![1, 2, 3], None, - Some(0b110) + Some(0b110), + None ); // Opcode @@ -1860,7 +1869,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, RegisterGP, RegisterGP], vec![1, 2, 3], None, - Some(0b111) + Some(0b111), + None ); // Opcode @@ -1888,7 +1898,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, RegisterGP, Immediate], vec![1, 2, 3], None, - Some(0) + Some(0), + None ); // Opcode @@ -1916,7 +1927,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, RegisterGP, Immediate], vec![1, 2, 3], None, - Some(0b010) + Some(0b010), + None ); // Opcode @@ -1944,7 +1956,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, RegisterGP, Immediate], vec![1, 2, 3], None, - Some(0b011) + Some(0b011), + None ); // Opcode @@ -1972,7 +1985,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, RegisterGP, Immediate], vec![1, 2, 3], None, - Some(0b100) + Some(0b100), + None ); // Opcode @@ -2000,7 +2014,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, RegisterGP, Immediate], vec![1, 2, 3], None, - Some(0b110) + Some(0b110), + None ); // Opcode @@ -2028,7 +2043,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, RegisterGP, Immediate], vec![1, 2, 3], None, - Some(0b111) + Some(0b111), + None ); // Opcode @@ -2059,7 +2075,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, RegisterGP, ShiftAmount], vec![1, 2, 3], None, - Some(0b001) + Some(0b001), + None ); // Opcode @@ -2090,7 +2107,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, RegisterGP, ShiftAmount], vec![1, 2, 3], None, - Some(0b101) + Some(0b101), + None ); // Opcode @@ -2121,7 +2139,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, RegisterGP, ShiftAmount], vec![1, 2, 3], None, - Some(0b101) + Some(0b101), + None ); // Opcode @@ -2149,7 +2168,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, MemoryAddress], vec![1, 3, 2], None, - Some(0b000) + Some(0b000), + None ); // Opcode @@ -2177,7 +2197,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, MemoryAddress], vec![1, 3, 2], None, - Some(0b001) + Some(0b001), + None ); // Opcode @@ -2205,7 +2226,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, MemoryAddress], vec![1, 3, 2], None, - Some(0b010) + Some(0b010), + None ); // Opcode @@ -2233,7 +2255,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, MemoryAddress], vec![1, 3, 2], None, - Some(0b100) + Some(0b100), + None ); // Opcode @@ -2261,7 +2284,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, MemoryAddress], vec![1, 3, 2], None, - Some(0b101) + Some(0b101), + None ); // Opcode @@ -2289,7 +2313,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, MemoryAddress], vec![1, 3, 2], None, - Some(0b000) + Some(0b000), + None ); // Opcode @@ -2321,7 +2346,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, MemoryAddress], vec![1, 3, 2], None, - Some(0b001) + Some(0b001), + None ); // Opcode @@ -2353,7 +2379,8 @@ pub fn read_instructions_riscv( vec![RegisterGP, MemoryAddress], vec![1, 3, 2], None, - Some(0b010) + Some(0b010), + None ); // Opcode @@ -2376,16 +2403,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "jal" => + "jal" => // Finish J instructions { log!("jal instruction"); log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + // Read as U-type instruction and reorder immediate value after read_operands_riscv( instruction, vec![RegisterGP, UpperImmediate], vec![1, 2], None, + None, None ); @@ -2394,6 +2423,8 @@ pub fn read_instructions_riscv( log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); // Reorder immediate + instruction.binary = upper_to_jump(instruction.binary); + log!("3. Reordered Binary: ", format!("{:032b}", instruction.binary)); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2407,20 +2438,21 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "lui" => + "jalr" => { log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); read_operands_riscv( instruction, - vec![RegisterGP, UpperImmediate], - vec![1, 2], + vec![RegisterGP, MemoryAddress], + vec![1, 3, 2], None, + Some(0b000), None ); // Opcode - instruction.binary = append_binary(instruction.binary, 0b0110111, 7); + instruction.binary = append_binary(instruction.binary, 0b1100111, 7); log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb @@ -2429,86 +2461,3140 @@ pub fn read_instructions_riscv( .is_empty() { let info = InstructionDescription{ - syntax: "lui rd, imm".to_string(), - description: "Build 32-bit constants and uses the U-type format. LUI places the U-immediate value in the top 20 bits of the destination register rd, filling in the lowest 12 bits with zeros.".to_string(), + syntax: "jalr rd, rs1, offset".to_string(), + description: "Jump to address and place return address in rd.".to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "auipc" => + "beq" => { - log!("auipc instruction"); log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); read_operands_riscv( instruction, - vec![RegisterGP, UpperImmediate], - vec![1, 2], + vec![RegisterGP, RegisterGP, Immediate], + vec![1, 2, 3], None, + Some(0b000), None ); // Opcode - instruction.binary = append_binary(instruction.binary, 0b0010111, 7); + instruction.binary = append_binary(instruction.binary, 0b1100011, 7); log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + instruction.binary = immediate_to_branch(instruction.binary); + log!("3. Reordered Binary: ", format!("{:032b}", instruction.binary)); + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] .mouse_hover_string .is_empty() { let info = InstructionDescription{ - syntax: "auipc rd, imm".to_string(), - description: "Build pc-relative addresses and uses the U-type format.\n\nAUIPC forms a 32-bit offset from the 20-bit U-immediate, filling in the lowest 12 bits with zeros, adds this offset to the pc, then places the result in register rd.".to_string(), + syntax: "beq rs1, rs2, offset".to_string(), + description: "Take the branch if registers rs1 and rs2 are equal.".to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - _ => + "bne" => { - if UNSUPPORTED_INSTRUCTIONS.contains(&&*instruction.operator.token_name) { - instruction.errors.push(Error { - error_name: UnsupportedInstruction, - token_causing_error: instruction.operator.token_name.to_string(), - start_end_columns: instruction.operator.start_end_columns, - message: "\n\n".to_string(), - }) - } else { - instruction.errors.push(Error { - error_name: UnrecognizedInstruction, - token_causing_error: instruction.operator.token_name.clone(), - start_end_columns: instruction.operator.start_end_columns, - message: "\n\n".to_string(), - }); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, Immediate], + vec![1, 2, 3], + None, + Some(0b001), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1100011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + instruction.binary = immediate_to_branch(instruction.binary); + log!("3. Reordered Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "bne rs1, rs2, offset".to_string(), + description: "Take the branch if registers rs1 and rs2 are not equal.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - } - } -} + "blt" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); -// Reorder store instruction to the correct format -fn immediate_to_stored(mut bin: u32) -> u32 -{ - // Extract bits 24-20 from the first segment - let lower_imm = (bin >> 20) & 0b11111; + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, Immediate], + vec![1, 2, 3], + None, + Some(0b100), + None + ); - // Extract bits 11-7 from the second segment - let rs2 = (bin >> 7) & 0b11111; + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1100011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); - log!("Bits to move (24-20): ", format!("{:05b}", lower_imm)); - log!("Bits to move (11-7): ", format!("{:05b}", rs2)); + instruction.binary = immediate_to_branch(instruction.binary); + log!("3. Reordered Binary: ", format!("{:032b}", instruction.binary)); - // Clear bits 24-20 and 11-7 - bin &= !((0b11111 << 20) | (0b11111 << 6)); + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "blt rs1, rs2, offset".to_string(), + description: "Take the branch if registers rs1 is less than rs2, using signed comparison.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "bge" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); - log!("Cleared bits: ", format!("{:032b}", bin)); + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, Immediate], + vec![1, 2, 3], + None, + Some(0b101), + None + ); - // Move bits 24-20 to positions 11-7 - let moved_imm = lower_imm << 7; + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1100011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); - // Move bits 11-7 to positions 24-20 - let moved_rs2 = rs2 << 20; + instruction.binary = immediate_to_branch(instruction.binary); + log!("3. Reordered Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "bge rs1, rs2, offset".to_string(), + description: "Take the branch if registers rs1 is greater than or equal to rs2, using signed comparison.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "bltu" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, Immediate], + vec![1, 2, 3], + None, + Some(0b110), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1100011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + instruction.binary = immediate_to_branch(instruction.binary); + log!("3. Reordered Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "bltu rs1, rs2, offset".to_string(), + description: "Take the branch if registers rs1 is less than rs2, using unsigned comparison.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "bgeu" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, Immediate], + vec![1, 2, 3], + None, + Some(0b111), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1100011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + instruction.binary = immediate_to_branch(instruction.binary); + log!("3. Reordered Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "bgeu rs1, rs2, offset".to_string(), + description: "Take the branch if registers rs1 is greater than or equal to rs2, using unsigned comparison.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "ecall" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // ecall instruction encoding does not change + instruction.binary = 0b00000000000000000000000001110011; + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "ecall".to_string(), + description: "Make a request to the supporting execution environment.\n\nWhen executed in U-mode, S-mode, or M-mode, it generates an environment-call-from-U-mode exception, environment-call-from-S-mode exception, or environment-call-from-M-mode exception, respectively, and performs no other operation.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "ebreak" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // ebreak instruction encoding does not change + instruction.binary = 0b00000000000100000000000001110011; + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "ebreak".to_string(), + description: "Used by debuggers to cause control to be transferred back to a debugging environment.\n\nIt generates a breakpoint exception and performs no other operation.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "uret" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // uret instruction encoding does not change + instruction.binary = 0b00000000001000000000000001110011; + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "uret".to_string(), + description: "Return from traps in U-mode, and URET copies UPIE into UIE, then sets UPIE.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "sret" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // uret instruction encoding does not change + instruction.binary = 0b00010000001000000000000001110011; + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "uret".to_string(), + description: "Return from traps in U-mode, and URET copies UPIE into UIE, then sets UPIE.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "mret" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // uret instruction encoding does not change + instruction.binary = 0b00110000001000000000000001110011; + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "mret".to_string(), + description: "Return from traps in M-mode, and MRET copies MPIE into MIE, then sets MPIE.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "wfi" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // uret instruction encoding does not change + instruction.binary = 0b00010000010100000000000001110011; + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "wfi".to_string(), + description: "Provides a hint to the implementation that the current hart can be stalled until an interrupt might need servicing.\n\nExecution of the WFI instruction can also be used to inform the hardware platform that suitable interrupts should preferentially be routed to this hart.\n\nWFI is available in all privileged modes, and optionally available to U-mode.\n\nThis instruction may raise an illegal instruction exception when TW=1 in mstatus.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fence.i" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // fence.i instruction encoding does not change + instruction.binary = 0b00000000000000000001000000001111; + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fence.i".to_string(), + description: "Provides explicit synchronization between writes to instruction memory and instruction fetches on the same hart.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "lui" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, UpperImmediate], + vec![1, 2], + None, + None, + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0110111, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "lui rd, imm".to_string(), + description: "Build 32-bit constants and uses the U-type format. LUI places the U-immediate value in the top 20 bits of the destination register rd, filling in the lowest 12 bits with zeros.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "auipc" => + { + log!("auipc instruction"); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, UpperImmediate], + vec![1, 2], + None, + None, + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0010111, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "auipc rd, imm".to_string(), + description: "Build pc-relative addresses and uses the U-type format.\n\nAUIPC forms a 32-bit offset from the 20-bit U-immediate, filling in the lowest 12 bits with zeros, adds this offset to the pc, then places the result in register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "addiw" => // Start of RV64I Instructions + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, Immediate], + vec![1, 2, 3], + None, + Some(0b000), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0011011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "addiw rd, rs1, imm".to_string(), + description: "Adds the sign-extended 12-bit immediate to register rs1 and produces the proper sign-extension of a 32-bit result in rd.\n\nOverflows are ignored and the result is the low 32 bits of the result sign-extended to 64 bits.\n\nNote, ADDIW rd, rs1, 0 writes the sign-extension of the lower 32 bits of register rs1 into register rd (assembler pseudoinstruction SEXT.W).".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "slliw" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000000, 7); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, ShiftAmount], + vec![1, 2, 3], + None, + Some(0b001), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0011011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "slliw rd, rs1, shamt".to_string(), + description: "Performs logical left shift on the 32-bit of value in register rs1 by the shift amount held in the lower 5 bits of the immediate.\n\nEncodings with $imm[5] neq 0$ are reserved.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "srliw" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000000, 7); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, ShiftAmount], + vec![1, 2, 3], + None, + Some(0b101), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0011011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "srliw rd, rs1, shamt".to_string(), + description: "Performs logical right shift on the 32-bit of value in register rs1 by the shift amount held in the lower 5 bits of the immediate.\n\nEncodings with $imm[5] neq 0$ are reserved.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "sraiw" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b01000, 7); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, ShiftAmount], + vec![1, 2, 3], + None, + Some(0b101), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0011011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "sraiw rd, rs1, shamt".to_string(), + description: "Performs arithmetic right shift on the 32-bit of value in register rs1 by the shift amount held in the lower 5 bits of the immediate.\n\nEncodings with $imm[5] neq 0$ are reserved.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "addw" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000000, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b000), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0111011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "addw rd, rs1, rs2".to_string(), + description: "Adds the 32-bit of registers rs1 and 32-bit of register rs2 and stores the result in rd.\n\nArithmetic overflow is ignored and the low 32-bits of the result is sign-extended to 64-bits and written to the destination register.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "subw" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0100000, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b000), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0111011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "subw rd, rs1, rs2".to_string(), + description: "Subtract the 32-bit of registers rs1 and 32-bit of register rs2 and stores the result in rd.\n\nArithmetic overflow is ignored and the low 32-bits of the result is sign-extended to 64-bits and written to the destination register.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "sllw" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000000, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b001), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0111011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "sllw rd, rs1, rs2".to_string(), + description: "Performs logical left shift on the low 32-bits value in register rs1 by the shift amount held in the lower 5 bits of register rs2 and produce 32-bit results and written to the destination register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "srlw" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000000, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b101), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0111011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "srlw rd, rs1, rs2".to_string(), + description: "Performs logical right shift on the low 32-bits value in register rs1 by the shift amount held in the lower 5 bits of register rs2 and produce 32-bit results and written to the destination register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "sraw" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0100000, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b101), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0111011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "sraw rd, rs1, rs2".to_string(), + description: "Performs arithmetic right shift on the low 32-bits value in register rs1 by the shift amount held in the lower 5 bits of register rs2 and produce 32-bit results and written to the destination register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "lwu" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, MemoryAddress], + vec![1, 3, 2], + None, + Some(0b110), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0000011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "lwu rd, offset(rs1)".to_string(), + description: "Loads a 32-bit value from memory and zero-extends this to 64 bits before storing it in register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "ld" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, MemoryAddress], + vec![1, 3, 2], + None, + Some(0b011), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0000011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "ld rd, offset(rs1)".to_string(), + description: "Loads a 64-bit value from memory into register rd for RV64I.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "sd" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, MemoryAddress], + vec![1, 3, 2], + None, + Some(0b011), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0100011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Encoded as I-type, but needs reordering for S-type + instruction.binary = immediate_to_stored(instruction.binary); + log!("3. Reordered: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "sd rs2, offset(rs1)".to_string(), + description: "Store 64-bit, values from register rs2 to memory.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "mul" => // Start of RV32M + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000001, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b000), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0110011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "mul rd, rs1, rs2".to_string(), + description: "Performs an XLEN-bit * XLEN-bit multiplication of signed rs1 by signed rs2 and places the lower XLEN bits in the destination register.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "mulh" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000001, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b001), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0110011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "mulh rd, rs1, rs2".to_string(), + description: "Performs an XLEN-bit * XLEN-bit multiplication of signed rs1 by signed rs2 and places the upper XLEN bits in the destination register. + ".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "mulhsu" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000001, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b010), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0110011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "mulhsu rd, rs1, rs2".to_string(), + description: "Performs an XLEN-bit * XLEN-bit multiplication of signed rs1 by unsigned rs2 and places the upper XLEN bits in the destination register.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "mulhu" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000001, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b011), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0110011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "mulhu rd, rs1, rs2".to_string(), + description: "Performs an XLEN-bit * XLEN-bit multiplication of unsigned rs1 by unsigned rs2 and places the upper XLEN bits in the destination register.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "div" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000001, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b100), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0110011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "div rd, rs1, rs2".to_string(), + description: "Perform an XLEN bits by XLEN bits signed integer division of rs1 by rs2, rounding towards zero.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "divu" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000001, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b101), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0110011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "divu rd, rs1, rs2".to_string(), + description: "Perform an XLEN bits by XLEN bits unsigned integer division of rs1 by rs2, rounding towards zero.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "rem" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000001, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b110), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0110011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "rem rd, rs1, rs2".to_string(), + description: "Perform an XLEN bits by XLEN bits signed integer remainder of rs1 by rs2.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "remu" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000001, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b111), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0110011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "remu rd, rs1, rs2".to_string(), + description: "Perform an XLEN bits by XLEN bits unsigned integer remainder of rs1 by rs2.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "mulw" => // Start of RV64M + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000001, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b000), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0111011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "mulw rd, rs1, rs2".to_string(), + description: "Multiplies the lower 32 bits of the source registers, placing the sign-extension of the lower 32 bits of the result into the destination register.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "divw" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000001, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b100), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0111011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "divw rd, rs1, rs2".to_string(), + description: "Perform an XLEN bits by XLEN bits signed integer division of rs1 by rs2.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "divuw" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000001, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b101), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0111011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "divuw rd, rs1, rs2".to_string(), + description: "Perform an XLEN bits by XLEN bits unsigned integer division of rs1 by rs2.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "remw" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000001, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b110), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0111011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "remw rd, rs1, rs2".to_string(), + description: "Perform an XLEN bits by XLEN bits signed integer remainder of rs1 by rs2.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "remuw" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct7 + instruction.binary = append_binary(instruction.binary, 0b0000001, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterGP, RegisterGP], + vec![1, 2, 3], + None, + Some(0b111), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0111011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "remuw rd, rs1, rs2".to_string(), + description: "Perform an XLEN bits by XLEN bits unsigned integer reminder of rs1 by rs2.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fmadd.s" => // Start of RV32F + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3, 4], + None, + Some(0b111), // This funct3 is used for the rm value + Some(0b00) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1000011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fmadd.s rd, rs1, rs2, rs3".to_string(), + description: "Multiplies the values in rs1 and rs2, adds the value in rs3, and writes the final result to rd.\n\nFMADD.S computes (rs1 * rs2) + rs3".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fmsub.s" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3, 4], + None, + Some(0b111), // This funct3 is used for the rm value + Some(0b00) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1000111, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fmsub.s rd, rs1, rs2, rs3".to_string(), + description: "Multiplies the values in rs1 and rs2, subtracts the value in rs3, and writes the final result to rd.\n\nFMSUB.S computes (rs1×rs2) - rs3.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fnmsub.s" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3, 4], + None, + Some(0b111), // This funct3 is used for the rm value + Some(0b00) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1001011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fnmsub.s rd, rs1, rs2, rs3".to_string(), + description: "Multiplies the values in rs1 and rs2, negates the product, adds the value in rs3, and writes the final result to rd.\n\nFNMSUB.S computes -(rs1 * rs2) + rs3.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fnmadd.s" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3, 4], + None, + Some(0b111), // This funct3 is used for the rm value + Some(0b00) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1001111, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fnmadd.s rd, rs1, rs2, rs3".to_string(), + description: "multiplies the values in rs1 and rs2, negates the product, subtracts the value in rs3, and writes the final result to rd.\n\nFNMADD.S computes -(rs1 * rs2) - rs3.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fadd.s" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b0000000, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fadd.s rd, rs1, rs2".to_string(), + description: "Perform single-precision floating-point addition.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fsub.s" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b0000100, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fsub.s rd, rs1, rs2".to_string(), + description: "Perform single-precision floating-point substraction.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fmul.s" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b0001000, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fmul.s rd, rs1, rs2".to_string(), + description: "Perform single-precision floating-point multiplication.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fdiv.s" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b0001100, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fdiv.s rd, rs1, rs2".to_string(), + description: "Perform single-precision floating-point division.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fsqrt.s" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + padding for absent register + instruction.binary = append_binary(instruction.binary, 0b010110000000, 12); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP], + vec![1, 2], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fsqrt.s rd, rs1".to_string(), + description: "Perform single-precision square root.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fsgnj.s" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b0010000, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b000), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fsgnj.s rd, rs1, rs2".to_string(), + description: "Produce a result that takes all bits except the sign bit from rs1.\n\nThe result's sign bit is rs2's sign bit.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fsgnjn.s" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b0010000, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b001), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fsgnjn.s rd, rs1, rs2".to_string(), + description: "Produce a result that takes all bits except the sign bit from rs1.\n\nThe result's sign bit is opposite of rs2's sign bit.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fsgnjx.s" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b0010000, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b010), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fsgnjx.s rd, rs1, rs2".to_string(), + description: "Produce a result that takes all bits except the sign bit from rs1.\n\nThe result's sign bit is XOR of sign bit of rs1 and rs2.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fmin.s" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b0010100, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b000), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fmin.s rd, rs1, rs2".to_string(), + description: "Write the smaller of single precision data in rs1 and rs2 to rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fmax.s" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b0010100, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b001), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fmax.s rd, rs1, rs2".to_string(), + description: "Write the larger of single precision data in rs1 and rs2 to rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fcvt.w.s" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + padding for absent register + instruction.binary = append_binary(instruction.binary, 0b110000000000, 12); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterFP], + vec![1, 2], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fcvt.w.s rd, rs1".to_string(), + description: "Convert a floating-point number in floating-point register rs1 to a signed 32-bit in integer register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fcvt.wu.s" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + rs2 + instruction.binary = append_binary(instruction.binary, 0b110000000001, 12); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterFP], + vec![1, 2], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fcvt.wu.s rd, rs1".to_string(), + description: "Convert a floating-point number in floating-point register rs1 to a signed 32-bit in unsigned integer register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fmv.x.w" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + rs2 + instruction.binary = append_binary(instruction.binary, 0b111000000000, 12); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterFP], + vec![1, 2], + None, + Some(0b000), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fmv.x.w rd, rs1".to_string(), + description: "Move the single-precision value in floating-point register rs1 represented in IEEE 754-2008 encoding to the lower 32 bits of integer register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "feq.s" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b1010000, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b010), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "feq.s rd, rs1, rs2".to_string(), + description: "Performs a quiet equal comparison between floating-point registers rs1 and rs2 and record the Boolean result in integer register rd.\n\nOnly signaling NaN inputs cause an Invalid Operation exception.\n\nThe result is 0 if either operand is NaN.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "flt.s" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b1010000, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b001), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "flt.s rd, rs1, rs2".to_string(), + description: "Performs a quiet less comparison between floating-point registers rs1 and rs2 and record the Boolean result in integer register rd.\n\nOnly signaling NaN inputs cause an Invalid Operation exception.\n\nThe result is 0 if either operand is NaN.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fle.s" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b1010000, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b000), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fle.s rd, rs1, rs2".to_string(), + description: "Performs a quiet less or equal comparison between floating-point registers rs1 and rs2 and record the Boolean result in integer register rd.\n\nOnly signaling NaN inputs cause an Invalid Operation exception.\n\nThe result is 0 if either operand is NaN.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fclass.s" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + rs2 + instruction.binary = append_binary(instruction.binary, 0b111000000000, 12); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterFP], + vec![1, 2], + None, + Some(0b001), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fclass.s rd, rs1".to_string(), + description: "Examines the value in floating-point register rs1 and writes to integer register rd a 10-bit mask that indicates the class of the floating-point number.\n\nThe corresponding bit in rd will be set if the property is true and clear otherwise. All other bits in rd are cleared.\n\nNote that exactly one bit in rd will be set.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fcvt.s.w" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + rs2 + instruction.binary = append_binary(instruction.binary, 0b110100000000, 12); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterGP], + vec![1, 2], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fcvt.s.w rd, rs1".to_string(), + description: "Converts a 32-bit signed integer, in integer register rs1 into a floating-point number in floating-point register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fcvt.s.wu" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + rs2 + instruction.binary = append_binary(instruction.binary, 0b110100000001, 12); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterGP], + vec![1, 2], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fcvt.s.wu rd, rs1".to_string(), + description: "Converts a 32-bit unsigned integer, in integer register rs1 into a floating-point number in floating-point register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fmv.w.x" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + rs2 + instruction.binary = append_binary(instruction.binary, 0b111100000000, 12); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterGP], + vec![1, 2], + None, + Some(0b000), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fmv.w.x rd, rs1".to_string(), + description: "Move the single-precision value encoded in IEEE 754-2008 standard encoding from the lower 32 bits of integer register rs1 to the floating-point register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fmadd.d" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3, 4], + None, + Some(0b111), // This funct3 is used for the rm value + Some(0b01) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1000011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fmadd.d rd, rs1, rs2, rs3".to_string(), + description: "Multiplies the values in rs1 and rs2, adds the value in rs3, and writes the final result tord.\n\nFMADD.D computes (rs1 * rs2) + rs3.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fmsub.d" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3, 4], + None, + Some(0b111), // This funct3 is used for the rm value + Some(0b01) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1000111, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fmsub.d rd, rs1, rs2, rs3".to_string(), + description: "Multiplies the values in rs1 and rs2, subtracts the value in rs3, and writes the final result to rd. FMSUB.D computes (rs1 * rs2) - rs3".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fnmsub.d" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3, 4], + None, + Some(0b111), // This funct3 is used for the rm value + Some(0b01) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1001011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fnmsub.d rd, rs1, rs2, rs3".to_string(), + description: "Multiplies the values in rs1 and rs2, negates the product, adds the value in rs3, and writes the final result to rd.\n\nFNMSUB.D computes -(rs1 * rs2) + rs3.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fnmadd.d" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3, 4], + None, + Some(0b111), // This funct3 is used for the rm value + Some(0b01) + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1001111, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fnmadd.d rd, rs1, rs2, rs3".to_string(), + description: "Multiplies the values in rs1 and rs2, negates the product, subtracts the value in rs3, and writes the final result to rd.\n\nFNMADD.D computes -(rs1 * rs2) - rs3".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fadd.d" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b0000001, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fadd.d rd, rs1, rs2".to_string(), + description: "Perform single-precision floating-point addition.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fsub.d" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b0000101, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fsub.d rd, rs1, rs2".to_string(), + description: "Perform single-precision floating-point subtraction.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fmul.d" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b0001001, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fmul.d rd, rs1, rs2".to_string(), + description: "Perform single-precision floating-point multiplication.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fdiv.d" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b0001101, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fdiv.d rd, rs1, rs2".to_string(), + description: "Perform single-precision floating-point division.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fsqrt.d" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + rs2 + instruction.binary = append_binary(instruction.binary, 0b010110100000, 12); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP], + vec![1, 2], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fsqrt.d rd, rs1".to_string(), + description: "Perform single-precision square root.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fsgnj.d" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b0010001, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b000), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fsgnj.d rd, rs1, rs2".to_string(), + description: "Produce a result that takes all bits except the sign bit from rs1.\n\nThe result's sign bit is rs2's sign bit.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fsgnjn.d" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b0010001, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b001), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fsgnjn.d rd, rs1, rs2".to_string(), + description: "Produce a result that takes all bits except the sign bit from rs1.\n\nThe result's sign bit is opposite of rs2's sign bit.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fsgnjx.d" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b0010001, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b010), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fsgnjx.d rd, rs1, rs2".to_string(), + description: "Produce a result that takes all bits except the sign bit from rs1.\n\nThe result's sign bit is XOR of sign bit of rs1 and rs2.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fmin.d" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b0010101, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b000), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fmin.d rd, rs1, rs2".to_string(), + description: "Write the smaller of single precision data in rs1 and rs2 to rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fmax.d" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b0010101, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b001), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fmax.d rd, rs1, rs2".to_string(), + description: "Write the larger of single precision data in rs1 and rs2 to rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fcvt.s.d" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + rs2 + instruction.binary = append_binary(instruction.binary, 0b010000000001, 12); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP], + vec![1, 2], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fcvt.s.d rd, rs1".to_string(), + description: "Converts double floating-point register in rs1 into a floating-point number in floating-point register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fcvt.d.s" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + rs2 + instruction.binary = append_binary(instruction.binary, 0b010000100000, 12); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterFP], + vec![1, 2], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fcvt.d.s rd, rs1".to_string(), + description: "Converts single floating-point register in rs1 into a double floating-point number in floating-point register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "feq.d" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b1010001, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b010), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "feq.d rd, rs1, rs2".to_string(), + description: "Performs a quiet equal comparison between floating-point registers rs1 and rs2 and record the Boolean result in integer register rd.\n\nOnly signaling NaN inputs cause an Invalid Operation exception.\n\nThe result is 0 if either operand is NaN.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "flt.d" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b1010001, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b001), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "flt.d rd, rs1, rs2".to_string(), + description: "Performs a quiet less comparison between floating-point registers rs1 and rs2 and record the Boolean result in integer register rd.\n\nOnly signaling NaN inputs cause an Invalid Operation exception.\n\nThe result is 0 if either operand is NaN.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fle.d" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + instruction.binary = append_binary(instruction.binary, 0b1010001, 7); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterFP, RegisterFP], + vec![1, 2, 3], + None, + Some(0b000), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fle.d rd, rs1, rs2".to_string(), + description: "Performs a quiet less or equal comparison between floating-point registers rs1 and rs2 and record the Boolean result in integer register rd.\n\nOnly signaling NaN inputs cause an Invalid Operation exception.\n\nThe result is 0 if either operand is NaN.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fclass.d" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + rs2 + instruction.binary = append_binary(instruction.binary, 0b111000100000, 12); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterFP], + vec![1, 2], + None, + Some(0b001), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fclass.d rd, rs1".to_string(), + description: "Examines the value in floating-point register rs1 and writes to integer register rd a 10-bit mask that indicates the class of the floating-point number.\n\nThe corresponding bit in rd will be set if the property is true and clear otherwise.\nAll other bits in rd are cleared.\n\nNote that exactly one bit in rd will be set.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fcvt.w.d" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + rs2 + instruction.binary = append_binary(instruction.binary, 0b110000100000, 12); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterFP], + vec![1, 2], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fcvt.w.d rd, rs1".to_string(), + description: "Converts a double-precision floating-point number in floating-point register rs1 to a signed 32-bit integer, in integer register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fcvt.wu.d" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + rs2 + instruction.binary = append_binary(instruction.binary, 0b110000100001, 12); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterFP], + vec![1, 2], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fcvt.wu.d rd, rs1".to_string(), + description: "Converts a double-precision floating-point number in floating-point register rs1 to a unsigned 32-bit integer, in integer register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fcvt.d.w" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + rs2 + instruction.binary = append_binary(instruction.binary, 0b110100100000, 12); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterGP], + vec![1, 2], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fcvt.d.w rd, rs1".to_string(), + description: "Converts a 32-bit signed integer, in integer register rs1 into a double-precision floating-point number in floating-point register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fcvt.d.wu" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + rs2 + instruction.binary = append_binary(instruction.binary, 0b110100100001, 12); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterGP], + vec![1, 2], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fcvt.d.wu rd, rs1".to_string(), + description: "Converts a 32-bit unsigned integer, in integer register rs1 into a double-precision floating-point number in floating-point register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "flw" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, MemoryAddress], + vec![1, 3, 2], + None, + Some(0b010), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0000111, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "flw rd, offset(rs1)".to_string(), + description: "Load a single-precision floating-point value from memory into floating-point register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fsw" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, MemoryAddress], + vec![1, 3, 2], + None, + Some(0b010), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0100111, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Encoded as I-type, but needs reordering for S-type + instruction.binary = immediate_to_stored(instruction.binary); + log!("3. Reordered: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fsw rs2, offset(rs1)".to_string(), + description: "Store a single-precision value from floating-point register rs2 to memory.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fld" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, MemoryAddress], + vec![1, 3, 2], + None, + Some(0b011), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0000111, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fld rd, rs1, offset".to_string(), + description: "Load a double-precision floating-point value from memory into floating-point register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fsd" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, MemoryAddress], + vec![1, 3, 2], + None, + Some(0b011), + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b0100111, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Encoded as I-type, but needs reordering for S-type + instruction.binary = immediate_to_stored(instruction.binary); + log!("3. Reordered: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fsd rs2, offset(rs1)".to_string(), + description: "Store a double-precision value from the floating-point registers to memory.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fcvt.l.s" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + rs2 + instruction.binary = append_binary(instruction.binary, 0b110000000010, 12); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterFP], + vec![1, 2], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fcvt.l.s rd, rs1".to_string(), + description: "Converts the floating-point value in register rs1 (interpreted as a single-precision floating-point number) to a signed 32-bit integer.\n\nThe result is then stored in integer register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fcvt.lu.s" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + rs2 + instruction.binary = append_binary(instruction.binary, 0b110000000011, 12); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterGP, RegisterFP], + vec![1, 2], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fcvt.lu.s rd, rs1".to_string(), + description: "This instruction converts the floating-point value in register rs1 (interpreted as a single-precision floating-point number) to an unsigned 32-bit integer.\n\nThe result is then stored in integer register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fcvt.s.l" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + rs2 + instruction.binary = append_binary(instruction.binary, 0b110100000010, 12); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterGP], + vec![1, 2], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fcvt.s.l rd, rs1".to_string(), + description: "Converts the signed 32-bit integer value in register rs1 to a single-precision floating-point number.\n\nThe result is then stored in floating-point register rd.".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + "fcvt.s.lu" => + { + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + // Funct5 + fmt + rs2 + instruction.binary = append_binary(instruction.binary, 0b110100000011, 12); + log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + + read_operands_riscv( + instruction, + vec![RegisterFP, RegisterGP], + vec![1, 2], + None, + Some(0b111), // This funct3 is used for the rm value + None + ); + + // Opcode + instruction.binary = append_binary(instruction.binary, 0b1010011, 7); + log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + + //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb + if monaco_line_info[instruction.line_number] + .mouse_hover_string + .is_empty() + { + let info = InstructionDescription{ + syntax: "fcvt.s.lu rd, rs1".to_string(), + description: "Converts a single-precision floating-point value to an unsigned 32-bit integer.\n\nTakes the value in a floating-point register (f-register), performs the conversion, and stores the result in an integer register (x-register).".to_string(), + }; + monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); + } + } + _ => + { + if UNSUPPORTED_INSTRUCTIONS.contains(&&*instruction.operator.token_name) { + instruction.errors.push(Error { + error_name: UnsupportedInstruction, + token_causing_error: instruction.operator.token_name.to_string(), + start_end_columns: instruction.operator.start_end_columns, + message: "\n\n".to_string(), + }) + } else { + instruction.errors.push(Error { + error_name: UnrecognizedInstruction, + token_causing_error: instruction.operator.token_name.clone(), + start_end_columns: instruction.operator.start_end_columns, + message: "\n\n".to_string(), + }); + } + } + } + } +} + +// Reorder store instruction to the correct format +fn immediate_to_stored(mut bin: u32) -> u32 +{ + // Extract bits 24-20 from the first segment + let lower_imm = (bin >> 20) & 0b11111; + + // Extract bits 11-7 from the second segment + let rs2 = (bin >> 7) & 0b11111; + + log!("Bits to move (24-20): ", format!("{:05b}", lower_imm)); + log!("Bits to move (11-7): ", format!("{:05b}", rs2)); + + // Clear bits 24-20 and 11-7 + bin &= !((0b11111 << 20) | (0b11111 << 6)); + + log!("Cleared bits: ", format!("{:032b}", bin)); + + // Move bits 24-20 to positions 11-7 + let moved_imm = lower_imm << 7; + + // Move bits 11-7 to positions 24-20 + let moved_rs2 = rs2 << 20; + + // Combine the manipulated bits + bin |= moved_imm | moved_rs2; + + bin +} + +// Converts an I-type instruction to B-type instruction +// Easier to encode in this manner +fn immediate_to_branch(mut bin: u32) -> u32 +{ + log!("Binary: ", format!("{:032b}", bin)); + log!("Immediate: ", format!("{:012b}", (bin >> 20))); + + // Extract bits imm[4:1] from the immediate, last bit is ignored + let lower_imm = (bin >> 21) & 0b1111; + + // Extract imm[10:5] + let upper_imm = (bin >> 24) & 0b111111; + + // Extract bit 11 and bit 12 + let bit_11 = (bin >> 30) & 0b1; + let bit_12 = (bin >> 31) & 0b1; + + // Extract rs1 and rs2 + let rs1 = (bin >> 7) & 0b11111; + let rs2 = (bin >> 15) & 0b11111; + + // Clear bits 24-20, rs1, and rs2 + bin &= !((0b11111 << 20) | (0b11111 << 15) | (0b11111 << 7)); + + // Move bits imm[4:1] to positions 10-8 + let moved_lower = lower_imm << 8; + + let moved_upper = upper_imm << 25; + + let moved_bit_11 = bit_11 << 7; + + let moved_bit_12 = bit_12 << 31; + + // Move rs2 to positions 24-20 + let moved_rs2 = rs2 << 20; + + // Move rs1 to positions 15-19 + let moved_rs1 = rs1 << 15; + + // Combine the manipulated bits + bin |= moved_bit_12 | moved_upper | moved_rs2 | moved_rs1 | moved_lower | moved_bit_11; + + bin +} + +// Reorder the immediate value to comply with J-type format +fn upper_to_jump(mut bin: u32) -> u32 +{ + // Extract bits 24-20 from the first segment + let lower_imm = (bin >> 20) & 0b11111; + + // Extract bits 11-7 from the second segment + let rs2 = (bin >> 7) & 0b11111; + + log!("Bits to move (24-20): ", format!("{:05b}", lower_imm)); + log!("Bits to move (11-7): ", format!("{:05b}", rs2)); + + // Clear bits 24-20 and 11-7 + bin &= !((0b11111 << 20) | (0b11111 << 6)); + + log!("Cleared bits: ", format!("{:032b}", bin)); + + // Move bits 24-20 to positions 11-7 + let moved_imm = lower_imm << 7; + + // Move bits 11-7 to positions 24-20 + let moved_rs2 = rs2 << 20; // Combine the manipulated bits bin |= moved_imm | moved_rs2; diff --git a/static/assembly_examples/riscv_test.asm b/static/assembly_examples/riscv_test.asm index f49f2a7bb..66836342f 100644 --- a/static/assembly_examples/riscv_test.asm +++ b/static/assembly_examples/riscv_test.asm @@ -1,4 +1,3 @@ -# Currently there is a problem with using tabs to space out instructions main: - jal x1, 50 - ret \ No newline at end of file + jal x1, 2047 + ret \ No newline at end of file From b566d94db9bae1562b22cfc2b61508432eb0c51e Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Fri, 16 Feb 2024 16:06:15 -0500 Subject: [PATCH 051/355] Go back to using Vec for instructions --- src/agent/datapath_communicator.rs | 2 +- src/agent/messages.rs | 2 +- src/bin/main.rs | 6 +----- src/emulation_core/datapath.rs | 2 +- src/emulation_core/mips/datapath.rs | 5 ++--- src/lib.rs | 1 - src/shims.rs | 19 ------------------- 7 files changed, 6 insertions(+), 31 deletions(-) delete mode 100644 src/shims.rs diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index b10dc6d1d..5d068388a 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -92,7 +92,7 @@ impl DatapathCommunicator { } /// Resets and loads the parsed/assembled instructions provided into the current emulator core. - pub fn initialize(&self, initial_pc: usize, instructions: Vec) { + pub fn initialize(&self, initial_pc: usize, instructions: Vec) { self.send_message(Command::Initialize(initial_pc, instructions)); } diff --git a/src/agent/messages.rs b/src/agent/messages.rs index b92c23208..1bd4379ca 100644 --- a/src/agent/messages.rs +++ b/src/agent/messages.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Serialize, Deserialize)] pub enum Command { SetCore(AvailableDatapaths), - Initialize(usize, Vec), + Initialize(usize, Vec), SetExecuteSpeed(u32), SetRegister(String, u64), SetMemory(usize, Vec), diff --git a/src/bin/main.rs b/src/bin/main.rs index 8136bd1c2..1027bb9e8 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -20,7 +20,6 @@ use swim::emulation_core::datapath::Datapath; use swim::emulation_core::mips::datapath::MipsDatapath; use swim::emulation_core::mips::datapath::Stage; use swim::parser::parser_assembler_main::parser; -use swim::shims; use swim::ui::console::component::Console; use swim::ui::regview::component::Regview; use wasm_bindgen::{JsCast, JsValue}; @@ -174,10 +173,7 @@ fn app(props: &AppProps) -> Html { text_model.set_value(&program_info.updated_monaco_string); // Expands pseudo-instructions to their hardware counterpart. datapath.registers.pc = program_info.pc_starting_point as u64; // Send the binary over to the emulation core thread - communicator.initialize( - program_info.pc_starting_point, - shims::convert_to_u8_bytes(assembled), - ) + communicator.initialize(program_info.pc_starting_point, assembled) } trigger.force_update(); diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index 4529ab819..4744d3d65 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -50,7 +50,7 @@ pub trait Datapath { /// Reset the datapath, load instructions into memory, and un-sets the `is_halted` /// flag. If the process fails, an [`Err`] is returned. - fn initialize(&mut self, initial_pc: usize, instructions: Vec) -> Result<(), String>; + fn initialize(&mut self, initial_pc: usize, instructions: Vec) -> Result<(), String>; /// Retrieve all memory as-is. fn get_memory(&self) -> &Memory; diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index 322fb262d..bdec0ddfd 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -53,7 +53,6 @@ use super::datapath_signals::*; use super::instruction::*; use super::{coprocessor::MipsFpCoprocessor, memory::Memory, registers::GpRegisters}; use crate::emulation_core::architectures::DatapathRef; -use crate::shims; use serde::{Deserialize, Serialize}; /// An implementation of a datapath for the MIPS64 ISA. @@ -273,9 +272,9 @@ impl Datapath for MipsDatapath { todo!() } - fn initialize(&mut self, initial_pc: usize, instructions: Vec) -> Result<(), String> { + fn initialize(&mut self, initial_pc: usize, instructions: Vec) -> Result<(), String> { self.reset(); - self.load_instructions(shims::convert_from_u8_bytes(instructions))?; + self.load_instructions(instructions)?; self.registers.pc = initial_pc as u64; self.is_halted = false; diff --git a/src/lib.rs b/src/lib.rs index 2ba0135bb..825d617f2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,6 @@ pub mod agent; pub mod emulation_core; pub mod parser; -pub mod shims; #[cfg(test)] pub mod tests; pub mod ui; diff --git a/src/shims.rs b/src/shims.rs deleted file mode 100644 index 625c13684..000000000 --- a/src/shims.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! Temporary shims to get things working for demos. These should NOT be used in the final version. - -pub fn convert_to_u8_bytes(input: Vec) -> Vec { - let mut res = Vec::new(); - for int in input { - for byte in int.to_le_bytes() { - res.push(byte); - } - } - res -} - -pub fn convert_from_u8_bytes(input: Vec) -> Vec { - let mut res = Vec::new(); - for int_bytes in input.chunks(4) { - res.push(u32::from_le_bytes(int_bytes.try_into().unwrap())); - } - res -} From 19e2eee3fa6fa7e2fcddf3f2b971f38878c95b77 Mon Sep 17 00:00:00 2001 From: Cay Date: Fri, 16 Feb 2024 16:51:20 -0500 Subject: [PATCH 052/355] Upgrade Trunk version in check.yml --- .github/workflows/check.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 7998a30d5..059b24387 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -7,7 +7,7 @@ on: workflow_call: env: - PROJECT_TRUNK_VERSION: 'v0.16.0' + PROJECT_TRUNK_VERSION: 'v0.18.8' jobs: check: @@ -37,7 +37,7 @@ jobs: - name: Build run: trunk build if: success() || failure() - + - name: Check documentation run: cargo doc --no-deps if: success() || failure() From eef80167ef2fc90e6256850a951bb1ac76943396 Mon Sep 17 00:00:00 2001 From: rharding8 Date: Fri, 16 Feb 2024 17:04:01 -0500 Subject: [PATCH 053/355] Removed RISC-V from main module rs. Just to test GitHub. --- src/emulation_core.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/emulation_core.rs b/src/emulation_core.rs index 3eb1d02fe..6bc6a6d54 100644 --- a/src/emulation_core.rs +++ b/src/emulation_core.rs @@ -1,5 +1,4 @@ //! The emulation core for the project. pub mod datapath; -pub mod mips; -pub mod riscv; \ No newline at end of file +pub mod mips; \ No newline at end of file From 21f8c067ef9298ba88ab352ae74d6a7b9d35432d Mon Sep 17 00:00:00 2001 From: Geetis Date: Fri, 16 Feb 2024 17:09:50 -0500 Subject: [PATCH 054/355] Revert to MIPS arch for merge purposes --- src/main.rs | 4 ++-- src/parser/parser_assembler_main.rs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main.rs b/src/main.rs index 3f34cccaa..61915f102 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,8 +36,8 @@ use yew_hooks::prelude::*; // To load in the Fibonacci example, uncomment the CONTENT and fib_model lines // and comment the code, language, and text_model lines. IMPORTANT: // rename fib_model to text_model to have it work. -// const CONTENT: &str = include_str!("../static/assembly_examples/fibonacci.asm"); -const CONTENT: &str = include_str!("../static/assembly_examples/riscv_test.asm"); +const CONTENT: &str = include_str!("../static/assembly_examples/fibonacci.asm"); +// const CONTENT: &str = include_str!("../static/assembly_examples/riscv_test.asm"); #[function_component(App)] fn app() -> Html { diff --git a/src/parser/parser_assembler_main.rs b/src/parser/parser_assembler_main.rs index c8bba9499..eb12d6bf6 100644 --- a/src/parser/parser_assembler_main.rs +++ b/src/parser/parser_assembler_main.rs @@ -15,7 +15,8 @@ use gloo_console::log; /// program and builds the binary of the instructions while cataloging any errors that are found. pub fn parser(file_string: String) -> (ProgramInfo, Vec) { - let arch = Architecture::RISCV; // Force RISC-V for testing purposes + // Force MIPS to pass unit tests until I change the function arguments for SWIMv1 test cases`` + let arch = Architecture::MIPS; if arch == Architecture::MIPS { From 44256e308687c8f598137555c05c24806b6d3dd0 Mon Sep 17 00:00:00 2001 From: rharding8 Date: Fri, 16 Feb 2024 17:10:25 -0500 Subject: [PATCH 055/355] Another test. --- src/emulation_core.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/emulation_core.rs b/src/emulation_core.rs index 6bc6a6d54..e62a37920 100644 --- a/src/emulation_core.rs +++ b/src/emulation_core.rs @@ -1,4 +1,4 @@ //! The emulation core for the project. pub mod datapath; -pub mod mips; \ No newline at end of file +pub mod mips; From 805e3e64e1f9bfcec120a987057f729e4eea379f Mon Sep 17 00:00:00 2001 From: Geetis Date: Fri, 16 Feb 2024 17:18:52 -0500 Subject: [PATCH 056/355] Cargo fmt --- src/parser/assembling.rs | 28 +- src/parser/parser_assembler_main.rs | 2406 ++++++++++++++++-------- src/parser/parser_structs_and_enums.rs | 4 +- 3 files changed, 1663 insertions(+), 775 deletions(-) diff --git a/src/parser/assembling.rs b/src/parser/assembling.rs index 065bec1f7..3ae1de2bd 100644 --- a/src/parser/assembling.rs +++ b/src/parser/assembling.rs @@ -6,7 +6,8 @@ use crate::parser::parser_structs_and_enums::ErrorType::{ NonIntImmediate, UnrecognizedDataType, UnrecognizedFPRegister, UnrecognizedGPRegister, }; use crate::parser::parser_structs_and_enums::OperandType::{ - Immediate, UpperImmediate, LabelAbsolute, LabelRelative, MemoryAddress, RegisterFP, RegisterGP, ShiftAmount + Immediate, LabelAbsolute, LabelRelative, MemoryAddress, RegisterFP, RegisterGP, ShiftAmount, + UpperImmediate, }; use crate::parser::parser_structs_and_enums::RegisterType::{FloatingPoint, GeneralPurpose}; use crate::parser::parser_structs_and_enums::TokenType::{ @@ -17,7 +18,7 @@ use crate::parser::parser_structs_and_enums::{ }; use std::collections::HashMap; -use super::parser_structs_and_enums::{RISCV_GP_REGISTERS, RISCV_FP_REGISTERS}; +use super::parser_structs_and_enums::{RISCV_FP_REGISTERS, RISCV_GP_REGISTERS}; use gloo_console::log; @@ -91,8 +92,7 @@ pub fn read_operands( instruction.errors.push(immediate_results.1.unwrap()); } } - UpperImmediate => - { + UpperImmediate => { // Don't need to handle for MIPS } MemoryAddress => { @@ -195,7 +195,7 @@ pub fn read_operands_riscv( concat_order: Vec, labels_option: Option>, funct3: Option, - fmt: Option + fmt: Option, ) -> &mut Instruction { //if the number of operands in the instruction does not match the expected number, there is an error if instruction.operands.len() != expected_operands.len() { @@ -238,7 +238,7 @@ pub fn read_operands_riscv( instruction.operands[i].start_end_columns, GeneralPurpose, ); - + log!("Register Results: ", format!("{:?}", register_results)); // Vector holding all register arguments @@ -262,7 +262,8 @@ pub fn read_operands_riscv( instruction.errors.push(immediate_results.1.unwrap()); } } - UpperImmediate => // Can be used to represent offsets for J-type instructions + UpperImmediate => + // Can be used to represent offsets for J-type instructions { log!("Upper Immediate"); instruction.operands[i].token_type = TokenType::Immediate; @@ -368,12 +369,11 @@ pub fn read_operands_riscv( binary_representation[element - 1], bit_lengths[element - 1], ); - if index == concat_order.len() - 2 && funct3.is_some() // Set funct3 value before the final argument + if index == concat_order.len() - 2 && funct3.is_some() + // Set funct3 value before the final argument { instruction.binary = append_binary(instruction.binary, funct3.unwrap_or(0), 3) - } - else if index == 0 && fmt.is_some() - { + } else if index == 0 && fmt.is_some() { instruction.binary = append_binary(instruction.binary, fmt.unwrap_or(0), 2) } } @@ -584,7 +584,8 @@ pub fn read_register( let general_result = match_gp_register(register); if let Some(..) = general_result { (general_result.unwrap(), None) - } else if match_fp_register(register).is_some() { // Creates Error if supplied a fp register for gp + } else if match_fp_register(register).is_some() { + // Creates Error if supplied a fp register for gp ( 0, Some(Error { @@ -646,7 +647,8 @@ pub fn read_register_riscv( let general_result = match_gp_register_riscv(register); if let Some(..) = general_result { (general_result.unwrap(), None) - } else if match_fp_register_riscv(register).is_some() { // Creates Error if supplied a fp register for gp + } else if match_fp_register_riscv(register).is_some() { + // Creates Error if supplied a fp register for gp ( 0, Some(Error { diff --git a/src/parser/parser_assembler_main.rs b/src/parser/parser_assembler_main.rs index eb12d6bf6..b458cef61 100644 --- a/src/parser/parser_assembler_main.rs +++ b/src/parser/parser_assembler_main.rs @@ -14,12 +14,10 @@ use gloo_console::log; ///Parser is the starting function of the parser / assembler process. It takes a string representation of a MIPS /// program and builds the binary of the instructions while cataloging any errors that are found. pub fn parser(file_string: String) -> (ProgramInfo, Vec) { - // Force MIPS to pass unit tests until I change the function arguments for SWIMv1 test cases`` let arch = Architecture::MIPS; - if arch == Architecture::MIPS - { + if arch == Architecture::MIPS { let mut program_info = ProgramInfo { monaco_line_info: tokenize_program(file_string), ..Default::default() @@ -75,9 +73,7 @@ pub fn parser(file_string: String) -> (ProgramInfo, Vec) { program_info.pc_starting_point = determine_pc_starting_point(labels); (program_info.clone(), binary) - } - else - { + } else { let mut program_info = ProgramInfo { monaco_line_info: tokenize_program(file_string), ..Default::default() @@ -1554,19 +1550,21 @@ pub fn read_instructions_riscv( instruction_list: &mut [Instruction], _labels: &HashMap, monaco_line_info: &mut [MonacoLineInfo], -) -{ - for mut instruction in &mut instruction_list.iter_mut() - { - match &*instruction.operator.token_name.to_lowercase() - { - "add" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); +) { + for mut instruction in &mut instruction_list.iter_mut() { + match &*instruction.operator.token_name.to_lowercase() { + "add" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000000, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -1574,12 +1572,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b000), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0110011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -1593,13 +1594,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "sub" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "sub" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0100000, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -1607,12 +1613,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b000), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0110011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -1626,13 +1635,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "sll" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "sll" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000000, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -1640,12 +1654,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b001), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0110011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -1659,13 +1676,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "slt" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "slt" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000000, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -1673,12 +1695,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b010), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0110011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -1692,13 +1717,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "sltu" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "sltu" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000000, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -1706,12 +1736,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b011), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0110011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -1725,13 +1758,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "xor" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "xor" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000000, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -1739,12 +1777,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b100), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0110011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -1758,13 +1799,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "srl" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "srl" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000000, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -1772,12 +1818,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b101), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0110011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -1791,13 +1840,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "sra" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "sra" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0100000, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -1805,12 +1859,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b101), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0110011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -1824,13 +1881,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "or" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "or" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000000, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -1838,12 +1900,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b110), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0110011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -1857,13 +1922,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "and" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "and" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000000, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -1871,12 +1941,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b111), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0110011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -1890,9 +1963,13 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "addi" => // This instruction requires the 12-bit immediate to be sign extended before moving to the emulator's register + "addi" => + // This instruction requires the 12-bit immediate to be sign extended before moving to the emulator's register { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -1900,12 +1977,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -1919,9 +1999,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "slti" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "slti" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -1929,12 +2011,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b010), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -1948,9 +2033,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "sltiu" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "sltiu" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -1958,12 +2045,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b011), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -1977,9 +2067,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "xori" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "xori" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -1987,12 +2079,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b100), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2006,9 +2101,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "ori" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "ori" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -2016,12 +2113,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b110), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2035,9 +2135,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "andi" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "andi" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -2045,12 +2147,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b111), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2064,9 +2169,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "slli" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "slli" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b00000, 5); // Check if the next 2 bits are needed @@ -2077,12 +2184,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b001), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2096,9 +2206,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "srli" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "srli" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b00000, 5); // Check if the next 2 bits are needed @@ -2109,12 +2221,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b101), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2128,9 +2243,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "srai" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "srai" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b01000, 5); // Check if the next 2 bits are needed @@ -2141,12 +2258,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b101), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2160,9 +2280,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "lb" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "lb" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -2170,12 +2292,15 @@ pub fn read_instructions_riscv( vec![1, 3, 2], None, Some(0b000), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0000011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2189,9 +2314,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "lh" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "lh" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -2199,12 +2326,15 @@ pub fn read_instructions_riscv( vec![1, 3, 2], None, Some(0b001), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0000011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2218,9 +2348,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "lw" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "lw" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -2228,12 +2360,15 @@ pub fn read_instructions_riscv( vec![1, 3, 2], None, Some(0b010), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0000011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2247,9 +2382,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "lbu" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "lbu" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -2257,12 +2394,15 @@ pub fn read_instructions_riscv( vec![1, 3, 2], None, Some(0b100), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0000011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2276,9 +2416,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "lhu" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "lhu" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -2286,12 +2428,15 @@ pub fn read_instructions_riscv( vec![1, 3, 2], None, Some(0b101), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0000011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2305,9 +2450,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "sb" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "sb" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -2315,12 +2462,15 @@ pub fn read_instructions_riscv( vec![1, 3, 2], None, Some(0b000), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0100011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Encoded as I-type, but needs reordering for S-type instruction.binary = immediate_to_stored(instruction.binary); @@ -2331,16 +2481,20 @@ pub fn read_instructions_riscv( .mouse_hover_string .is_empty() { - let info = InstructionDescription{ + let info = InstructionDescription { syntax: "sb rs2, offset(rs1)".to_string(), - description: "Store 8-bit, values from the low bits of register rs2 to memory.".to_string(), + description: + "Store 8-bit, values from the low bits of register rs2 to memory." + .to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "sh" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "sh" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -2348,12 +2502,15 @@ pub fn read_instructions_riscv( vec![1, 3, 2], None, Some(0b001), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0100011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Encoded as I-type, but needs reordering for S-type instruction.binary = immediate_to_stored(instruction.binary); @@ -2364,16 +2521,20 @@ pub fn read_instructions_riscv( .mouse_hover_string .is_empty() { - let info = InstructionDescription{ + let info = InstructionDescription { syntax: "sh rs2, offset(rs1)".to_string(), - description: "Store 16-bit, values from the low bits of register rs2 to memory.".to_string(), + description: + "Store 16-bit, values from the low bits of register rs2 to memory." + .to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "sw" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "sw" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -2381,12 +2542,15 @@ pub fn read_instructions_riscv( vec![1, 3, 2], None, Some(0b010), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0100011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Encoded as I-type, but needs reordering for S-type instruction.binary = immediate_to_stored(instruction.binary); @@ -2397,17 +2561,23 @@ pub fn read_instructions_riscv( .mouse_hover_string .is_empty() { - let info = InstructionDescription{ + let info = InstructionDescription { syntax: "sw rs2, offset(rs1)".to_string(), - description: "Store 32-bit, values from the low bits of register rs2 to memory.".to_string(), + description: + "Store 32-bit, values from the low bits of register rs2 to memory." + .to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "jal" => // Finish J instructions + "jal" => + // Finish J instructions { log!("jal instruction"); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Read as U-type instruction and reorder immediate value after read_operands_riscv( @@ -2416,32 +2586,40 @@ pub fn read_instructions_riscv( vec![1, 2], None, None, - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1101111, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Reorder immediate instruction.binary = upper_to_jump(instruction.binary); - log!("3. Reordered Binary: ", format!("{:032b}", instruction.binary)); + log!( + "3. Reordered Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] .mouse_hover_string .is_empty() { - let info = InstructionDescription{ + let info = InstructionDescription { syntax: "jal rd, offset".to_string(), description: "Jump to address and place return address in rd.".to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "jalr" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "jalr" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -2449,28 +2627,33 @@ pub fn read_instructions_riscv( vec![1, 3, 2], None, Some(0b000), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1100111, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] .mouse_hover_string .is_empty() { - let info = InstructionDescription{ + let info = InstructionDescription { syntax: "jalr rd, rs1, offset".to_string(), description: "Jump to address and place return address in rd.".to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "beq" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "beq" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -2478,31 +2661,40 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b000), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1100011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); instruction.binary = immediate_to_branch(instruction.binary); - log!("3. Reordered Binary: ", format!("{:032b}", instruction.binary)); + log!( + "3. Reordered Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] .mouse_hover_string .is_empty() { - let info = InstructionDescription{ + let info = InstructionDescription { syntax: "beq rs1, rs2, offset".to_string(), - description: "Take the branch if registers rs1 and rs2 are equal.".to_string(), + description: "Take the branch if registers rs1 and rs2 are equal." + .to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "bne" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "bne" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -2510,31 +2702,40 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b001), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1100011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); instruction.binary = immediate_to_branch(instruction.binary); - log!("3. Reordered Binary: ", format!("{:032b}", instruction.binary)); + log!( + "3. Reordered Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] .mouse_hover_string .is_empty() { - let info = InstructionDescription{ + let info = InstructionDescription { syntax: "bne rs1, rs2, offset".to_string(), - description: "Take the branch if registers rs1 and rs2 are not equal.".to_string(), + description: "Take the branch if registers rs1 and rs2 are not equal." + .to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "blt" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "blt" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -2542,15 +2743,21 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b100), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1100011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); instruction.binary = immediate_to_branch(instruction.binary); - log!("3. Reordered Binary: ", format!("{:032b}", instruction.binary)); + log!( + "3. Reordered Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2564,9 +2771,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "bge" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "bge" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -2574,15 +2783,21 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b101), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1100011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); instruction.binary = immediate_to_branch(instruction.binary); - log!("3. Reordered Binary: ", format!("{:032b}", instruction.binary)); + log!( + "3. Reordered Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2596,9 +2811,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "bltu" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "bltu" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -2606,15 +2823,21 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b110), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1100011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); instruction.binary = immediate_to_branch(instruction.binary); - log!("3. Reordered Binary: ", format!("{:032b}", instruction.binary)); + log!( + "3. Reordered Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2628,9 +2851,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "bgeu" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "bgeu" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -2638,15 +2863,21 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b111), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1100011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); instruction.binary = immediate_to_branch(instruction.binary); - log!("3. Reordered Binary: ", format!("{:032b}", instruction.binary)); + log!( + "3. Reordered Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2660,13 +2891,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "ecall" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "ecall" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // ecall instruction encoding does not change instruction.binary = 0b00000000000000000000000001110011; - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2680,13 +2916,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "ebreak" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "ebreak" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // ebreak instruction encoding does not change instruction.binary = 0b00000000000100000000000001110011; - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2700,13 +2941,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "uret" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "uret" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // uret instruction encoding does not change instruction.binary = 0b00000000001000000000000001110011; - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2720,13 +2966,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "sret" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "sret" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // uret instruction encoding does not change instruction.binary = 0b00010000001000000000000001110011; - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2740,13 +2991,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "mret" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "mret" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // uret instruction encoding does not change instruction.binary = 0b00110000001000000000000001110011; - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2760,13 +3016,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "wfi" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "wfi" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // uret instruction encoding does not change instruction.binary = 0b00010000010100000000000001110011; - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2780,13 +3041,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fence.i" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fence.i" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // fence.i instruction encoding does not change instruction.binary = 0b00000000000000000001000000001111; - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2800,9 +3066,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "lui" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "lui" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -2810,12 +3078,15 @@ pub fn read_instructions_riscv( vec![1, 2], None, None, - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0110111, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2829,10 +3100,12 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "auipc" => - { + "auipc" => { log!("auipc instruction"); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -2840,12 +3113,15 @@ pub fn read_instructions_riscv( vec![1, 2], None, None, - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0010111, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2859,9 +3135,13 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "addiw" => // Start of RV64I Instructions + "addiw" => + // Start of RV64I Instructions { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -2869,12 +3149,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b000), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0011011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2888,9 +3171,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "slliw" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "slliw" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000000, 7); @@ -2901,12 +3186,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b001), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0011011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2920,9 +3208,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "srliw" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "srliw" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000000, 7); @@ -2933,12 +3223,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b101), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0011011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2952,25 +3245,30 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "sraiw" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "sraiw" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b01000, 7); - + read_operands_riscv( instruction, vec![RegisterGP, RegisterGP, ShiftAmount], vec![1, 2, 3], None, Some(0b101), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0011011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -2984,13 +3282,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "addw" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "addw" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000000, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -2998,12 +3301,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b000), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0111011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3017,13 +3323,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "subw" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "subw" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0100000, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3031,12 +3342,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b000), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0111011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3050,13 +3364,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "sllw" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "sllw" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000000, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3064,12 +3383,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b001), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0111011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3083,13 +3405,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "srlw" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "srlw" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000000, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3097,12 +3424,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b101), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0111011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3116,13 +3446,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "sraw" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "sraw" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0100000, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3130,12 +3465,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b101), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0111011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3149,9 +3487,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "lwu" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "lwu" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3159,12 +3499,15 @@ pub fn read_instructions_riscv( vec![1, 3, 2], None, Some(0b110), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0000011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3178,9 +3521,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "ld" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "ld" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3188,28 +3533,34 @@ pub fn read_instructions_riscv( vec![1, 3, 2], None, Some(0b011), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0000011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] .mouse_hover_string .is_empty() { - let info = InstructionDescription{ + let info = InstructionDescription { syntax: "ld rd, offset(rs1)".to_string(), - description: "Loads a 64-bit value from memory into register rd for RV64I.".to_string(), + description: "Loads a 64-bit value from memory into register rd for RV64I." + .to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "sd" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "sd" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3217,12 +3568,15 @@ pub fn read_instructions_riscv( vec![1, 3, 2], None, Some(0b011), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0100011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Encoded as I-type, but needs reordering for S-type instruction.binary = immediate_to_stored(instruction.binary); @@ -3233,20 +3587,28 @@ pub fn read_instructions_riscv( .mouse_hover_string .is_empty() { - let info = InstructionDescription{ + let info = InstructionDescription { syntax: "sd rs2, offset(rs1)".to_string(), - description: "Store 64-bit, values from register rs2 to memory.".to_string(), + description: "Store 64-bit, values from register rs2 to memory." + .to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "mul" => // Start of RV32M + "mul" => + // Start of RV32M { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000001, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3254,12 +3616,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b000), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0110011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3273,13 +3638,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "mulh" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "mulh" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000001, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3287,12 +3657,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b001), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0110011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3307,13 +3680,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "mulhsu" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "mulhsu" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000001, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3321,12 +3699,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b010), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0110011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3340,13 +3721,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "mulhu" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "mulhu" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000001, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3354,12 +3740,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b011), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0110011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3373,13 +3762,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "div" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "div" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000001, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3387,12 +3781,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b100), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0110011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3406,13 +3803,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "divu" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "divu" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000001, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3420,12 +3822,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b101), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0110011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3439,13 +3844,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "rem" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "rem" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000001, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3453,12 +3863,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b110), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0110011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3472,13 +3885,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "remu" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "remu" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000001, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3486,12 +3904,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b111), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0110011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3505,13 +3926,20 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "mulw" => // Start of RV64M + "mulw" => + // Start of RV64M { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000001, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3519,12 +3947,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b000), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0111011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3538,13 +3969,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "divw" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "divw" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000001, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3552,12 +3988,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b100), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0111011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3571,13 +4010,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "divuw" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "divuw" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000001, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3585,12 +4029,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b101), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0111011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3604,13 +4051,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "remw" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "remw" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000001, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3618,12 +4070,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b110), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0111011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3637,13 +4092,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "remuw" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "remuw" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct7 instruction.binary = append_binary(instruction.binary, 0b0000001, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3651,12 +4111,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b111), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0111011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3670,9 +4133,13 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fmadd.s" => // Start of RV32F + "fmadd.s" => + // Start of RV32F { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3680,12 +4147,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3, 4], None, Some(0b111), // This funct3 is used for the rm value - Some(0b00) + Some(0b00), ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1000011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3699,9 +4169,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fmsub.s" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fmsub.s" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3709,12 +4181,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3, 4], None, Some(0b111), // This funct3 is used for the rm value - Some(0b00) + Some(0b00), ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1000111, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3728,9 +4203,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fnmsub.s" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fnmsub.s" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3738,12 +4215,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3, 4], None, Some(0b111), // This funct3 is used for the rm value - Some(0b00) + Some(0b00), ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1001011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3757,9 +4237,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fnmadd.s" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fnmadd.s" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3767,12 +4249,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3, 4], None, Some(0b111), // This funct3 is used for the rm value - Some(0b00) + Some(0b00), ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1001111, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3786,13 +4271,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fadd.s" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fadd.s" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b0000000, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3800,32 +4290,41 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] .mouse_hover_string .is_empty() { - let info = InstructionDescription{ + let info = InstructionDescription { syntax: "fadd.s rd, rs1, rs2".to_string(), - description: "Perform single-precision floating-point addition.".to_string(), + description: "Perform single-precision floating-point addition." + .to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fsub.s" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fsub.s" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b0000100, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3833,32 +4332,41 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] .mouse_hover_string .is_empty() { - let info = InstructionDescription{ + let info = InstructionDescription { syntax: "fsub.s rd, rs1, rs2".to_string(), - description: "Perform single-precision floating-point substraction.".to_string(), + description: "Perform single-precision floating-point substraction." + .to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fmul.s" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fmul.s" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b0001000, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3866,32 +4374,41 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] .mouse_hover_string .is_empty() { - let info = InstructionDescription{ + let info = InstructionDescription { syntax: "fmul.s rd, rs1, rs2".to_string(), - description: "Perform single-precision floating-point multiplication.".to_string(), + description: "Perform single-precision floating-point multiplication." + .to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fdiv.s" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fdiv.s" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b0001100, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3899,32 +4416,41 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] .mouse_hover_string .is_empty() { - let info = InstructionDescription{ + let info = InstructionDescription { syntax: "fdiv.s rd, rs1, rs2".to_string(), - description: "Perform single-precision floating-point division.".to_string(), + description: "Perform single-precision floating-point division." + .to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fsqrt.s" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fsqrt.s" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt + padding for absent register instruction.binary = append_binary(instruction.binary, 0b010110000000, 12); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3932,32 +4458,40 @@ pub fn read_instructions_riscv( vec![1, 2], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] .mouse_hover_string .is_empty() { - let info = InstructionDescription{ + let info = InstructionDescription { syntax: "fsqrt.s rd, rs1".to_string(), description: "Perform single-precision square root.".to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fsgnj.s" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fsgnj.s" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b0010000, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3965,12 +4499,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b000), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -3984,13 +4521,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fsgnjn.s" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fsgnjn.s" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b0010000, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -3998,12 +4540,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b001), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -4017,13 +4562,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fsgnjx.s" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fsgnjx.s" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b0010000, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4031,12 +4581,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b010), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -4050,13 +4603,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fmin.s" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fmin.s" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b0010100, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4064,32 +4622,42 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b000), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] .mouse_hover_string .is_empty() { - let info = InstructionDescription{ + let info = InstructionDescription { syntax: "fmin.s rd, rs1, rs2".to_string(), - description: "Write the smaller of single precision data in rs1 and rs2 to rd.".to_string(), + description: + "Write the smaller of single precision data in rs1 and rs2 to rd." + .to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fmax.s" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fmax.s" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b0010100, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4097,32 +4665,42 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b001), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] .mouse_hover_string .is_empty() { - let info = InstructionDescription{ + let info = InstructionDescription { syntax: "fmax.s rd, rs1, rs2".to_string(), - description: "Write the larger of single precision data in rs1 and rs2 to rd.".to_string(), + description: + "Write the larger of single precision data in rs1 and rs2 to rd." + .to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fcvt.w.s" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fcvt.w.s" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt + padding for absent register instruction.binary = append_binary(instruction.binary, 0b110000000000, 12); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4130,12 +4708,15 @@ pub fn read_instructions_riscv( vec![1, 2], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -4149,13 +4730,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fcvt.wu.s" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fcvt.wu.s" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt + rs2 instruction.binary = append_binary(instruction.binary, 0b110000000001, 12); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4163,12 +4749,15 @@ pub fn read_instructions_riscv( vec![1, 2], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -4182,13 +4771,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fmv.x.w" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fmv.x.w" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt + rs2 instruction.binary = append_binary(instruction.binary, 0b111000000000, 12); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4196,12 +4790,15 @@ pub fn read_instructions_riscv( vec![1, 2], None, Some(0b000), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -4215,13 +4812,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "feq.s" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "feq.s" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b1010000, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4229,12 +4831,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b010), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -4248,13 +4853,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "flt.s" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "flt.s" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b1010000, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4262,12 +4872,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b001), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -4281,13 +4894,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fle.s" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fle.s" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b1010000, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4295,12 +4913,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b000), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -4314,13 +4935,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fclass.s" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fclass.s" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt + rs2 instruction.binary = append_binary(instruction.binary, 0b111000000000, 12); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4328,12 +4954,15 @@ pub fn read_instructions_riscv( vec![1, 2], None, Some(0b001), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -4347,13 +4976,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fcvt.s.w" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fcvt.s.w" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt + rs2 instruction.binary = append_binary(instruction.binary, 0b110100000000, 12); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4361,12 +4995,15 @@ pub fn read_instructions_riscv( vec![1, 2], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -4380,13 +5017,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fcvt.s.wu" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fcvt.s.wu" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt + rs2 instruction.binary = append_binary(instruction.binary, 0b110100000001, 12); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4394,12 +5036,15 @@ pub fn read_instructions_riscv( vec![1, 2], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -4413,13 +5058,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fmv.w.x" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fmv.w.x" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt + rs2 instruction.binary = append_binary(instruction.binary, 0b111100000000, 12); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4427,12 +5077,15 @@ pub fn read_instructions_riscv( vec![1, 2], None, Some(0b000), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -4446,9 +5099,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fmadd.d" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fmadd.d" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4456,12 +5111,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3, 4], None, Some(0b111), // This funct3 is used for the rm value - Some(0b01) + Some(0b01), ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1000011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -4475,9 +5133,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fmsub.d" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fmsub.d" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4485,12 +5145,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3, 4], None, Some(0b111), // This funct3 is used for the rm value - Some(0b01) + Some(0b01), ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1000111, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -4504,9 +5167,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fnmsub.d" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fnmsub.d" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4514,12 +5179,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3, 4], None, Some(0b111), // This funct3 is used for the rm value - Some(0b01) + Some(0b01), ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1001011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -4533,9 +5201,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fnmadd.d" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fnmadd.d" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4543,12 +5213,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3, 4], None, Some(0b111), // This funct3 is used for the rm value - Some(0b01) + Some(0b01), ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1001111, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -4562,13 +5235,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fadd.d" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fadd.d" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b0000001, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4576,32 +5254,41 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] .mouse_hover_string .is_empty() { - let info = InstructionDescription{ + let info = InstructionDescription { syntax: "fadd.d rd, rs1, rs2".to_string(), - description: "Perform single-precision floating-point addition.".to_string(), + description: "Perform single-precision floating-point addition." + .to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fsub.d" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fsub.d" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b0000101, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4609,32 +5296,41 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] .mouse_hover_string .is_empty() { - let info = InstructionDescription{ + let info = InstructionDescription { syntax: "fsub.d rd, rs1, rs2".to_string(), - description: "Perform single-precision floating-point subtraction.".to_string(), + description: "Perform single-precision floating-point subtraction." + .to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fmul.d" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fmul.d" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b0001001, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4642,32 +5338,41 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] .mouse_hover_string .is_empty() { - let info = InstructionDescription{ + let info = InstructionDescription { syntax: "fmul.d rd, rs1, rs2".to_string(), - description: "Perform single-precision floating-point multiplication.".to_string(), + description: "Perform single-precision floating-point multiplication." + .to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fdiv.d" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fdiv.d" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b0001101, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4675,32 +5380,41 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] .mouse_hover_string .is_empty() { - let info = InstructionDescription{ + let info = InstructionDescription { syntax: "fdiv.d rd, rs1, rs2".to_string(), - description: "Perform single-precision floating-point division.".to_string(), + description: "Perform single-precision floating-point division." + .to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fsqrt.d" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fsqrt.d" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt + rs2 instruction.binary = append_binary(instruction.binary, 0b010110100000, 12); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4708,32 +5422,40 @@ pub fn read_instructions_riscv( vec![1, 2], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] .mouse_hover_string .is_empty() { - let info = InstructionDescription{ + let info = InstructionDescription { syntax: "fsqrt.d rd, rs1".to_string(), description: "Perform single-precision square root.".to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fsgnj.d" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fsgnj.d" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b0010001, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4741,12 +5463,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b000), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -4760,13 +5485,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fsgnjn.d" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fsgnjn.d" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b0010001, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4774,12 +5504,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b001), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -4793,13 +5526,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fsgnjx.d" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fsgnjx.d" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b0010001, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4807,12 +5545,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b010), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -4826,13 +5567,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fmin.d" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fmin.d" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b0010101, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4840,32 +5586,42 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b000), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] .mouse_hover_string .is_empty() { - let info = InstructionDescription{ + let info = InstructionDescription { syntax: "fmin.d rd, rs1, rs2".to_string(), - description: "Write the smaller of single precision data in rs1 and rs2 to rd.".to_string(), + description: + "Write the smaller of single precision data in rs1 and rs2 to rd." + .to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fmax.d" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fmax.d" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b0010101, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4873,32 +5629,42 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b001), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] .mouse_hover_string .is_empty() { - let info = InstructionDescription{ + let info = InstructionDescription { syntax: "fmax.d rd, rs1, rs2".to_string(), - description: "Write the larger of single precision data in rs1 and rs2 to rd.".to_string(), + description: + "Write the larger of single precision data in rs1 and rs2 to rd." + .to_string(), }; monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fcvt.s.d" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fcvt.s.d" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt + rs2 instruction.binary = append_binary(instruction.binary, 0b010000000001, 12); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4906,12 +5672,15 @@ pub fn read_instructions_riscv( vec![1, 2], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -4925,13 +5694,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fcvt.d.s" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fcvt.d.s" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt + rs2 instruction.binary = append_binary(instruction.binary, 0b010000100000, 12); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4939,12 +5713,15 @@ pub fn read_instructions_riscv( vec![1, 2], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -4958,13 +5735,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "feq.d" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "feq.d" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b1010001, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -4972,12 +5754,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b010), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -4991,13 +5776,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "flt.d" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "flt.d" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b1010001, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -5005,12 +5795,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b001), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -5024,13 +5817,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fle.d" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fle.d" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt instruction.binary = append_binary(instruction.binary, 0b1010001, 7); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -5038,12 +5836,15 @@ pub fn read_instructions_riscv( vec![1, 2, 3], None, Some(0b000), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -5057,13 +5858,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fclass.d" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fclass.d" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt + rs2 instruction.binary = append_binary(instruction.binary, 0b111000100000, 12); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -5071,12 +5877,15 @@ pub fn read_instructions_riscv( vec![1, 2], None, Some(0b001), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -5090,13 +5899,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fcvt.w.d" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fcvt.w.d" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt + rs2 instruction.binary = append_binary(instruction.binary, 0b110000100000, 12); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -5104,12 +5918,15 @@ pub fn read_instructions_riscv( vec![1, 2], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -5123,13 +5940,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fcvt.wu.d" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fcvt.wu.d" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt + rs2 instruction.binary = append_binary(instruction.binary, 0b110000100001, 12); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -5137,12 +5959,15 @@ pub fn read_instructions_riscv( vec![1, 2], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -5156,13 +5981,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fcvt.d.w" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fcvt.d.w" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt + rs2 instruction.binary = append_binary(instruction.binary, 0b110100100000, 12); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -5170,12 +6000,15 @@ pub fn read_instructions_riscv( vec![1, 2], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -5189,13 +6022,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fcvt.d.wu" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fcvt.d.wu" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt + rs2 instruction.binary = append_binary(instruction.binary, 0b110100100001, 12); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -5203,12 +6041,15 @@ pub fn read_instructions_riscv( vec![1, 2], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -5222,9 +6063,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "flw" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "flw" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -5232,12 +6075,15 @@ pub fn read_instructions_riscv( vec![1, 3, 2], None, Some(0b010), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0000111, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -5251,9 +6097,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fsw" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fsw" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -5261,12 +6109,15 @@ pub fn read_instructions_riscv( vec![1, 3, 2], None, Some(0b010), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0100111, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Encoded as I-type, but needs reordering for S-type instruction.binary = immediate_to_stored(instruction.binary); @@ -5284,9 +6135,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fld" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fld" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -5294,12 +6147,15 @@ pub fn read_instructions_riscv( vec![1, 3, 2], None, Some(0b011), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0000111, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -5313,9 +6169,11 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fsd" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fsd" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -5323,12 +6181,15 @@ pub fn read_instructions_riscv( vec![1, 3, 2], None, Some(0b011), - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b0100111, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Encoded as I-type, but needs reordering for S-type instruction.binary = immediate_to_stored(instruction.binary); @@ -5346,13 +6207,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fcvt.l.s" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fcvt.l.s" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt + rs2 instruction.binary = append_binary(instruction.binary, 0b110000000010, 12); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -5360,12 +6226,15 @@ pub fn read_instructions_riscv( vec![1, 2], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -5379,13 +6248,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fcvt.lu.s" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fcvt.lu.s" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt + rs2 instruction.binary = append_binary(instruction.binary, 0b110000000011, 12); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -5393,12 +6267,15 @@ pub fn read_instructions_riscv( vec![1, 2], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -5412,13 +6289,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fcvt.s.l" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fcvt.s.l" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt + rs2 instruction.binary = append_binary(instruction.binary, 0b110100000010, 12); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -5426,12 +6308,15 @@ pub fn read_instructions_riscv( vec![1, 2], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -5445,13 +6330,18 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - "fcvt.s.lu" => - { - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + "fcvt.s.lu" => { + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); // Funct5 + fmt + rs2 instruction.binary = append_binary(instruction.binary, 0b110100000011, 12); - log!("Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); read_operands_riscv( instruction, @@ -5459,12 +6349,15 @@ pub fn read_instructions_riscv( vec![1, 2], None, Some(0b111), // This funct3 is used for the rm value - None + None, ); // Opcode instruction.binary = append_binary(instruction.binary, 0b1010011, 7); - log!("2. Instruction Binary: ", format!("{:032b}", instruction.binary)); + log!( + "2. Instruction Binary: ", + format!("{:032b}", instruction.binary) + ); //Pseudo-instructions already have text in mouse_hover_string so we check if there's text there already before adding in the blurb if monaco_line_info[instruction.line_number] @@ -5478,8 +6371,7 @@ pub fn read_instructions_riscv( monaco_line_info[instruction.line_number].mouse_hover_string = info.to_string(); } } - _ => - { + _ => { if UNSUPPORTED_INSTRUCTIONS.contains(&&*instruction.operator.token_name) { instruction.errors.push(Error { error_name: UnsupportedInstruction, @@ -5501,8 +6393,7 @@ pub fn read_instructions_riscv( } // Reorder store instruction to the correct format -fn immediate_to_stored(mut bin: u32) -> u32 -{ +fn immediate_to_stored(mut bin: u32) -> u32 { // Extract bits 24-20 from the first segment let lower_imm = (bin >> 20) & 0b11111; @@ -5524,15 +6415,14 @@ fn immediate_to_stored(mut bin: u32) -> u32 let moved_rs2 = rs2 << 20; // Combine the manipulated bits - bin |= moved_imm | moved_rs2; + bin |= moved_imm | moved_rs2; bin } // Converts an I-type instruction to B-type instruction // Easier to encode in this manner -fn immediate_to_branch(mut bin: u32) -> u32 -{ +fn immediate_to_branch(mut bin: u32) -> u32 { log!("Binary: ", format!("{:032b}", bin)); log!("Immediate: ", format!("{:012b}", (bin >> 20))); @@ -5555,7 +6445,7 @@ fn immediate_to_branch(mut bin: u32) -> u32 // Move bits imm[4:1] to positions 10-8 let moved_lower = lower_imm << 8; - + let moved_upper = upper_imm << 25; let moved_bit_11 = bit_11 << 7; @@ -5569,14 +6459,13 @@ fn immediate_to_branch(mut bin: u32) -> u32 let moved_rs1 = rs1 << 15; // Combine the manipulated bits - bin |= moved_bit_12 | moved_upper | moved_rs2 | moved_rs1 | moved_lower | moved_bit_11; + bin |= moved_bit_12 | moved_upper | moved_rs2 | moved_rs1 | moved_lower | moved_bit_11; bin } // Reorder the immediate value to comply with J-type format -fn upper_to_jump(mut bin: u32) -> u32 -{ +fn upper_to_jump(mut bin: u32) -> u32 { // Extract bits 24-20 from the first segment let lower_imm = (bin >> 20) & 0b11111; @@ -5598,12 +6487,11 @@ fn upper_to_jump(mut bin: u32) -> u32 let moved_rs2 = rs2 << 20; // Combine the manipulated bits - bin |= moved_imm | moved_rs2; + bin |= moved_imm | moved_rs2; bin } - ///This function takes two numbers and inserts the binary of the second at a given index in the binary of the first. ///All binary values at and past the insertion index of the original string will be moved to the end of the resultant string. ///Since binary is sign extended on the left to 32 bits, insertion index must be the index from the end of the string. diff --git a/src/parser/parser_structs_and_enums.rs b/src/parser/parser_structs_and_enums.rs index efd05e8d4..07dd2ecc7 100644 --- a/src/parser/parser_structs_and_enums.rs +++ b/src/parser/parser_structs_and_enums.rs @@ -21,7 +21,7 @@ pub struct ProgramInfo { pub enum Architecture { #[default] MIPS, - RISCV + RISCV, } #[derive(Clone, Debug, Default, Eq, PartialEq)] @@ -666,7 +666,6 @@ pub const UNSUPPORTED_INSTRUCTIONS: [&str; 408] = [ "xor", "xori", // RISC-V Instructions - ]; ///Contains every general purpose register's binary value and the various names they are recognized as. Any reference to gp registers throughout the parser/assembler should reference this array @@ -1079,7 +1078,6 @@ pub const RISCV_GP_REGISTERS: &[GPRegisterRiscv; 32] = &[ }, ]; - pub struct FPRegisterRiscv<'a> { pub names: &'a [&'a str], pub binary: u8, From a9ffb9e8e666b296b30151eef9c125b30dfd9144 Mon Sep 17 00:00:00 2001 From: Cay Date: Fri, 16 Feb 2024 17:25:19 -0500 Subject: [PATCH 057/355] Edit memory using communicator --- src/agent/datapath_reducer.rs | 3 ++- src/bin/main.rs | 42 +++++++++++------------------ src/emulation_core/architectures.rs | 2 +- 3 files changed, 18 insertions(+), 29 deletions(-) diff --git a/src/agent/datapath_reducer.rs b/src/agent/datapath_reducer.rs index 55f073675..954f86925 100644 --- a/src/agent/datapath_reducer.rs +++ b/src/agent/datapath_reducer.rs @@ -7,12 +7,13 @@ use crate::emulation_core::mips::registers::GpRegisters; use std::rc::Rc; use yew::Reducible; +#[derive(PartialEq)] pub struct DatapathReducer { pub current_architecture: AvailableDatapaths, pub mips: MipsCoreState, } -#[derive(Default)] +#[derive(Default, PartialEq)] pub struct MipsCoreState { pub state: DatapathState, pub registers: GpRegisters, diff --git a/src/bin/main.rs b/src/bin/main.rs index e6f50219d..c8bb7021d 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -21,11 +21,6 @@ use swim::emulation_core::mips::datapath::MipsDatapath; use swim::emulation_core::mips::datapath::Stage; use swim::ui::footer::component::Footer; use swim::parser::parser_assembler_main::parser; -<<<<<<< HEAD -use swim::shims; -======= -use swim::ui::console::component::Console; ->>>>>>> 0c78fd0aa063b873ebe3afa961a8b9ac352b2329 use swim::ui::regview::component::Regview; use swim::ui::swim_editor::component::SwimEditor; use wasm_bindgen::{JsCast, JsValue}; @@ -116,6 +111,7 @@ fn app(props: &AppProps) -> Html { let memory_text_model = memory_text_model.clone(); let memory_curr_instr = memory_curr_instr.clone(); let datapath = Rc::clone(&datapath); + let datapath_state = datapath_state.clone(); let parser_text_output = parser_text_output.clone(); let trigger = use_force_update(); let editor_curr_line = editor_curr_line.clone(); @@ -127,7 +123,7 @@ fn app(props: &AppProps) -> Html { let binary_ref = Rc::clone(&binary_ref); use_callback( - move |_, (text_model, editor_curr_line, memory_curr_instr)| { + move |_, (text_model, editor_curr_line, memory_curr_instr, datapath_state)| { let mut datapath = datapath.borrow_mut(); let text_model = text_model.clone(); let memory_text_model = memory_text_model.clone(); @@ -184,7 +180,7 @@ fn app(props: &AppProps) -> Html { memory_curr_instr.set(datapath.registers.pc); // log!(datapath.memory.to_string()); text_model.set_value(&program_info.updated_monaco_string); // Expands pseudo-instructions to their hardware counterpart. - let hexdump = &datapath.memory.generate_formatted_hex(); + let hexdump = &datapath_state.mips.memory.generate_formatted_hex(); memory_text_model.set_value(hexdump); datapath.registers.pc = program_info.pc_starting_point as u64; // Send the binary over to the emulation core thread @@ -193,7 +189,7 @@ fn app(props: &AppProps) -> Html { trigger.force_update(); }, - (text_model, editor_curr_line, memory_curr_instr), + (text_model, editor_curr_line, memory_curr_instr, datapath_state), ) }; @@ -205,6 +201,7 @@ fn app(props: &AppProps) -> Html { // code, the previously executed line is highlighted. let on_execute_clicked = { let datapath = Rc::clone(&datapath); + let datapath_state = datapath_state.clone(); let program_info_ref = Rc::clone(&program_info_ref); // Code editor @@ -218,7 +215,7 @@ fn app(props: &AppProps) -> Html { let communicator = props.communicator; use_callback( - move |_, (editor_curr_line, memory_curr_instr)| { + move |_, (editor_curr_line, memory_curr_instr, datapath_state)| { let mut datapath = datapath.borrow_mut(); let memory_text_model = memory_text_model.clone(); @@ -235,18 +232,19 @@ fn app(props: &AppProps) -> Html { communicator.execute_instruction(); // Update memory - let hexdump = &datapath.memory.generate_formatted_hex(); + let hexdump = &datapath_state.mips.memory.generate_formatted_hex(); memory_text_model.set_value(hexdump); trigger.force_update(); }, - (editor_curr_line, memory_curr_instr), + (editor_curr_line, memory_curr_instr, datapath_state), ) }; let on_execute_stage_clicked = { let datapath = Rc::clone(&datapath); + let datapath_state = datapath_state.clone(); let program_info_ref = Rc::clone(&program_info_ref); // Code editor @@ -259,7 +257,7 @@ fn app(props: &AppProps) -> Html { let trigger = use_force_update(); use_callback( - move |_, (editor_curr_line, memory_curr_instr)| { + move |_, (editor_curr_line, memory_curr_instr, datapath_state)| { let mut datapath = datapath.borrow_mut(); let memory_text_model = memory_text_model.clone(); @@ -278,18 +276,17 @@ fn app(props: &AppProps) -> Html { } // Update memory - let hexdump = &datapath.memory.generate_formatted_hex(); + let hexdump = &datapath_state.mips.memory.generate_formatted_hex(); memory_text_model.set_value(hexdump); trigger.force_update(); }, - (editor_curr_line, memory_curr_instr), + (editor_curr_line, memory_curr_instr, datapath_state), ) }; let on_memory_clicked = { - let datapath = Rc::clone(&datapath); let program_info_ref = Rc::clone(&program_info_ref); // Code editor @@ -303,9 +300,7 @@ fn app(props: &AppProps) -> Html { let datapath_state = datapath_state.clone(); use_callback( - move |_, _| { - let datapath = datapath.borrow_mut(); - + move |_, datapath_state| { let communicator = communicator.clone(); let text_model = text_model.clone(); @@ -335,7 +330,7 @@ fn app(props: &AppProps) -> Html { } }; - let curr_word = match datapath.memory.load_word(address * 4) { + let curr_word = match datapath_state.mips.memory.load_word(address * 4) { Ok(data) => data, Err(e) => { debug!("{:?}", e); @@ -343,8 +338,6 @@ fn app(props: &AppProps) -> Html { } }; if curr_word != *data { - debug!("address: {:?}", address * 4); - log::debug!("curr word: {}, new word: {}", curr_word, data); changed_lines.push(UpdatedLine::new(string_version, i)); communicator.set_memory(address * 4, *data); @@ -407,19 +400,14 @@ fn app(props: &AppProps) -> Html { } } - let hexdump = datapath.memory.generate_formatted_hex(); - - memory_text_model.set_value(&hexdump); - // Update the parsed info for text and data segment views let (program_info, _) = parser(text_model.get_value()); *program_info_ref.borrow_mut() = program_info.clone(); - communicator.execute_stage(); trigger.force_update(); }, - (), + datapath_state, ) }; diff --git a/src/emulation_core/architectures.rs b/src/emulation_core/architectures.rs index 20cf13478..9dfe17a25 100644 --- a/src/emulation_core/architectures.rs +++ b/src/emulation_core/architectures.rs @@ -2,7 +2,7 @@ use crate::agent::messages::MipsStateUpdate; use crate::emulation_core::mips::datapath::MipsDatapath; use serde::{Deserialize, Serialize}; -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum AvailableDatapaths { MIPS, RISCV, From c15b22996a65480f678422c9b8850bb2af59d8dd Mon Sep 17 00:00:00 2001 From: Cay Date: Fri, 16 Feb 2024 18:13:12 -0500 Subject: [PATCH 058/355] Add current_stage to DatapathReducer --- src/agent.rs | 2 + src/agent/datapath_reducer.rs | 12 +++++- src/agent/messages.rs | 3 +- src/bin/main.rs | 59 ++++++++++------------------- src/emulation_core/datapath.rs | 1 + src/emulation_core/mips/datapath.rs | 2 +- 6 files changed, 37 insertions(+), 42 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index add746df6..a21634060 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -58,9 +58,11 @@ pub async fn emulation_core_agent(scope: ReactorScope) DatapathUpdate::MIPS(MipsStateUpdate::UpdateRegisters(datapath.registers)); let memory_update = DatapathUpdate::MIPS(MipsStateUpdate::UpdateMemory(datapath.memory.clone())); + let stage_update = DatapathUpdate::MIPS(MipsStateUpdate::UpdateStage(datapath.current_stage.clone())); state.scope.send(state_update).await.unwrap(); state.scope.send(register_update).await.unwrap(); state.scope.send(memory_update).await.unwrap(); + state.scope.send(stage_update).await.unwrap(); } } } diff --git a/src/agent/datapath_reducer.rs b/src/agent/datapath_reducer.rs index 954f86925..bbde6e936 100644 --- a/src/agent/datapath_reducer.rs +++ b/src/agent/datapath_reducer.rs @@ -1,7 +1,7 @@ use crate::agent::messages::MipsStateUpdate; use crate::emulation_core::architectures::AvailableDatapaths::MIPS; use crate::emulation_core::architectures::{AvailableDatapaths, DatapathUpdate}; -use crate::emulation_core::mips::datapath::DatapathState; +use crate::emulation_core::mips::datapath::{DatapathState, Stage}; use crate::emulation_core::mips::memory::Memory; use crate::emulation_core::mips::registers::GpRegisters; use std::rc::Rc; @@ -18,6 +18,7 @@ pub struct MipsCoreState { pub state: DatapathState, pub registers: GpRegisters, pub memory: Memory, + pub current_stage: Stage } impl Default for DatapathReducer { @@ -41,16 +42,25 @@ impl Reducible for DatapathReducer { state, registers: self.mips.registers, memory: self.mips.memory.clone(), + current_stage: self.mips.current_stage.clone(), }, MipsStateUpdate::UpdateRegisters(registers) => MipsCoreState { state: self.mips.state.clone(), registers, memory: self.mips.memory.clone(), + current_stage: self.mips.current_stage.clone(), }, MipsStateUpdate::UpdateMemory(memory) => MipsCoreState { state: self.mips.state.clone(), registers: self.mips.registers, memory, + current_stage: self.mips.current_stage.clone(), + }, + MipsStateUpdate::UpdateStage(stage) => MipsCoreState { + state: self.mips.state.clone(), + registers: self.mips.registers, + memory: self.mips.memory.clone(), + current_stage: stage, }, }, }, diff --git a/src/agent/messages.rs b/src/agent/messages.rs index 4d20a9054..6c4ff504a 100644 --- a/src/agent/messages.rs +++ b/src/agent/messages.rs @@ -1,4 +1,4 @@ -use crate::emulation_core::architectures::AvailableDatapaths; +use crate::emulation_core::{architectures::AvailableDatapaths, mips::datapath::Stage}; use crate::emulation_core::mips::datapath::DatapathState; use crate::emulation_core::mips::memory::Memory; use crate::emulation_core::mips::registers::GpRegisters; @@ -25,4 +25,5 @@ pub enum MipsStateUpdate { UpdateState(DatapathState), UpdateRegisters(GpRegisters), UpdateMemory(Memory), + UpdateStage(Stage) } diff --git a/src/bin/main.rs b/src/bin/main.rs index c8bb7021d..5579ab39a 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -16,7 +16,6 @@ use std::rc::Rc; use swim::agent::datapath_communicator::DatapathCommunicator; use swim::agent::datapath_reducer::DatapathReducer; use swim::agent::EmulationCoreAgent; -use swim::emulation_core::datapath::Datapath; use swim::emulation_core::mips::datapath::MipsDatapath; use swim::emulation_core::mips::datapath::Stage; use swim::ui::footer::component::Footer; @@ -106,11 +105,10 @@ fn app(props: &AppProps) -> Html { // This is where code is assembled and loaded into the emulation core's memory. let on_assemble_clicked = { // props.communicator.send_test_message(1); // Test message, remove later. - let communicator = props.communicator; + // let communicator = props.communicator; let text_model = text_model.clone(); let memory_text_model = memory_text_model.clone(); let memory_curr_instr = memory_curr_instr.clone(); - let datapath = Rc::clone(&datapath); let datapath_state = datapath_state.clone(); let parser_text_output = parser_text_output.clone(); let trigger = use_force_update(); @@ -124,7 +122,6 @@ fn app(props: &AppProps) -> Html { use_callback( move |_, (text_model, editor_curr_line, memory_curr_instr, datapath_state)| { - let mut datapath = datapath.borrow_mut(); let text_model = text_model.clone(); let memory_text_model = memory_text_model.clone(); // parses through the code to assemble the binary and retrieves programinfo for error marking and mouse hover @@ -169,22 +166,12 @@ fn app(props: &AppProps) -> Html { // Proceed with loading into memory and expand pseudo-instructions if there are no errors. if marker_jsarray.length() == 0 { - // Load the binary into the datapath's memory - match datapath.initialize_legacy(assembled.clone()) { - Ok(_) => (), - Err(msg) => { - // In the case of an error, note this and stop early. - parser_text_output.set(format!("This program failed to load into the datapath. Message returned by datapath: {msg}")); - } - } - memory_curr_instr.set(datapath.registers.pc); - // log!(datapath.memory.to_string()); + // Send the binary over to the emulation core thread + communicator.initialize(program_info.pc_starting_point, assembled); + memory_curr_instr.set(datapath_state.mips.registers.pc); text_model.set_value(&program_info.updated_monaco_string); // Expands pseudo-instructions to their hardware counterpart. let hexdump = &datapath_state.mips.memory.generate_formatted_hex(); memory_text_model.set_value(hexdump); - datapath.registers.pc = program_info.pc_starting_point as u64; - // Send the binary over to the emulation core thread - communicator.initialize(program_info.pc_starting_point, assembled) } trigger.force_update(); @@ -200,7 +187,6 @@ fn app(props: &AppProps) -> Html { // syscall instruction, which will halt the datapath. As you execute the // code, the previously executed line is highlighted. let on_execute_clicked = { - let datapath = Rc::clone(&datapath); let datapath_state = datapath_state.clone(); let program_info_ref = Rc::clone(&program_info_ref); @@ -216,19 +202,17 @@ fn app(props: &AppProps) -> Html { use_callback( move |_, (editor_curr_line, memory_curr_instr, datapath_state)| { - let mut datapath = datapath.borrow_mut(); let memory_text_model = memory_text_model.clone(); // Get the current line and convert it to f64 let programinfo = Rc::clone(&program_info_ref); let programinfo = programinfo.borrow().clone(); let list_of_line_numbers = programinfo.address_to_line_number; - let index = datapath.registers.pc as usize / 4; + let index = datapath_state.mips.registers.pc as usize / 4; editor_curr_line.set(*list_of_line_numbers.get(index).unwrap_or(&0) as f64 + 1.0); // add one to account for the editor's line numbers - memory_curr_instr.set(datapath.registers.pc); + memory_curr_instr.set(datapath_state.mips.registers.pc); // Execute instruction - datapath.execute_instruction(); communicator.execute_instruction(); // Update memory @@ -243,9 +227,9 @@ fn app(props: &AppProps) -> Html { }; let on_execute_stage_clicked = { - let datapath = Rc::clone(&datapath); let datapath_state = datapath_state.clone(); let program_info_ref = Rc::clone(&program_info_ref); + let communicator = props.communicator; // Code editor let editor_curr_line = editor_curr_line.clone(); @@ -258,21 +242,19 @@ fn app(props: &AppProps) -> Html { use_callback( move |_, (editor_curr_line, memory_curr_instr, datapath_state)| { - let mut datapath = datapath.borrow_mut(); - let memory_text_model = memory_text_model.clone(); - if datapath.current_stage == Stage::InstructionDecode { + if datapath_state.mips.current_stage == Stage::InstructionDecode { // highlight on InstructionDecode since syscall stops at that stage. let programinfo = Rc::clone(&program_info_ref); let programinfo = programinfo.borrow().clone(); let list_of_line_numbers = programinfo.address_to_line_number; - let index = datapath.registers.pc as usize / 4; + let index = datapath_state.mips.registers.pc as usize / 4; editor_curr_line.set(*list_of_line_numbers.get(index).unwrap_or(&0) as f64 + 1.0); - memory_curr_instr.set(datapath.registers.pc); - datapath.execute_stage(); + memory_curr_instr.set(datapath_state.mips.registers.pc); + communicator.execute_stage(); } else { - datapath.execute_stage(); + communicator.execute_stage(); } // Update memory @@ -414,7 +396,7 @@ fn app(props: &AppProps) -> Html { // This is how we will reset the datapath. // This will also clear any highlight on the editor. let on_reset_clicked = { - let datapath = Rc::clone(&datapath); + let datapath_state = datapath_state.clone(); let trigger = use_force_update(); let parser_text_output = parser_text_output.clone(); let communicator = props.communicator; @@ -428,15 +410,14 @@ fn app(props: &AppProps) -> Html { let memory_curr_instr = memory_curr_instr.clone(); use_callback( - move |_, editor_curr_line| { - let mut datapath = datapath.borrow_mut(); + move |_, (editor_curr_line, datapath_state)| { // Set highlighted line to 0 editor_curr_line.set(0.0); - memory_curr_instr.set(datapath.registers.pc); + memory_curr_instr.set(datapath_state.mips.registers.pc); parser_text_output.set("".to_string()); - datapath.reset(); + communicator.reset(); // Clear hex editor content let memory_text_model = memory_text_model.clone(); @@ -446,7 +427,7 @@ fn app(props: &AppProps) -> Html { communicator.reset(); trigger.force_update(); }, - editor_curr_line, + (editor_curr_line, datapath_state), ) }; @@ -504,8 +485,8 @@ fn app(props: &AppProps) -> Html {
- - + + // @@ -517,7 +498,7 @@ fn app(props: &AppProps) -> Html { // Editor
- +
// Console diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index 3d7341b9c..0d73035fc 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -55,6 +55,7 @@ pub trait Datapath { /// Retrieve all memory as-is. fn get_memory(&self) -> &Memory; + // Store word in memory at ptr fn set_memory(&mut self, ptr: u64, data: u32); /// Returns if the datapath is in a "halted" or "stopped" state. This may diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index f5d46eaf7..7eca803f6 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -163,7 +163,7 @@ pub struct DatapathState { } /// The possible stages the datapath could be in during execution. -#[derive(Clone, Copy, Default, Eq, PartialEq)] +#[derive(Clone, Copy, Default, Eq, PartialEq, Debug, Serialize, Deserialize)] pub enum Stage { #[default] InstructionFetch, From 0a84ae3998e09bcad6f41109554b6629a44b1ae1 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Wed, 15 Nov 2023 18:13:08 -0500 Subject: [PATCH 059/355] Separate the main binary from a worker binary --- index.html | 2 ++ src/{ => bin}/main.rs | 20 +++++++------------- src/bin/worker.rs | 5 +++++ src/lib.rs | 5 +++++ 4 files changed, 19 insertions(+), 13 deletions(-) rename src/{ => bin}/main.rs (98%) create mode 100644 src/bin/worker.rs create mode 100644 src/lib.rs diff --git a/index.html b/index.html index 7d62cbe60..169778ced 100644 --- a/index.html +++ b/index.html @@ -2,6 +2,8 @@ + + diff --git a/src/main.rs b/src/bin/main.rs similarity index 98% rename from src/main.rs rename to src/bin/main.rs index a59835a88..fb589b86d 100644 --- a/src/main.rs +++ b/src/bin/main.rs @@ -1,12 +1,6 @@ -pub mod emulation_core; -pub mod parser; -#[cfg(test)] -pub mod tests; -pub mod ui; - -use emulation_core::datapath::Datapath; -use emulation_core::mips::datapath::MipsDatapath; -use emulation_core::mips::datapath::Stage; +use swim::emulation_core::datapath::Datapath; +use swim::emulation_core::mips::datapath::MipsDatapath; +use swim::emulation_core::mips::datapath::Stage; use gloo::{dialogs::alert, file::FileList}; use js_sys::Object; use monaco::{ @@ -20,10 +14,10 @@ use monaco::{ }, yew::CodeEditor, }; -use parser::parser_assembler_main::parser; +use swim::parser::parser_assembler_main::parser; use std::rc::Rc; -use ui::console::component::Console; -use ui::regview::component::Regview; +use swim::ui::console::component::Console; +use swim::ui::regview::component::Regview; use wasm_bindgen::{JsCast, JsValue}; use wasm_bindgen_futures::spawn_local; use web_sys::HtmlInputElement; @@ -34,7 +28,7 @@ use yew_hooks::prelude::*; // To load in the Fibonacci example, uncomment the CONTENT and fib_model lines // and comment the code, language, and text_model lines. IMPORTANT: // rename fib_model to text_model to have it work. -const CONTENT: &str = include_str!("../static/assembly_examples/fibonacci.asm"); +const CONTENT: &str = include_str!("../../static/assembly_examples/fibonacci.asm"); #[function_component(App)] fn app() -> Html { diff --git a/src/bin/worker.rs b/src/bin/worker.rs new file mode 100644 index 000000000..3071854da --- /dev/null +++ b/src/bin/worker.rs @@ -0,0 +1,5 @@ +use gloo_console::log; + +fn main() { + log!("Hello world from the worker!") +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 000000000..cad0e1f1a --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,5 @@ +pub mod emulation_core; +pub mod parser; +#[cfg(test)] +pub mod tests; +pub mod ui; \ No newline at end of file From 69235deeb6276aa1c9dd5f5bc21196b84e9c7fd5 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Sun, 26 Nov 2023 18:17:03 -0500 Subject: [PATCH 060/355] Implement basic agent code --- src/bin/worker.rs | 5 +++-- src/emulation_core/agent.rs | 13 +++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 src/emulation_core/agent.rs diff --git a/src/bin/worker.rs b/src/bin/worker.rs index 3071854da..5430906de 100644 --- a/src/bin/worker.rs +++ b/src/bin/worker.rs @@ -1,5 +1,6 @@ -use gloo_console::log; +use yew_agent::Registrable; +use swim::emulation_core::agent::EmulationCoreAgent; fn main() { - log!("Hello world from the worker!") + EmulationCoreAgent::registrar().register(); } \ No newline at end of file diff --git a/src/emulation_core/agent.rs b/src/emulation_core/agent.rs new file mode 100644 index 000000000..ef960e1af --- /dev/null +++ b/src/emulation_core/agent.rs @@ -0,0 +1,13 @@ +use yew_agent::prelude::*; +use futures::{SinkExt, StreamExt}; +use serde::{Deserialize, Serialize}; +use gloo_console::log; + +#[reactor(EmulationCoreAgent)] +pub async fn emulation_core_agent(mut scope: ReactorScope) { + log!("Hello world!"); + scope.send(1).await.unwrap(); + loop { + let _msg = scope.next().await; + } +} From c62d811a68aae06089b0abec30ad609b67585ced Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Sun, 26 Nov 2023 19:27:23 -0500 Subject: [PATCH 061/355] Spawn newly created worker thread --- Cargo.lock | 848 +++++++++++++++++++++++++++++++----------- Cargo.toml | 3 + src/bin/main.rs | 3 + src/emulation_core.rs | 1 + 4 files changed, 640 insertions(+), 215 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 353001015..c63c9c952 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "akin" version = "0.4.0" @@ -20,6 +35,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "bincode" version = "1.3.3" @@ -37,9 +67,24 @@ checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9" [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "bytes" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -57,23 +102,36 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "futures" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" dependencies = [ "futures-channel", "futures-core", + "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -82,9 +140,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", "futures-sink", @@ -92,44 +150,55 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" + +[[package]] +name = "futures-executor" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] [[package]] name = "futures-io" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-macro" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] name = "futures-sink" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-util" -version = "0.3.26" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-channel", "futures-core", @@ -143,23 +212,61 @@ dependencies = [ "slab", ] +[[package]] +name = "getrandom" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "gloo" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28999cda5ef6916ffd33fb4a7b87e1de633c47c0dc6d97905fee1cdaa142b94d" +dependencies = [ + "gloo-console 0.2.3", + "gloo-dialogs 0.1.1", + "gloo-events 0.1.2", + "gloo-file 0.2.3", + "gloo-history 0.1.5", + "gloo-net 0.3.1", + "gloo-render 0.1.1", + "gloo-storage 0.2.2", + "gloo-timers 0.2.6", + "gloo-utils 0.1.7", + "gloo-worker 0.2.1", +] + [[package]] name = "gloo" -version = "0.8.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a4bef6b277b3ab073253d4bca60761240cf8d6998f4bd142211957b69a61b20" +checksum = "cd35526c28cc55c1db77aed6296de58677dbab863b118483a27845631d870249" dependencies = [ - "gloo-console", - "gloo-dialogs", - "gloo-events", - "gloo-file", - "gloo-history", - "gloo-net", - "gloo-render", - "gloo-storage", - "gloo-timers", - "gloo-utils", - "gloo-worker", + "gloo-console 0.3.0", + "gloo-dialogs 0.2.0", + "gloo-events 0.2.0", + "gloo-file 0.3.0", + "gloo-history 0.2.1", + "gloo-net 0.4.0", + "gloo-render 0.2.0", + "gloo-storage 0.3.0", + "gloo-timers 0.3.0", + "gloo-utils 0.2.0", + "gloo-worker 0.4.0", ] [[package]] @@ -168,7 +275,20 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82b7ce3c05debe147233596904981848862b068862e9ec3e34be446077190d3f" dependencies = [ - "gloo-utils", + "gloo-utils 0.1.7", + "js-sys", + "serde", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-console" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a17868f56b4a24f677b17c8cb69958385102fa879418052d60b50bc1727e261" +dependencies = [ + "gloo-utils 0.2.0", "js-sys", "serde", "wasm-bindgen", @@ -185,6 +305,16 @@ dependencies = [ "web-sys", ] +[[package]] +name = "gloo-dialogs" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4748e10122b01435750ff530095b1217cf6546173459448b83913ebe7815df" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + [[package]] name = "gloo-events" version = "0.1.2" @@ -195,6 +325,16 @@ dependencies = [ "web-sys", ] +[[package]] +name = "gloo-events" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27c26fb45f7c385ba980f5fa87ac677e363949e065a083722697ef1b2cc91e41" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + [[package]] name = "gloo-file" version = "0.2.3" @@ -202,7 +342,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d5564e570a38b43d78bdc063374a0c3098c4f0d64005b12f9bbe87e869b6d7" dependencies = [ "futures-channel", - "gloo-events", + "gloo-events 0.1.2", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-file" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97563d71863fb2824b2e974e754a81d19c4a7ec47b09ced8a0e6656b6d54bd1f" +dependencies = [ + "gloo-events 0.2.0", "js-sys", "wasm-bindgen", "web-sys", @@ -210,14 +362,31 @@ dependencies = [ [[package]] name = "gloo-history" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd451019e0b7a2b8a7a7b23e74916601abf1135c54664e57ff71dcc26dfcdeb7" +checksum = "85725d90bf0ed47063b3930ef28e863658a7905989e9929a8708aab74a1d5e7f" dependencies = [ - "gloo-events", - "gloo-utils", + "gloo-events 0.1.2", + "gloo-utils 0.1.7", "serde", - "serde-wasm-bindgen", + "serde-wasm-bindgen 0.5.0", + "serde_urlencoded", + "thiserror", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-history" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4022e82f5f9e03cb1251b13c0a967e0600e97aa179c617f6519bac40640160" +dependencies = [ + "getrandom", + "gloo-events 0.2.0", + "gloo-utils 0.2.0", + "serde", + "serde-wasm-bindgen 0.6.1", "serde_urlencoded", "thiserror", "wasm-bindgen", @@ -226,14 +395,36 @@ dependencies = [ [[package]] name = "gloo-net" -version = "0.2.6" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a66b4e3c7d9ed8d315fd6b97c8b1f74a7c6ecbbc2320e65ae7ed38b7068cc620" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils 0.1.7", + "http", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "gloo-net" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9902a044653b26b99f7e3693a42f171312d9be8b26b5697bd1e43ad1f8a35e10" +checksum = "8ac9e8288ae2c632fa9f8657ac70bfe38a1530f345282d7ba66a1f70b72b7dc4" dependencies = [ "futures-channel", "futures-core", "futures-sink", - "gloo-utils", + "gloo-utils 0.2.0", + "http", "js-sys", "pin-project", "serde", @@ -254,13 +445,38 @@ dependencies = [ "web-sys", ] +[[package]] +name = "gloo-render" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56008b6744713a8e8d98ac3dcb7d06543d5662358c9c805b4ce2167ad4649833" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + [[package]] name = "gloo-storage" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d6ab60bf5dbfd6f0ed1f7843da31b41010515c745735c970e821945ca91e480" dependencies = [ - "gloo-utils", + "gloo-utils 0.1.7", + "js-sys", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-storage" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc8031e8c92758af912f9bc08fbbadd3c6f3cfcbf6b64cdf3d6a81f0139277a" +dependencies = [ + "gloo-utils 0.2.0", "js-sys", "serde", "serde_json", @@ -281,11 +497,34 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "gloo-utils" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8e8fc851e9c7b9852508bc6e3f690f452f474417e8545ec9857b7f7377036b5" +checksum = "037fcb07216cb3a30f7292bd0176b050b7b9a052ba830ef7d5d65f6dc64ba58e" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gloo-utils" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa" dependencies = [ "js-sys", "serde", @@ -302,8 +541,8 @@ checksum = "13471584da78061a28306d1359dd0178d8d6fc1c7c80e5e35d27260346e0516a" dependencies = [ "anymap2", "bincode", - "gloo-console", - "gloo-utils", + "gloo-console 0.2.3", + "gloo-utils 0.1.7", "js-sys", "serde", "wasm-bindgen", @@ -311,12 +550,49 @@ dependencies = [ "web-sys", ] +[[package]] +name = "gloo-worker" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76495d3dd87de51da268fa3a593da118ab43eb7f8809e17eb38d3319b424e400" +dependencies = [ + "bincode", + "futures", + "gloo-utils 0.2.0", + "gloo-worker-macros", + "js-sys", + "pinned", + "serde", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "gloo-worker-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956caa58d4857bc9941749d55e4bd3000032d8212762586fa5705632967140e7" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[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" @@ -325,43 +601,81 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.2.6" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "http" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ - "libc", + "bytes", + "fnv", + "itoa", ] [[package]] name = "implicit-clone" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40fc102e70475c320b185cd18c1e48bba2d7210b63970a4d581ef903e4368ef7" +checksum = "7c6ecbd987bb94f1f3c76c6787879756cf4b6f73bfff48d79308e8c56b46f65f" dependencies = [ - "indexmap", + "indexmap 1.9.3", +] + +[[package]] +name = "implicit-clone" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc06a255cbf402a52ae399c05a518c68c569c916ea11423620111df576b9b9bb" +dependencies = [ + "implicit-clone-derive", + "indexmap 2.1.0", +] + +[[package]] +name = "implicit-clone-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9311685eb9a34808bbb0608ad2fcab9ae216266beca5848613e95553ac914e3b" +dependencies = [ + "quote", + "syn 2.0.39", ] [[package]] name = "indexmap" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", ] [[package]] name = "itoa" -version = "1.0.5" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" -version = "0.3.61" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" dependencies = [ "wasm-bindgen", ] @@ -374,24 +688,30 @@ checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" [[package]] name = "libc" -version = "0.2.139" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "log" -version = "0.4.17" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] [[package]] name = "monaco" @@ -402,62 +722,71 @@ dependencies = [ "paste", "wasm-bindgen", "web-sys", - "yew", + "yew 0.20.0", ] [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ "hermit-abi", "libc", ] +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "paste" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project" -version = "1.0.12" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.12" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -478,12 +807,32 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.1.23" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97e3215779627f01ee256d2fad52f3d95e8e1c11e9fc6fd08f7cd455d5d5c78" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" dependencies = [ "proc-macro2", - "syn", + "syn 1.0.109", +] + +[[package]] +name = "prettyplease" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" +dependencies = [ + "proc-macro2", + "syn 2.0.39", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", ] [[package]] @@ -495,7 +844,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "version_check", ] @@ -512,9 +861,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.51" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" dependencies = [ "unicode-ident", ] @@ -526,7 +875,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03b55e106e5791fa5a13abd13c85d6127312e8e09098059ca2bc9b03ca4cf488" dependencies = [ "futures", - "gloo", + "gloo 0.8.1", "num_cpus", "once_cell", "pin-project", @@ -538,39 +887,56 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.23" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustversion" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.12" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "serde" -version = "1.0.152" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde-wasm-bindgen" -version = "0.4.5" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf" +checksum = "17ba92964781421b6cef36bf0d7da26d201e96d84e1b10e7ae6ed416e516906d" dependencies = [ "js-sys", "serde", @@ -579,20 +945,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.152" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] name = "serde_json" -version = "1.0.93" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -613,9 +979,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] @@ -636,7 +1002,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn", + "syn 1.0.109", ] [[package]] @@ -644,27 +1010,41 @@ name = "swim" version = "0.1.0" dependencies = [ "akin", - "gloo", - "gloo-console", - "gloo-events", - "gloo-utils", + "futures", + "gloo 0.8.1", + "gloo-console 0.2.3", + "gloo-events 0.1.2", + "gloo-utils 0.1.7", "js-sys", "levenshtein", "monaco", + "serde", "strum", "strum_macros", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "yew", + "yew 0.20.0", + "yew-agent", "yew-hooks", ] [[package]] name = "syn" -version = "1.0.107" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -673,53 +1053,68 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] name = "tokio" -version = "1.25.0" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ - "autocfg", + "backtrace", "pin-project-lite", - "windows-sys", ] [[package]] name = "tokio-stream" -version = "0.1.11" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", "pin-project-lite", "tokio", ] +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.1.0", + "toml_datetime", + "winnow", +] + [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -727,29 +1122,29 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "version_check" @@ -757,11 +1152,17 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -769,24 +1170,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.39", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.34" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" dependencies = [ "cfg-if", "js-sys", @@ -796,9 +1197,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -806,101 +1207,78 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.39", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" [[package]] name = "web-sys" -version = "0.3.61" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] -name = "windows-sys" -version = "0.42.0" +name = "winnow" +version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "memchr", ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.1" +name = "yew" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +checksum = "5dbecfe44343b70cc2932c3eb445425969ae21754a8ab3a0966981c1cf7af1cc" +dependencies = [ + "console_error_panic_hook", + "futures", + "gloo 0.8.1", + "implicit-clone 0.3.6", + "indexmap 1.9.3", + "js-sys", + "prokio", + "rustversion", + "serde", + "slab", + "thiserror", + "tokio", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "yew-macro 0.20.0", +] [[package]] name = "yew" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dbecfe44343b70cc2932c3eb445425969ae21754a8ab3a0966981c1cf7af1cc" +checksum = "5f1a03f255c70c7aa3e9c62e15292f142ede0564123543c1cc0c7a4f31660cac" dependencies = [ "console_error_panic_hook", "futures", - "gloo", - "implicit-clone", - "indexmap", + "gloo 0.10.0", + "implicit-clone 0.4.8", + "indexmap 2.1.0", "js-sys", "prokio", "rustversion", @@ -912,7 +1290,32 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "yew-macro", + "yew-macro 0.21.0", +] + +[[package]] +name = "yew-agent" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e27eaca61ea9d0e1a6589dce592283b0e62ced527d8a8b28447957295d588f5" +dependencies = [ + "futures", + "gloo-worker 0.4.0", + "serde", + "wasm-bindgen", + "yew 0.21.0", + "yew-agent-macro", +] + +[[package]] +name = "yew-agent-macro" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ad00f6c9436d25c9225ed0fd8eea27e6d2886c1387bf934afdf91e9131b8b77" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", ] [[package]] @@ -921,14 +1324,14 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "268e2367720311f19582235f5c021702d6be8ded13b7ee8dcacc71019d055d15" dependencies = [ - "gloo", + "gloo 0.8.1", "js-sys", "log", "serde", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "yew", + "yew 0.20.0", ] [[package]] @@ -939,9 +1342,24 @@ checksum = "b64c253c1d401f1ea868ca9988db63958cfa15a69f739101f338d6f05eea8301" dependencies = [ "boolinator", "once_cell", - "prettyplease", + "prettyplease 0.1.25", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "yew-macro" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02fd8ca5166d69e59f796500a2ce432ff751edecbbb308ca59fd3fe4d0343de2" +dependencies = [ + "boolinator", + "once_cell", + "prettyplease 0.2.15", "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 2.0.39", ] diff --git a/Cargo.toml b/Cargo.toml index c78e1ac3c..00af8ce40 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,9 @@ wasm-bindgen-futures = "0.4.33" web-sys = {version = "0.3.60", features = ["CssStyleDeclaration", "Event", "HtmlCollection", "HtmlElement", "HtmlInputElement", "HtmlObjectElement", "SvgElement"]} yew = {version = "0.20.0", features = ["csr"] } yew-hooks = "0.2.0" +yew-agent = "0.3.0" +serde = "1.0.193" +futures = "0.3.29" # Parser / Assembler levenshtein = "1.0.5" diff --git a/src/bin/main.rs b/src/bin/main.rs index fb589b86d..dbea2550c 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,6 +1,7 @@ use swim::emulation_core::datapath::Datapath; use swim::emulation_core::mips::datapath::MipsDatapath; use swim::emulation_core::mips::datapath::Stage; +use swim::emulation_core::agent::EmulationCoreAgent; use gloo::{dialogs::alert, file::FileList}; use js_sys::Object; use monaco::{ @@ -24,6 +25,7 @@ use web_sys::HtmlInputElement; use yew::prelude::*; use yew::{html, Html, Properties}; use yew_hooks::prelude::*; +use yew_agent::Spawnable; // To load in the Fibonacci example, uncomment the CONTENT and fib_model lines // and comment the code, language, and text_model lines. IMPORTANT: @@ -532,5 +534,6 @@ pub fn on_upload_file_clicked() { } fn main() { + let bridge = EmulationCoreAgent::spawner().spawn("./worker.js"); yew::Renderer::::new().render(); } diff --git a/src/emulation_core.rs b/src/emulation_core.rs index e62a37920..74cad3ccc 100644 --- a/src/emulation_core.rs +++ b/src/emulation_core.rs @@ -2,3 +2,4 @@ pub mod datapath; pub mod mips; +pub mod agent; \ No newline at end of file From 7b79fc0e27417a4cfc190e1901774d04723a7739 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Sun, 26 Nov 2023 19:46:08 -0500 Subject: [PATCH 062/355] Implement basic DatapathCommunicator and listen_for_updates function (design pending) --- src/emulation_core.rs | 3 ++- src/emulation_core/datapath_communicator.rs | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/emulation_core/datapath_communicator.rs diff --git a/src/emulation_core.rs b/src/emulation_core.rs index 74cad3ccc..0d8e00947 100644 --- a/src/emulation_core.rs +++ b/src/emulation_core.rs @@ -2,4 +2,5 @@ pub mod datapath; pub mod mips; -pub mod agent; \ No newline at end of file +pub mod agent; +mod datapath_communicator; \ No newline at end of file diff --git a/src/emulation_core/datapath_communicator.rs b/src/emulation_core/datapath_communicator.rs new file mode 100644 index 000000000..ab085d8d1 --- /dev/null +++ b/src/emulation_core/datapath_communicator.rs @@ -0,0 +1,21 @@ +use futures::stream::{SplitSink, SplitStream}; +use futures::StreamExt; +use gloo_console::log; +use yew::UseForceUpdateHandle; +use yew_agent::reactor::ReactorBridge; +use crate::emulation_core::agent::EmulationCoreAgent; + +pub struct DatapathCommunicator { + writer: SplitSink, i32>, + reader: SplitStream>, +} + +impl DatapathCommunicator { + pub async fn listen_for_updates(&mut self, update_handle: UseForceUpdateHandle) { + loop { + let update = self.reader.next().await; + log!(format!("Got update {:?}", update)); + update_handle.force_update(); + } + } +} \ No newline at end of file From f4a3b4ee1291bd257479777c36c7cad6f4761cec Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 18 Jan 2024 15:34:23 -0500 Subject: [PATCH 063/355] Implement sending/receving from worker thread --- src/bin/main.rs | 46 +++++++++++++++++---- src/bin/worker.rs | 4 +- src/emulation_core.rs | 4 +- src/emulation_core/agent.rs | 6 +-- src/emulation_core/datapath_communicator.rs | 42 ++++++++++++++++--- src/lib.rs | 2 +- 6 files changed, 82 insertions(+), 22 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index dbea2550c..4971eacad 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,7 +1,3 @@ -use swim::emulation_core::datapath::Datapath; -use swim::emulation_core::mips::datapath::MipsDatapath; -use swim::emulation_core::mips::datapath::Stage; -use swim::emulation_core::agent::EmulationCoreAgent; use gloo::{dialogs::alert, file::FileList}; use js_sys::Object; use monaco::{ @@ -15,8 +11,13 @@ use monaco::{ }, yew::CodeEditor, }; -use swim::parser::parser_assembler_main::parser; use std::rc::Rc; +use swim::emulation_core::agent::EmulationCoreAgent; +use swim::emulation_core::datapath::Datapath; +use swim::emulation_core::datapath_communicator::DatapathCommunicator; +use swim::emulation_core::mips::datapath::MipsDatapath; +use swim::emulation_core::mips::datapath::Stage; +use swim::parser::parser_assembler_main::parser; use swim::ui::console::component::Console; use swim::ui::regview::component::Regview; use wasm_bindgen::{JsCast, JsValue}; @@ -24,16 +25,29 @@ use wasm_bindgen_futures::spawn_local; use web_sys::HtmlInputElement; use yew::prelude::*; use yew::{html, Html, Properties}; -use yew_hooks::prelude::*; use yew_agent::Spawnable; +use yew_hooks::prelude::*; // To load in the Fibonacci example, uncomment the CONTENT and fib_model lines // and comment the code, language, and text_model lines. IMPORTANT: // rename fib_model to text_model to have it work. const CONTENT: &str = include_str!("../../static/assembly_examples/fibonacci.asm"); +#[derive(Properties, Clone)] +struct AppProps { + communicator: &'static DatapathCommunicator, +} + +impl PartialEq for AppProps { + fn eq(&self, other: &Self) -> bool { + let self_ptr: *const Self = self; + let other_ptr: *const Self = other; + self_ptr == other_ptr + } +} + #[function_component(App)] -fn app() -> Html { +fn app(props: &AppProps) -> Html { // This contains the binary representation of "ori $s0, $zero, 12345", which // stores 12345 in register $s0. // let code = String::from("ori $s0, $zero, 12345\n"); @@ -78,8 +92,18 @@ fn app() -> Html { // the ability to access and change its contents be mutable. let datapath = use_mut_ref(MipsDatapath::default); + // Start listening for messages from the communicator + { + let trigger = use_force_update(); + let communicator = props.communicator; + use_effect(move || { + spawn_local(communicator.listen_for_updates(trigger)); + }); + } + // This is where code is assembled and loaded into the emulation core's memory. let on_assemble_clicked = { + props.communicator.send_test_message(); let text_model = Rc::clone(&text_model); let datapath = Rc::clone(&datapath); let parser_text_output = parser_text_output.clone(); @@ -534,6 +558,12 @@ pub fn on_upload_file_clicked() { } fn main() { + // Initialize and leak the communicator to ensure that the thread spawns immediately and the bridge to it lives + // for the remainder of the program. let bridge = EmulationCoreAgent::spawner().spawn("./worker.js"); - yew::Renderer::::new().render(); + let communicator = Box::new(DatapathCommunicator::new(bridge)); + yew::Renderer::::with_props(AppProps { + communicator: Box::leak(communicator), + }) + .render(); } diff --git a/src/bin/worker.rs b/src/bin/worker.rs index 5430906de..f02e1b997 100644 --- a/src/bin/worker.rs +++ b/src/bin/worker.rs @@ -1,6 +1,6 @@ -use yew_agent::Registrable; use swim::emulation_core::agent::EmulationCoreAgent; +use yew_agent::Registrable; fn main() { EmulationCoreAgent::registrar().register(); -} \ No newline at end of file +} diff --git a/src/emulation_core.rs b/src/emulation_core.rs index 0d8e00947..7fcb1c723 100644 --- a/src/emulation_core.rs +++ b/src/emulation_core.rs @@ -1,6 +1,6 @@ //! The emulation core for the project. +pub mod agent; pub mod datapath; +pub mod datapath_communicator; pub mod mips; -pub mod agent; -mod datapath_communicator; \ No newline at end of file diff --git a/src/emulation_core/agent.rs b/src/emulation_core/agent.rs index ef960e1af..eb89d7526 100644 --- a/src/emulation_core/agent.rs +++ b/src/emulation_core/agent.rs @@ -1,13 +1,13 @@ -use yew_agent::prelude::*; use futures::{SinkExt, StreamExt}; -use serde::{Deserialize, Serialize}; use gloo_console::log; +use yew_agent::prelude::*; #[reactor(EmulationCoreAgent)] pub async fn emulation_core_agent(mut scope: ReactorScope) { log!("Hello world!"); scope.send(1).await.unwrap(); loop { - let _msg = scope.next().await; + let msg = scope.next().await; + log!("Got message: ", msg); } } diff --git a/src/emulation_core/datapath_communicator.rs b/src/emulation_core/datapath_communicator.rs index ab085d8d1..b90a0d9eb 100644 --- a/src/emulation_core/datapath_communicator.rs +++ b/src/emulation_core/datapath_communicator.rs @@ -1,21 +1,51 @@ +use crate::emulation_core::agent::EmulationCoreAgent; use futures::stream::{SplitSink, SplitStream}; +use futures::FutureExt; +use futures::SinkExt; use futures::StreamExt; use gloo_console::log; +use gloo_console::warn; +use std::cell::RefCell; use yew::UseForceUpdateHandle; use yew_agent::reactor::ReactorBridge; -use crate::emulation_core::agent::EmulationCoreAgent; pub struct DatapathCommunicator { - writer: SplitSink, i32>, - reader: SplitStream>, + writer: RefCell, i32>>, + reader: RefCell>>, } impl DatapathCommunicator { - pub async fn listen_for_updates(&mut self, update_handle: UseForceUpdateHandle) { + pub fn new(bridge: ReactorBridge) -> DatapathCommunicator { + let (write, read) = bridge.split(); + DatapathCommunicator { + writer: RefCell::new(write), + reader: RefCell::new(read), + } + } + + #[allow(clippy::await_holding_refcell_ref)] + pub async fn listen_for_updates(&self, update_handle: UseForceUpdateHandle) { + let mut reader = match self.reader.try_borrow_mut() { + Ok(reader) => reader, + Err(_) => { + warn!("Warning: Attempted to listen for updates multiple times"); + return; + } + }; + loop { - let update = self.reader.next().await; + let update = reader.next().await; log!(format!("Got update {:?}", update)); update_handle.force_update(); } } -} \ No newline at end of file + + pub fn send_test_message(&self) { + let mut writer = self.writer.borrow_mut(); + writer + .send(1) + .now_or_never() + .expect("Send function did not immediately return, async logic needed.") + .expect("Sending test message error") + } +} diff --git a/src/lib.rs b/src/lib.rs index cad0e1f1a..52b5b61b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,4 +2,4 @@ pub mod emulation_core; pub mod parser; #[cfg(test)] pub mod tests; -pub mod ui; \ No newline at end of file +pub mod ui; From 7d2070b6ca749cab02254829b6cf5af50995e411 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Fri, 19 Jan 2024 16:52:09 -0500 Subject: [PATCH 064/355] Add documentation --- src/{emulation_core => }/agent.rs | 6 ++++++ .../datapath_communicator.rs | 13 ++++++++++++- src/bin/main.rs | 9 +++++---- src/bin/worker.rs | 2 +- src/emulation_core.rs | 2 -- src/lib.rs | 1 + 6 files changed, 25 insertions(+), 8 deletions(-) rename src/{emulation_core => }/agent.rs (54%) rename src/{emulation_core => agent}/datapath_communicator.rs (67%) diff --git a/src/emulation_core/agent.rs b/src/agent.rs similarity index 54% rename from src/emulation_core/agent.rs rename to src/agent.rs index eb89d7526..5a674cec3 100644 --- a/src/emulation_core/agent.rs +++ b/src/agent.rs @@ -1,7 +1,13 @@ +//! The agent responsible for running the emulator core on the worker thread and communication functionalities. + use futures::{SinkExt, StreamExt}; use gloo_console::log; use yew_agent::prelude::*; +pub mod datapath_communicator; + +/// The main logic for the emulation core agent. All code within this function runs on a worker thread as opposed to +/// the UI thread. #[reactor(EmulationCoreAgent)] pub async fn emulation_core_agent(mut scope: ReactorScope) { log!("Hello world!"); diff --git a/src/emulation_core/datapath_communicator.rs b/src/agent/datapath_communicator.rs similarity index 67% rename from src/emulation_core/datapath_communicator.rs rename to src/agent/datapath_communicator.rs index b90a0d9eb..abd87b247 100644 --- a/src/emulation_core/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -1,4 +1,4 @@ -use crate::emulation_core::agent::EmulationCoreAgent; +use crate::agent::EmulationCoreAgent; use futures::stream::{SplitSink, SplitStream}; use futures::FutureExt; use futures::SinkExt; @@ -9,12 +9,18 @@ use std::cell::RefCell; use yew::UseForceUpdateHandle; use yew_agent::reactor::ReactorBridge; +/// This struct provides an abstraction over all communication with the worker thread. Any commands to the worker +/// thread should be sent by calling a function on this struct. +/// +/// The DatapathCommunicator will also handle receiving information about the state of the emulation core and maintain +/// internal state that can be displayed by the UI. pub struct DatapathCommunicator { writer: RefCell, i32>>, reader: RefCell>>, } impl DatapathCommunicator { + /// Initialize the DatapathCommunicator using a bridge. pub fn new(bridge: ReactorBridge) -> DatapathCommunicator { let (write, read) = bridge.split(); DatapathCommunicator { @@ -23,6 +29,9 @@ impl DatapathCommunicator { } } + /// Listen for updates from the worker thread and update internal state accordingly. This function should be called + /// from the main app component. After updating internal state, the component this was called from will be force + /// updated. #[allow(clippy::await_holding_refcell_ref)] pub async fn listen_for_updates(&self, update_handle: UseForceUpdateHandle) { let mut reader = match self.reader.try_borrow_mut() { @@ -40,10 +49,12 @@ impl DatapathCommunicator { } } + /// Sends a test message to the worker thread. pub fn send_test_message(&self) { let mut writer = self.writer.borrow_mut(); writer .send(1) + // The .now_or_never() .expect("Send function did not immediately return, async logic needed.") .expect("Sending test message error") diff --git a/src/bin/main.rs b/src/bin/main.rs index 4971eacad..2c572e226 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -12,9 +12,9 @@ use monaco::{ yew::CodeEditor, }; use std::rc::Rc; -use swim::emulation_core::agent::EmulationCoreAgent; +use swim::agent::EmulationCoreAgent; +use swim::agent::datapath_communicator::DatapathCommunicator; use swim::emulation_core::datapath::Datapath; -use swim::emulation_core::datapath_communicator::DatapathCommunicator; use swim::emulation_core::mips::datapath::MipsDatapath; use swim::emulation_core::mips::datapath::Stage; use swim::parser::parser_assembler_main::parser; @@ -92,7 +92,8 @@ fn app(props: &AppProps) -> Html { // the ability to access and change its contents be mutable. let datapath = use_mut_ref(MipsDatapath::default); - // Start listening for messages from the communicator + // Start listening for messages from the communicator. This effectively links the worker thread to the main thread + // and will force updates whenever its internal state changes. { let trigger = use_force_update(); let communicator = props.communicator; @@ -103,7 +104,7 @@ fn app(props: &AppProps) -> Html { // This is where code is assembled and loaded into the emulation core's memory. let on_assemble_clicked = { - props.communicator.send_test_message(); + props.communicator.send_test_message(); // Test message, remove later. let text_model = Rc::clone(&text_model); let datapath = Rc::clone(&datapath); let parser_text_output = parser_text_output.clone(); diff --git a/src/bin/worker.rs b/src/bin/worker.rs index f02e1b997..587377ae1 100644 --- a/src/bin/worker.rs +++ b/src/bin/worker.rs @@ -1,4 +1,4 @@ -use swim::emulation_core::agent::EmulationCoreAgent; +use swim::agent::EmulationCoreAgent; use yew_agent::Registrable; fn main() { diff --git a/src/emulation_core.rs b/src/emulation_core.rs index 7fcb1c723..e62a37920 100644 --- a/src/emulation_core.rs +++ b/src/emulation_core.rs @@ -1,6 +1,4 @@ //! The emulation core for the project. -pub mod agent; pub mod datapath; -pub mod datapath_communicator; pub mod mips; diff --git a/src/lib.rs b/src/lib.rs index 52b5b61b7..1f34be2c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,3 +3,4 @@ pub mod parser; #[cfg(test)] pub mod tests; pub mod ui; +pub mod agent; From bf1de6db8694e213ea13a469924eadccaab86d80 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Fri, 19 Jan 2024 17:44:52 -0500 Subject: [PATCH 065/355] Fix update polling loop being called multiple times --- src/agent.rs | 6 +++++- src/agent/datapath_communicator.rs | 13 +++++++++++++ src/bin/main.rs | 21 ++++++++------------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index 5a674cec3..f74dda20b 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -11,9 +11,13 @@ pub mod datapath_communicator; #[reactor(EmulationCoreAgent)] pub async fn emulation_core_agent(mut scope: ReactorScope) { log!("Hello world!"); - scope.send(1).await.unwrap(); + let mut num = 1; + scope.send(num).await.unwrap(); loop { let msg = scope.next().await; log!("Got message: ", msg); + num += 1; + scope.send(num).await.unwrap(); + log!("Sent."); } } diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index abd87b247..49de5f3d9 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -19,6 +19,15 @@ pub struct DatapathCommunicator { reader: RefCell>>, } +// Check references for equality by memory address. +impl PartialEq for &'static DatapathCommunicator { + fn eq(&self, other: &Self) -> bool { + let self_ptr: *const DatapathCommunicator = *self; + let other_ptr: *const DatapathCommunicator = *other; + self_ptr == other_ptr + } +} + impl DatapathCommunicator { /// Initialize the DatapathCommunicator using a bridge. pub fn new(bridge: ReactorBridge) -> DatapathCommunicator { @@ -43,8 +52,12 @@ impl DatapathCommunicator { }; loop { + log!("Waiting..."); let update = reader.next().await; log!(format!("Got update {:?}", update)); + if let None = update { + return; + } update_handle.force_update(); } } diff --git a/src/bin/main.rs b/src/bin/main.rs index 2c572e226..a9961bc48 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,5 +1,6 @@ use gloo::{dialogs::alert, file::FileList}; use js_sys::Object; +use gloo_console::log; use monaco::{ api::TextModel, sys::{ @@ -33,19 +34,11 @@ use yew_hooks::prelude::*; // rename fib_model to text_model to have it work. const CONTENT: &str = include_str!("../../static/assembly_examples/fibonacci.asm"); -#[derive(Properties, Clone)] +#[derive(Properties, Clone, PartialEq)] struct AppProps { communicator: &'static DatapathCommunicator, } -impl PartialEq for AppProps { - fn eq(&self, other: &Self) -> bool { - let self_ptr: *const Self = self; - let other_ptr: *const Self = other; - self_ptr == other_ptr - } -} - #[function_component(App)] fn app(props: &AppProps) -> Html { // This contains the binary representation of "ori $s0, $zero, 12345", which @@ -96,15 +89,14 @@ fn app(props: &AppProps) -> Html { // and will force updates whenever its internal state changes. { let trigger = use_force_update(); - let communicator = props.communicator; - use_effect(move || { + use_effect_with_deps(move |communicator| { spawn_local(communicator.listen_for_updates(trigger)); - }); + }, props.communicator); } // This is where code is assembled and loaded into the emulation core's memory. let on_assemble_clicked = { - props.communicator.send_test_message(); // Test message, remove later. + let communicator = props.communicator; let text_model = Rc::clone(&text_model); let datapath = Rc::clone(&datapath); let parser_text_output = parser_text_output.clone(); @@ -115,6 +107,7 @@ fn app(props: &AppProps) -> Html { use_callback( move |_, text_model| { + communicator.send_test_message(); // Test message, remove later. let mut datapath = datapath.borrow_mut(); let text_model = text_model.borrow_mut(); @@ -182,6 +175,8 @@ fn app(props: &AppProps) -> Html { ) }; + log!("Re-rendered!"); + // This is where the code will get executed. If you execute further // than when the code ends, the program crashes. This is remedied via the // syscall instruction, which will halt the datapath. As you execute the From 794d35906248144e0a922d401c6cdd2a8d001f9b Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Fri, 19 Jan 2024 18:14:02 -0500 Subject: [PATCH 066/355] Remove unnecessary lifetime parameter --- src/agent/datapath_communicator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index 49de5f3d9..aca3d1e3b 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -20,7 +20,7 @@ pub struct DatapathCommunicator { } // Check references for equality by memory address. -impl PartialEq for &'static DatapathCommunicator { +impl PartialEq for &DatapathCommunicator { fn eq(&self, other: &Self) -> bool { let self_ptr: *const DatapathCommunicator = *self; let other_ptr: *const DatapathCommunicator = *other; From 867c0cdc6c08a00222cd062f765f4041fb357810 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Fri, 26 Jan 2024 17:47:42 -0500 Subject: [PATCH 067/355] Fix formatting and Clippy warnings --- src/agent/datapath_communicator.rs | 2 +- src/bin/main.rs | 16 ++++++++++------ src/lib.rs | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index aca3d1e3b..bdd839e53 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -55,7 +55,7 @@ impl DatapathCommunicator { log!("Waiting..."); let update = reader.next().await; log!(format!("Got update {:?}", update)); - if let None = update { + if update.is_none() { return; } update_handle.force_update(); diff --git a/src/bin/main.rs b/src/bin/main.rs index a9961bc48..e0fbc285b 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,6 +1,6 @@ use gloo::{dialogs::alert, file::FileList}; -use js_sys::Object; use gloo_console::log; +use js_sys::Object; use monaco::{ api::TextModel, sys::{ @@ -13,8 +13,8 @@ use monaco::{ yew::CodeEditor, }; use std::rc::Rc; -use swim::agent::EmulationCoreAgent; use swim::agent::datapath_communicator::DatapathCommunicator; +use swim::agent::EmulationCoreAgent; use swim::emulation_core::datapath::Datapath; use swim::emulation_core::mips::datapath::MipsDatapath; use swim::emulation_core::mips::datapath::Stage; @@ -89,9 +89,12 @@ fn app(props: &AppProps) -> Html { // and will force updates whenever its internal state changes. { let trigger = use_force_update(); - use_effect_with_deps(move |communicator| { - spawn_local(communicator.listen_for_updates(trigger)); - }, props.communicator); + use_effect_with_deps( + move |communicator| { + spawn_local(communicator.listen_for_updates(trigger)); + }, + props.communicator, + ); } // This is where code is assembled and loaded into the emulation core's memory. @@ -555,7 +558,8 @@ pub fn on_upload_file_clicked() { fn main() { // Initialize and leak the communicator to ensure that the thread spawns immediately and the bridge to it lives - // for the remainder of the program. + // for the remainder of the program. We can use the communicator exclusively through immutable references for the + // rest of the program. let bridge = EmulationCoreAgent::spawner().spawn("./worker.js"); let communicator = Box::new(DatapathCommunicator::new(bridge)); yew::Renderer::::with_props(AppProps { diff --git a/src/lib.rs b/src/lib.rs index 1f34be2c9..825d617f2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ +pub mod agent; pub mod emulation_core; pub mod parser; #[cfg(test)] pub mod tests; pub mod ui; -pub mod agent; From 54a274d11d9ad8228b2e367d4c1045620dd1447d Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Mon, 29 Jan 2024 16:51:00 -0500 Subject: [PATCH 068/355] Add new functions for generic datapath --- src/emulation_core/datapath.rs | 35 +++++++++++++++++++++++++++++ src/emulation_core/mips/datapath.rs | 14 ++++++++++++ 2 files changed, 49 insertions(+) diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index b3d1c8deb..0484ffc4a 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -27,6 +27,11 @@ pub trait Datapath { /// or its own interface at will. type MemoryType; + /// This enum describes all possible stages in the datapath. This is + /// used primarily for the visual datapath view. Must be convertable + /// into a string for highlighting purposes. + type StageEnum: Into; + /// Execute a single instruction based on the current state of the /// datapath. Should the datapath support stages, if the datapath is /// midway through a stage, the current instruction will be finished @@ -45,15 +50,45 @@ pub trait Datapath { /// registers should be listed within [`Self::RegisterEnum`]. fn get_register_by_enum(&self, register: Self::RegisterEnum) -> Self::RegisterData; + /// Sets the data in the register indicated by the provided enum. + fn set_register_by_enum(&self, _register: Self::RegisterEnum, _data: Self::RegisterData) { + todo!() + } + + /// Loads the instructions from the provided array into an emulation core's + /// memory. This will also clear the memory of the emulation core and reset + /// the core's program counter. + fn load_instructions(&mut self, instructions: &[Self::MemoryType]) { + self.reset(); + self.set_memory(0, instructions); + } + /// Retrieve all memory as-is. fn get_memory(&self) -> &Self::MemoryType; + fn set_memory(&mut self, _ptr: usize, _data: &[Self::MemoryType]) { + todo!() + } + /// Returns if the datapath is in a "halted" or "stopped" state. This may /// be true in the case where an error had occurred previously. fn is_halted(&self) -> bool; /// Restore the datapath to its default state. fn reset(&mut self); + + // Information retrieval + + /// Get the program counter from an emulation core, regardless of what + /// it's called. + fn get_pc(&self) -> Self::RegisterData { + todo!() + } + + /// Gets the current stage the emulator core is in. + fn get_stage(&self) -> Self::StageEnum { + todo!() + } } /// A datapath that supports a visual diagram component. diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index 16ac9c9d0..072ec2fb7 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -185,6 +185,18 @@ impl Stage { } } +impl From for String { + fn from(val: Stage) -> String { + String::from(match val { + Stage::InstructionFetch => "writeback", + Stage::InstructionDecode => "instruction_fetch", + Stage::Execute => "instruction_decode", + Stage::Memory => "execute", + Stage::WriteBack => "memory", + }) + } +} + impl Default for MipsDatapath { fn default() -> Self { let mut datapath = MipsDatapath { @@ -212,6 +224,8 @@ impl Datapath for MipsDatapath { type RegisterEnum = super::registers::GpRegisterType; type MemoryType = Memory; + type StageEnum = Stage; + fn execute_instruction(&mut self) { loop { // Stop early if the datapath has halted. From 63c10c40478aeae284a6f78b3b3a111c77ff8e56 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 1 Feb 2024 21:51:49 -0500 Subject: [PATCH 069/355] Design datapath communicator API (feedback wanted!) --- src/agent/datapath_communicator.rs | 58 +++++++++++++++++++++++++++++ src/emulation_core.rs | 1 + src/emulation_core/architectures.rs | 4 ++ 3 files changed, 63 insertions(+) create mode 100644 src/emulation_core/architectures.rs diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index bdd839e53..9b1d6dbda 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -1,4 +1,5 @@ use crate::agent::EmulationCoreAgent; +use crate::emulation_core::architectures::AvailableDatapaths; use futures::stream::{SplitSink, SplitStream}; use futures::FutureExt; use futures::SinkExt; @@ -6,6 +7,7 @@ use futures::StreamExt; use gloo_console::log; use gloo_console::warn; use std::cell::RefCell; +use std::collections::HashMap; use yew::UseForceUpdateHandle; use yew_agent::reactor::ReactorBridge; @@ -29,6 +31,8 @@ impl PartialEq for &DatapathCommunicator { } impl DatapathCommunicator { + // General operational functions + /// Initialize the DatapathCommunicator using a bridge. pub fn new(bridge: ReactorBridge) -> DatapathCommunicator { let (write, read) = bridge.split(); @@ -72,4 +76,58 @@ impl DatapathCommunicator { .expect("Send function did not immediately return, async logic needed.") .expect("Sending test message error") } + + // Wrapper functions for commands + + pub fn set_core(&self, _architecture: AvailableDatapaths) { + todo!() + } + + pub fn load_instructions(&self, _instructions: &[u8]) { + todo!() + } + + pub fn set_execute_speed(&self, _speed: u32) { + todo!() + } + + pub fn set_register(&self, _register: &str, _data: &str) { + todo!() + } + + pub fn set_memory(&self, _ptr: usize, _data: &[u8]) { + todo!() + } + + pub fn execute(&self) { + todo!() + } + + pub fn execute_instruction(&self) { + todo!() + } + + pub fn execute_stage(&self) { + todo!() + } + + pub fn pause_core(&self) {} + + // Getters for internal state + + pub fn get_registers(&self) -> HashMap { + todo!() + } + + pub fn get_memory(&self) -> Vec { + todo!() + } + + pub fn get_current_stage(&self) -> String { + todo!() + } + + pub fn get_current_instruction(&self) -> usize { + todo!() + } } diff --git a/src/emulation_core.rs b/src/emulation_core.rs index e62a37920..ac45cc291 100644 --- a/src/emulation_core.rs +++ b/src/emulation_core.rs @@ -1,4 +1,5 @@ //! The emulation core for the project. +pub mod architectures; pub mod datapath; pub mod mips; diff --git a/src/emulation_core/architectures.rs b/src/emulation_core/architectures.rs new file mode 100644 index 000000000..27fc363ed --- /dev/null +++ b/src/emulation_core/architectures.rs @@ -0,0 +1,4 @@ +pub enum AvailableDatapaths { + MIPS, + RISCV, +} From 892ed6cdf46c23109485d31f9fdaa40ef10a7272 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 1 Feb 2024 22:17:14 -0500 Subject: [PATCH 070/355] Remove the type alias for line information on the VisualDatapath trait --- src/emulation_core/datapath.rs | 7 +++---- src/emulation_core/mips/line_info.rs | 2 -- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index 0484ffc4a..21c80534d 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -1,5 +1,7 @@ //! Module for the API of a generic datapath. +use crate::emulation_core::mips::line_info::LineInformation; + /// A generic datapath. /// /// This has the ability to execute instructions, and to interface with @@ -96,10 +98,7 @@ pub trait Datapath { /// This requires a corresponding visual diagram with labels that can be mapped /// to the datapath. pub trait VisualDatapath { - /// The information about a piece of the diagram that is returned from the datapath. - type LineInformation; - /// Return the information from the datapath corresponding to the `variable` attribute on a /// part of the visual datapath diagram. - fn visual_line_to_data(&self, variable: &str) -> Self::LineInformation; + fn visual_line_to_data(&self, variable: &str) -> LineInformation; } diff --git a/src/emulation_core/mips/line_info.rs b/src/emulation_core/mips/line_info.rs index c28c0a8aa..add7c20ec 100644 --- a/src/emulation_core/mips/line_info.rs +++ b/src/emulation_core/mips/line_info.rs @@ -19,8 +19,6 @@ pub struct LineInformation { } impl VisualDatapath for MipsDatapath { - type LineInformation = LineInformation; - fn visual_line_to_data(&self, variable: &str) -> LineInformation { match variable { "alu_input2" => LineInformation { From 028d99fc28ffd74a69022fc4e1cb33424d02dbb1 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 1 Feb 2024 22:19:02 -0500 Subject: [PATCH 071/355] Add documentation for tentative API --- src/agent/datapath_communicator.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index 9b1d6dbda..e9cdb7f0d 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -1,5 +1,6 @@ use crate::agent::EmulationCoreAgent; use crate::emulation_core::architectures::AvailableDatapaths; +use crate::emulation_core::datapath::VisualDatapath; use futures::stream::{SplitSink, SplitStream}; use futures::FutureExt; use futures::SinkExt; @@ -79,55 +80,79 @@ impl DatapathCommunicator { // Wrapper functions for commands + /// Sets the current emulation core to the provided architecture. pub fn set_core(&self, _architecture: AvailableDatapaths) { todo!() } + /// Loads the parsed/assembled instructions provided into the current emulator core. pub fn load_instructions(&self, _instructions: &[u8]) { todo!() } + /// Sets the execution speed of the emulator core to the provided speed in hz. If set to zero, the emulator core + /// will execute as fast as possible. pub fn set_execute_speed(&self, _speed: u32) { todo!() } + /// Sets the register with the provided name to the provided value. pub fn set_register(&self, _register: &str, _data: &str) { todo!() } + /// Copies the contents of `data` to the emulator core's memory at `ptr`. Copies until either the end of `data` or + /// the end of the emulaot core's memory. pub fn set_memory(&self, _ptr: usize, _data: &[u8]) { todo!() } + /// Executes the emulator core at the current set speed. pub fn execute(&self) { todo!() } + /// Executes a single instruction on the emulator core and pauses. pub fn execute_instruction(&self) { todo!() } + /// Executes a single stage on the emulator core and pauses. pub fn execute_stage(&self) { todo!() } + /// Pauses the core. Does nothing if the emulator core is already paused. pub fn pause_core(&self) {} // Getters for internal state + /// Returns a list of all the registers on the current emulator core. pub fn get_registers(&self) -> HashMap { todo!() } + /// Returns the emulator core's memory as an array of bytes. pub fn get_memory(&self) -> Vec { todo!() } + /// Gets the current stage of the emulator core as a string. pub fn get_current_stage(&self) -> String { todo!() } + /// Gets the currently executing instruction on the emulator core. This is generally based on the value of the + /// program counter. pub fn get_current_instruction(&self) -> usize { todo!() } + + /// Returns the appropriate visual datapath for the current architecture. Returns a boxed generic VisualDatapath. + pub fn get_visual_datapath( + &self, + _architecture: AvailableDatapaths, + ) -> Box { + todo!() + } } From 8c420be80da4a8744955ad3f7c45d81bbd4ca200 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 1 Feb 2024 22:29:53 -0500 Subject: [PATCH 072/355] Add/document communication-related enums --- src/agent.rs | 1 + src/agent/messages.rs | 27 +++++++++++++++++++++++++++ src/emulation_core/architectures.rs | 3 +++ 3 files changed, 31 insertions(+) create mode 100644 src/agent/messages.rs diff --git a/src/agent.rs b/src/agent.rs index f74dda20b..65265ed2b 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -5,6 +5,7 @@ use gloo_console::log; use yew_agent::prelude::*; pub mod datapath_communicator; +pub mod messages; /// The main logic for the emulation core agent. All code within this function runs on a worker thread as opposed to /// the UI thread. diff --git a/src/agent/messages.rs b/src/agent/messages.rs new file mode 100644 index 000000000..059bc0532 --- /dev/null +++ b/src/agent/messages.rs @@ -0,0 +1,27 @@ +use crate::emulation_core::architectures::AvailableDatapaths; +use serde::{Deserialize, Serialize}; + +/// Commands sent from the UI thread to the worker thread. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum Command { + SetCore(AvailableDatapaths), + LoadInstructions(Vec), + SetExecuteSpeed(u32), + SetRegister(String, u64), + SetMemory(usize, Vec), + Execute, + ExecuteInstruction, + ExecuteStage, + Pause, +} + +/// Information about the emulator core's state sent from the worker thread to the UI thread. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum StateUpdate { + UpdateRegister(u64), + UpdateMemory(usize, Vec), + SetCurrentStage(String), + SetCurrentInstruction(usize), + AddMemorySegment, + RemoveMemorySegment, +} diff --git a/src/emulation_core/architectures.rs b/src/emulation_core/architectures.rs index 27fc363ed..bc29426d1 100644 --- a/src/emulation_core/architectures.rs +++ b/src/emulation_core/architectures.rs @@ -1,3 +1,6 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum AvailableDatapaths { MIPS, RISCV, From 1e8234c06ea5b3ed014d513d953e3df8c99d0df4 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 1 Feb 2024 23:30:05 -0500 Subject: [PATCH 073/355] Proof-of-concept implementation of the emulator core thread --- src/agent.rs | 111 ++++++++++++++++++++++++++--- src/agent/datapath_communicator.rs | 18 +++-- src/bin/main.rs | 2 - 3 files changed, 113 insertions(+), 18 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index 65265ed2b..7ae3acac9 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -1,7 +1,14 @@ //! The agent responsible for running the emulator core on the worker thread and communication functionalities. -use futures::{SinkExt, StreamExt}; +use crate::agent::messages::{Command, StateUpdate}; +use crate::emulation_core::datapath::Datapath; +use crate::emulation_core::mips::datapath::{MipsDatapath, Stage}; +use crate::emulation_core::mips::memory::Memory; +use crate::emulation_core::mips::registers::GpRegisterType; +use futures::{FutureExt, StreamExt}; use gloo_console::log; +use std::time::Duration; +use yew::platform::time::sleep; use yew_agent::prelude::*; pub mod datapath_communicator; @@ -10,15 +17,101 @@ pub mod messages; /// The main logic for the emulation core agent. All code within this function runs on a worker thread as opposed to /// the UI thread. #[reactor(EmulationCoreAgent)] -pub async fn emulation_core_agent(mut scope: ReactorScope) { +pub async fn emulation_core_agent(scope: ReactorScope) { log!("Hello world!"); - let mut num = 1; - scope.send(num).await.unwrap(); + let mut state = EmulatorCoreAgentState::new(scope); loop { - let msg = scope.next().await; - log!("Got message: ", msg); - num += 1; - scope.send(num).await.unwrap(); - log!("Sent."); + let execution_delay = state.get_delay(); + futures::select! { + // If we get a message, handle the command before attempting to execute. + msg = state.scope.next() => match msg { + Some(msg) => state.handle_command(msg), + None => return, + }, + // Delay to slow execution down to the intended speed. + _ = sleep(Duration::from_millis(execution_delay)).fuse() => {}, + } + + // Execute a single instruction if the emulator core should be executing. + state.execute(); + } +} + +struct EmulatorCoreAgentState { + current_datapath: Box< + dyn Datapath< + MemoryType = Memory, + RegisterData = u64, + RegisterEnum = GpRegisterType, + StageEnum = Stage, + >, + >, + pub scope: ReactorScope, + speed: u32, + executing: bool, +} + +impl EmulatorCoreAgentState { + pub fn new(scope: ReactorScope) -> EmulatorCoreAgentState { + EmulatorCoreAgentState { + current_datapath: Box::::default(), + scope, + speed: 0, + executing: false, + } + } + + pub fn handle_command(&mut self, command: Command) { + match command { + Command::SetCore(_architecture) => { + todo!() // Implement once we have a RISCV datapath + } + Command::LoadInstructions(_mem) => { + // FIXME: Uncomment once refactoring is done on the trait + // self.current_datapath.load_instructions(mem); + todo!() + } + Command::SetExecuteSpeed(speed) => { + self.speed = speed; + } + Command::SetRegister(_register, _value) => { + todo!() + } + Command::SetMemory(_ptr, _data) => { + // FIXME: Uncomment once refectoring is done on the trait + // self.current_datapath.set_memory(ptr, &data); + todo!() + } + Command::Execute => { + self.executing = true; + } + Command::ExecuteInstruction => { + self.current_datapath.execute_instruction(); + } + Command::ExecuteStage => { + self.current_datapath.execute_stage(); + } + Command::Pause => { + self.executing = false; + } + } + } + + pub fn execute(&mut self) { + // Skip the execution phase if the emulator core is not currently executing. + if !self.executing { + return; + } + self.current_datapath.execute_instruction(); + } + + /// Returns the delay between CPU cycles in milliseconds for the current execution speed. Will return zero if the + /// execution speed is zero. + pub fn get_delay(&self) -> u64 { + if self.speed == 0 { + 0 + } else { + (1000 / self.speed).into() + } } } diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index e9cdb7f0d..693dc33d8 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -1,3 +1,4 @@ +use crate::agent::messages::Command; use crate::agent::EmulationCoreAgent; use crate::emulation_core::architectures::AvailableDatapaths; use crate::emulation_core::datapath::VisualDatapath; @@ -18,7 +19,7 @@ use yew_agent::reactor::ReactorBridge; /// The DatapathCommunicator will also handle receiving information about the state of the emulation core and maintain /// internal state that can be displayed by the UI. pub struct DatapathCommunicator { - writer: RefCell, i32>>, + writer: RefCell, Command>>, reader: RefCell>>, } @@ -68,11 +69,14 @@ impl DatapathCommunicator { } /// Sends a test message to the worker thread. - pub fn send_test_message(&self) { + fn send_message(&self, command: Command) { let mut writer = self.writer.borrow_mut(); writer - .send(1) - // The + .send(command) + // The logic for sending a message is synchronous but the API for writing to a SplitSink is asynchronous, + // so we attempt to resolve the future immediately so we can expose a synchronous API for sending commands. + // If the future doesn't return immediately, there's serious logic changes that need to happen so we just + // log an error message and panic. .now_or_never() .expect("Send function did not immediately return, async logic needed.") .expect("Sending test message error") @@ -103,13 +107,13 @@ impl DatapathCommunicator { /// Copies the contents of `data` to the emulator core's memory at `ptr`. Copies until either the end of `data` or /// the end of the emulaot core's memory. - pub fn set_memory(&self, _ptr: usize, _data: &[u8]) { - todo!() + pub fn set_memory(&self, ptr: usize, data: Vec) { + self.send_message(Command::SetMemory(ptr, data)); } /// Executes the emulator core at the current set speed. pub fn execute(&self) { - todo!() + self.send_message(Command::Execute); } /// Executes a single instruction on the emulator core and pauses. diff --git a/src/bin/main.rs b/src/bin/main.rs index e0fbc285b..487c0254b 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -99,7 +99,6 @@ fn app(props: &AppProps) -> Html { // This is where code is assembled and loaded into the emulation core's memory. let on_assemble_clicked = { - let communicator = props.communicator; let text_model = Rc::clone(&text_model); let datapath = Rc::clone(&datapath); let parser_text_output = parser_text_output.clone(); @@ -110,7 +109,6 @@ fn app(props: &AppProps) -> Html { use_callback( move |_, text_model| { - communicator.send_test_message(); // Test message, remove later. let mut datapath = datapath.borrow_mut(); let text_model = text_model.borrow_mut(); From d7ba579b5f8b332b67f834e9712d949166932226 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Fri, 2 Feb 2024 18:37:28 -0500 Subject: [PATCH 074/355] Remove the MemoryType type alias from the Datapath trait to make it more generic --- src/agent.rs | 11 ++--------- src/emulation_core/datapath.rs | 12 ++++-------- src/emulation_core/mips/datapath.rs | 3 +-- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index 7ae3acac9..a77b3c1c0 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -3,7 +3,6 @@ use crate::agent::messages::{Command, StateUpdate}; use crate::emulation_core::datapath::Datapath; use crate::emulation_core::mips::datapath::{MipsDatapath, Stage}; -use crate::emulation_core::mips::memory::Memory; use crate::emulation_core::mips::registers::GpRegisterType; use futures::{FutureExt, StreamExt}; use gloo_console::log; @@ -38,14 +37,8 @@ pub async fn emulation_core_agent(scope: ReactorScope) { } struct EmulatorCoreAgentState { - current_datapath: Box< - dyn Datapath< - MemoryType = Memory, - RegisterData = u64, - RegisterEnum = GpRegisterType, - StageEnum = Stage, - >, - >, + current_datapath: + Box>, pub scope: ReactorScope, speed: u32, executing: bool, diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index 21c80534d..00081844a 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -1,6 +1,7 @@ //! Module for the API of a generic datapath. use crate::emulation_core::mips::line_info::LineInformation; +use crate::emulation_core::mips::memory::Memory; /// A generic datapath. /// @@ -24,11 +25,6 @@ pub trait Datapath { /// at the discretion of the developer. type RegisterEnum; - /// The data type that describes memory for this datapath. This must be - /// defined separately. This allows raw access to any parts of memory - /// or its own interface at will. - type MemoryType; - /// This enum describes all possible stages in the datapath. This is /// used primarily for the visual datapath view. Must be convertable /// into a string for highlighting purposes. @@ -60,15 +56,15 @@ pub trait Datapath { /// Loads the instructions from the provided array into an emulation core's /// memory. This will also clear the memory of the emulation core and reset /// the core's program counter. - fn load_instructions(&mut self, instructions: &[Self::MemoryType]) { + fn load_instructions(&mut self, instructions: &[u8]) { self.reset(); self.set_memory(0, instructions); } /// Retrieve all memory as-is. - fn get_memory(&self) -> &Self::MemoryType; + fn get_memory(&self) -> &Memory; - fn set_memory(&mut self, _ptr: usize, _data: &[Self::MemoryType]) { + fn set_memory(&mut self, _ptr: usize, _data: &[u8]) { todo!() } diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index 072ec2fb7..e982d3c96 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -222,7 +222,6 @@ impl Default for MipsDatapath { impl Datapath for MipsDatapath { type RegisterData = u64; type RegisterEnum = super::registers::GpRegisterType; - type MemoryType = Memory; type StageEnum = Stage; @@ -269,7 +268,7 @@ impl Datapath for MipsDatapath { self.registers[register] } - fn get_memory(&self) -> &Self::MemoryType { + fn get_memory(&self) -> &Memory { &self.memory } From 9ef6fb89ff3cf079a5e70699325786b065e4bed6 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Tue, 6 Feb 2024 20:39:46 -0500 Subject: [PATCH 075/355] Finish up basic commands implementation --- src/agent.rs | 21 ++++++++------------- src/emulation_core/datapath.rs | 25 +++---------------------- src/emulation_core/mips/datapath.rs | 6 ++++-- 3 files changed, 15 insertions(+), 37 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index a77b3c1c0..35c589d64 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -2,7 +2,7 @@ use crate::agent::messages::{Command, StateUpdate}; use crate::emulation_core::datapath::Datapath; -use crate::emulation_core::mips::datapath::{MipsDatapath, Stage}; +use crate::emulation_core::mips::datapath::MipsDatapath; use crate::emulation_core::mips::registers::GpRegisterType; use futures::{FutureExt, StreamExt}; use gloo_console::log; @@ -37,8 +37,7 @@ pub async fn emulation_core_agent(scope: ReactorScope) { } struct EmulatorCoreAgentState { - current_datapath: - Box>, + current_datapath: Box>, pub scope: ReactorScope, speed: u32, executing: bool, @@ -59,21 +58,17 @@ impl EmulatorCoreAgentState { Command::SetCore(_architecture) => { todo!() // Implement once we have a RISCV datapath } - Command::LoadInstructions(_mem) => { - // FIXME: Uncomment once refactoring is done on the trait - // self.current_datapath.load_instructions(mem); - todo!() + Command::LoadInstructions(mem) => { + self.current_datapath.load_instructions(&mem); } Command::SetExecuteSpeed(speed) => { self.speed = speed; } - Command::SetRegister(_register, _value) => { - todo!() + Command::SetRegister(register, value) => { + self.current_datapath.set_register_by_str(®ister, value); } - Command::SetMemory(_ptr, _data) => { - // FIXME: Uncomment once refectoring is done on the trait - // self.current_datapath.set_memory(ptr, &data); - todo!() + Command::SetMemory(ptr, data) => { + self.current_datapath.set_memory(ptr, &data); } Command::Execute => { self.executing = true; diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index 00081844a..b1a29d6e5 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -25,11 +25,6 @@ pub trait Datapath { /// at the discretion of the developer. type RegisterEnum; - /// This enum describes all possible stages in the datapath. This is - /// used primarily for the visual datapath view. Must be convertable - /// into a string for highlighting purposes. - type StageEnum: Into; - /// Execute a single instruction based on the current state of the /// datapath. Should the datapath support stages, if the datapath is /// midway through a stage, the current instruction will be finished @@ -48,10 +43,9 @@ pub trait Datapath { /// registers should be listed within [`Self::RegisterEnum`]. fn get_register_by_enum(&self, register: Self::RegisterEnum) -> Self::RegisterData; - /// Sets the data in the register indicated by the provided enum. - fn set_register_by_enum(&self, _register: Self::RegisterEnum, _data: Self::RegisterData) { - todo!() - } + /// Sets the data in the register indicated by the provided string. If it doesn't exist, + /// this function returns Err. + fn set_register_by_str(&mut self, register: &str, data: Self::RegisterData); /// Loads the instructions from the provided array into an emulation core's /// memory. This will also clear the memory of the emulation core and reset @@ -74,19 +68,6 @@ pub trait Datapath { /// Restore the datapath to its default state. fn reset(&mut self); - - // Information retrieval - - /// Get the program counter from an emulation core, regardless of what - /// it's called. - fn get_pc(&self) -> Self::RegisterData { - todo!() - } - - /// Gets the current stage the emulator core is in. - fn get_stage(&self) -> Self::StageEnum { - todo!() - } } /// A datapath that supports a visual diagram component. diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index e982d3c96..f2835a6c8 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -223,8 +223,6 @@ impl Datapath for MipsDatapath { type RegisterData = u64; type RegisterEnum = super::registers::GpRegisterType; - type StageEnum = Stage; - fn execute_instruction(&mut self) { loop { // Stop early if the datapath has halted. @@ -268,6 +266,10 @@ impl Datapath for MipsDatapath { self.registers[register] } + fn set_register_by_str(&mut self, _register: &str, _data: Self::RegisterData) { + todo!() + } + fn get_memory(&self) -> &Memory { &self.memory } From 90ce02fbef4a4aa62f447dcd15a194db113f8264 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Wed, 7 Feb 2024 16:41:14 -0500 Subject: [PATCH 076/355] Implement naive state updates for MIPS --- src/agent.rs | 29 +++++++++++++--- src/agent/datapath_communicator.rs | 51 ++++++---------------------- src/agent/messages.rs | 14 ++++---- src/emulation_core/architectures.rs | 11 ++++++ src/emulation_core/datapath.rs | 3 ++ src/emulation_core/mips/datapath.rs | 8 ++++- src/emulation_core/mips/memory.rs | 4 ++- src/emulation_core/mips/registers.rs | 3 +- 8 files changed, 67 insertions(+), 56 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index 35c589d64..dde11710c 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -1,10 +1,11 @@ //! The agent responsible for running the emulator core on the worker thread and communication functionalities. -use crate::agent::messages::{Command, StateUpdate}; +use crate::agent::messages::{Command, MipsStateUpdate}; +use crate::emulation_core::architectures::{DatapathRef, DatapathUpdate}; use crate::emulation_core::datapath::Datapath; use crate::emulation_core::mips::datapath::MipsDatapath; use crate::emulation_core::mips::registers::GpRegisterType; -use futures::{FutureExt, StreamExt}; +use futures::{FutureExt, SinkExt, StreamExt}; use gloo_console::log; use std::time::Duration; use yew::platform::time::sleep; @@ -16,11 +17,12 @@ pub mod messages; /// The main logic for the emulation core agent. All code within this function runs on a worker thread as opposed to /// the UI thread. #[reactor(EmulationCoreAgent)] -pub async fn emulation_core_agent(scope: ReactorScope) { +pub async fn emulation_core_agent(scope: ReactorScope) { log!("Hello world!"); let mut state = EmulatorCoreAgentState::new(scope); loop { let execution_delay = state.get_delay(); + // Part 1: Delay/Command Handling futures::select! { // If we get a message, handle the command before attempting to execute. msg = state.scope.next() => match msg { @@ -31,20 +33,37 @@ pub async fn emulation_core_agent(scope: ReactorScope) { _ = sleep(Duration::from_millis(execution_delay)).fuse() => {}, } + // Part 2: Execution // Execute a single instruction if the emulator core should be executing. state.execute(); + + // Part 3: Processing State/Sending Updates to UI + // TODO: This is a very naive implementation. Optimization is probably a good idea. + match state.current_datapath.as_datapath_ref() { + DatapathRef::MIPS(datapath) => { + let state_update = + DatapathUpdate::MIPS(MipsStateUpdate::UpdateState(datapath.state.clone())); + let register_update = + DatapathUpdate::MIPS(MipsStateUpdate::UpdateRegisters(datapath.registers)); + let memory_update = + DatapathUpdate::MIPS(MipsStateUpdate::UpdateMemory(datapath.memory.clone())); + state.scope.send(state_update).await.unwrap(); + state.scope.send(register_update).await.unwrap(); + state.scope.send(memory_update).await.unwrap(); + } + } } } struct EmulatorCoreAgentState { current_datapath: Box>, - pub scope: ReactorScope, + pub scope: ReactorScope, speed: u32, executing: bool, } impl EmulatorCoreAgentState { - pub fn new(scope: ReactorScope) -> EmulatorCoreAgentState { + pub fn new(scope: ReactorScope) -> EmulatorCoreAgentState { EmulatorCoreAgentState { current_datapath: Box::::default(), scope, diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index 693dc33d8..c6936a9bd 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -1,7 +1,6 @@ use crate::agent::messages::Command; use crate::agent::EmulationCoreAgent; use crate::emulation_core::architectures::AvailableDatapaths; -use crate::emulation_core::datapath::VisualDatapath; use futures::stream::{SplitSink, SplitStream}; use futures::FutureExt; use futures::SinkExt; @@ -9,7 +8,6 @@ use futures::StreamExt; use gloo_console::log; use gloo_console::warn; use std::cell::RefCell; -use std::collections::HashMap; use yew::UseForceUpdateHandle; use yew_agent::reactor::ReactorBridge; @@ -90,19 +88,19 @@ impl DatapathCommunicator { } /// Loads the parsed/assembled instructions provided into the current emulator core. - pub fn load_instructions(&self, _instructions: &[u8]) { - todo!() + pub fn load_instructions(&self, instructions: Vec) { + self.send_message(Command::LoadInstructions(instructions)); } /// Sets the execution speed of the emulator core to the provided speed in hz. If set to zero, the emulator core /// will execute as fast as possible. - pub fn set_execute_speed(&self, _speed: u32) { - todo!() + pub fn set_execute_speed(&self, speed: u32) { + self.send_message(Command::SetExecuteSpeed(speed)); } /// Sets the register with the provided name to the provided value. - pub fn set_register(&self, _register: &str, _data: &str) { - todo!() + pub fn set_register(&self, register: String, data: u64) { + self.send_message(Command::SetRegister(register, data)); } /// Copies the contents of `data` to the emulator core's memory at `ptr`. Copies until either the end of `data` or @@ -118,45 +116,16 @@ impl DatapathCommunicator { /// Executes a single instruction on the emulator core and pauses. pub fn execute_instruction(&self) { - todo!() + self.send_message(Command::ExecuteInstruction); } /// Executes a single stage on the emulator core and pauses. pub fn execute_stage(&self) { - todo!() + self.send_message(Command::ExecuteStage); } /// Pauses the core. Does nothing if the emulator core is already paused. - pub fn pause_core(&self) {} - - // Getters for internal state - - /// Returns a list of all the registers on the current emulator core. - pub fn get_registers(&self) -> HashMap { - todo!() - } - - /// Returns the emulator core's memory as an array of bytes. - pub fn get_memory(&self) -> Vec { - todo!() - } - - /// Gets the current stage of the emulator core as a string. - pub fn get_current_stage(&self) -> String { - todo!() - } - - /// Gets the currently executing instruction on the emulator core. This is generally based on the value of the - /// program counter. - pub fn get_current_instruction(&self) -> usize { - todo!() - } - - /// Returns the appropriate visual datapath for the current architecture. Returns a boxed generic VisualDatapath. - pub fn get_visual_datapath( - &self, - _architecture: AvailableDatapaths, - ) -> Box { - todo!() + pub fn pause_core(&self) { + self.send_message(Command::Pause); } } diff --git a/src/agent/messages.rs b/src/agent/messages.rs index 059bc0532..62d59d9d9 100644 --- a/src/agent/messages.rs +++ b/src/agent/messages.rs @@ -1,4 +1,7 @@ use crate::emulation_core::architectures::AvailableDatapaths; +use crate::emulation_core::mips::datapath::DatapathState; +use crate::emulation_core::mips::memory::Memory; +use crate::emulation_core::mips::registers::GpRegisters; use serde::{Deserialize, Serialize}; /// Commands sent from the UI thread to the worker thread. @@ -17,11 +20,8 @@ pub enum Command { /// Information about the emulator core's state sent from the worker thread to the UI thread. #[derive(Clone, Debug, Serialize, Deserialize)] -pub enum StateUpdate { - UpdateRegister(u64), - UpdateMemory(usize, Vec), - SetCurrentStage(String), - SetCurrentInstruction(usize), - AddMemorySegment, - RemoveMemorySegment, +pub enum MipsStateUpdate { + UpdateState(DatapathState), + UpdateRegisters(GpRegisters), + UpdateMemory(Memory), } diff --git a/src/emulation_core/architectures.rs b/src/emulation_core/architectures.rs index bc29426d1..20cf13478 100644 --- a/src/emulation_core/architectures.rs +++ b/src/emulation_core/architectures.rs @@ -1,3 +1,5 @@ +use crate::agent::messages::MipsStateUpdate; +use crate::emulation_core::mips::datapath::MipsDatapath; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Serialize, Deserialize)] @@ -5,3 +7,12 @@ pub enum AvailableDatapaths { MIPS, RISCV, } + +pub enum DatapathRef<'a> { + MIPS(&'a MipsDatapath), +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum DatapathUpdate { + MIPS(MipsStateUpdate), +} diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index b1a29d6e5..156bf1262 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -1,5 +1,6 @@ //! Module for the API of a generic datapath. +use crate::emulation_core::architectures::DatapathRef; use crate::emulation_core::mips::line_info::LineInformation; use crate::emulation_core::mips::memory::Memory; @@ -68,6 +69,8 @@ pub trait Datapath { /// Restore the datapath to its default state. fn reset(&mut self); + + fn as_datapath_ref(&self) -> DatapathRef; } /// A datapath that supports a visual diagram component. diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index f2835a6c8..4bb23c693 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -52,6 +52,8 @@ use super::control_signals::{floating_point::*, *}; use super::datapath_signals::*; use super::instruction::*; use super::{coprocessor::MipsFpCoprocessor, memory::Memory, registers::GpRegisters}; +use crate::emulation_core::architectures::DatapathRef; +use serde::{Deserialize, Serialize}; /// An implementation of a datapath for the MIPS64 ISA. #[derive(Clone, PartialEq)] @@ -76,7 +78,7 @@ pub struct MipsDatapath { } /// A collection of all the data lines and wires in the datapath. -#[derive(Clone, Default, PartialEq)] +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] pub struct DatapathState { /// *Data line.* The currently loaded instruction. Initialized after the /// Instruction Fetch stage. @@ -281,6 +283,10 @@ impl Datapath for MipsDatapath { fn reset(&mut self) { std::mem::take(self); } + + fn as_datapath_ref(&self) -> DatapathRef { + DatapathRef::MIPS(self) + } } impl MipsDatapath { diff --git a/src/emulation_core/mips/memory.rs b/src/emulation_core/mips/memory.rs index 2abcf1921..6dae642cf 100644 --- a/src/emulation_core/mips/memory.rs +++ b/src/emulation_core/mips/memory.rs @@ -1,9 +1,11 @@ //! Data and instruction memory implementation and API. +use serde::{Deserialize, Serialize}; + // pub const CAPACITY_BYTES: usize = 2^12; // 4KB pub const CAPACITY_BYTES: usize = 64 * 1024; // 64 KB -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Memory { pub memory: Vec, } diff --git a/src/emulation_core/mips/registers.rs b/src/emulation_core/mips/registers.rs index efd218a83..a4171e87f 100644 --- a/src/emulation_core/mips/registers.rs +++ b/src/emulation_core/mips/registers.rs @@ -1,12 +1,13 @@ //! Register structure and API. +use serde::{Deserialize, Serialize}; use std::ops::{Index, IndexMut}; use std::str::FromStr; use strum::IntoEnumIterator; use strum_macros::{Display, EnumIter, EnumString}; /// Collection of general-purpose registers used by the datapath. -#[derive(Clone, Copy, Debug, Default, PartialEq)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)] pub struct GpRegisters { pub pc: u64, pub gpr: [u64; 32], From a281e8870e125f20e7c7a0f4e2903faa94c1eeb5 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 8 Feb 2024 20:13:02 -0500 Subject: [PATCH 077/355] Rename LoadInstructions to Initialize and get MIPS to start using it --- src/agent.rs | 24 ++++++++++++++++-------- src/agent/datapath_communicator.rs | 6 +++--- src/agent/messages.rs | 2 +- src/bin/main.rs | 2 +- src/emulation_core/datapath.rs | 10 +++------- src/emulation_core/mips/datapath.rs | 15 +++++++++++---- src/lib.rs | 1 + src/shims.rs | 19 +++++++++++++++++++ 8 files changed, 55 insertions(+), 24 deletions(-) create mode 100644 src/shims.rs diff --git a/src/agent.rs b/src/agent.rs index dde11710c..497a0b2fb 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -22,15 +22,23 @@ pub async fn emulation_core_agent(scope: ReactorScope) let mut state = EmulatorCoreAgentState::new(scope); loop { let execution_delay = state.get_delay(); + // Part 1: Delay/Command Handling - futures::select! { - // If we get a message, handle the command before attempting to execute. - msg = state.scope.next() => match msg { + if state.executing { + futures::select! { + // If we get a message, handle the command before attempting to execute. + msg = state.scope.next() => match msg { + Some(msg) => state.handle_command(msg), + None => return, + }, + // Delay to slow execution down to the intended speed. + _ = sleep(Duration::from_millis(execution_delay)).fuse() => {}, + } + } else { + match state.scope.next().await { Some(msg) => state.handle_command(msg), None => return, - }, - // Delay to slow execution down to the intended speed. - _ = sleep(Duration::from_millis(execution_delay)).fuse() => {}, + } } // Part 2: Execution @@ -77,8 +85,8 @@ impl EmulatorCoreAgentState { Command::SetCore(_architecture) => { todo!() // Implement once we have a RISCV datapath } - Command::LoadInstructions(mem) => { - self.current_datapath.load_instructions(&mem); + Command::Initialize(mem) => { + self.current_datapath.initialize(mem).unwrap(); } Command::SetExecuteSpeed(speed) => { self.speed = speed; diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index c6936a9bd..18c5d772e 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -87,9 +87,9 @@ impl DatapathCommunicator { todo!() } - /// Loads the parsed/assembled instructions provided into the current emulator core. - pub fn load_instructions(&self, instructions: Vec) { - self.send_message(Command::LoadInstructions(instructions)); + /// Resets and loads the parsed/assembled instructions provided into the current emulator core. + pub fn initialize(&self, instructions: Vec) { + self.send_message(Command::Initialize(instructions)); } /// Sets the execution speed of the emulator core to the provided speed in hz. If set to zero, the emulator core diff --git a/src/agent/messages.rs b/src/agent/messages.rs index 62d59d9d9..63a24a1cf 100644 --- a/src/agent/messages.rs +++ b/src/agent/messages.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Serialize, Deserialize)] pub enum Command { SetCore(AvailableDatapaths), - LoadInstructions(Vec), + Initialize(Vec), SetExecuteSpeed(u32), SetRegister(String, u64), SetMemory(usize, Vec), diff --git a/src/bin/main.rs b/src/bin/main.rs index 487c0254b..ddcb01140 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -158,7 +158,7 @@ fn app(props: &AppProps) -> Html { // Proceed with loading into memory and expand pseudo-instructions if there are no errors. if marker_jsarray.length() == 0 { // Load the binary into the datapath's memory - match datapath.initialize(assembled) { + match datapath.initialize_legacy(assembled) { Ok(_) => (), Err(msg) => { // In the case of an error, note this and stop early. diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index 156bf1262..47ceb3217 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -48,13 +48,9 @@ pub trait Datapath { /// this function returns Err. fn set_register_by_str(&mut self, register: &str, data: Self::RegisterData); - /// Loads the instructions from the provided array into an emulation core's - /// memory. This will also clear the memory of the emulation core and reset - /// the core's program counter. - fn load_instructions(&mut self, instructions: &[u8]) { - self.reset(); - self.set_memory(0, instructions); - } + /// Reset the datapath, load instructions into memory, and un-sets the `is_halted` + /// flag. If the process fails, an [`Err`] is returned. + fn initialize(&mut self, instructions: Vec) -> Result<(), String>; /// Retrieve all memory as-is. fn get_memory(&self) -> &Memory; diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index 4bb23c693..fbddacd88 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -41,7 +41,7 @@ //! # Notes on `is_halted` //! //! - The datapath starts with the `is_halted` flag set. -//! - [`MipsDatapath::initialize()`] should be used to un-set `is_halted`. +//! - [`MipsDatapath::initialize_legacy()`] should be used to un-set `is_halted`. //! - The `syscall` instruction simply performs a no-operation instruction, except for //! setting the boolean flag `is_halted`. //! - Invalid instructions will cause the datapath to set the `is_halted` flag. @@ -53,6 +53,7 @@ use super::datapath_signals::*; use super::instruction::*; use super::{coprocessor::MipsFpCoprocessor, memory::Memory, registers::GpRegisters}; use crate::emulation_core::architectures::DatapathRef; +use crate::shims; use serde::{Deserialize, Serialize}; /// An implementation of a datapath for the MIPS64 ISA. @@ -272,6 +273,14 @@ impl Datapath for MipsDatapath { todo!() } + fn initialize(&mut self, instructions: Vec) -> Result<(), String> { + self.reset(); + self.load_instructions(shims::convert_from_u8_bytes(instructions))?; + self.is_halted = false; + + Ok(()) + } + fn get_memory(&self) -> &Memory { &self.memory } @@ -291,9 +300,7 @@ impl Datapath for MipsDatapath { impl MipsDatapath { // ===================== General Functions ===================== - /// Reset the datapath, load instructions into memory, and un-sets the `is_halted` - /// flag. If the process fails, an [`Err`] is returned. - pub fn initialize(&mut self, instructions: Vec) -> Result<(), String> { + pub fn initialize_legacy(&mut self, instructions: Vec) -> Result<(), String> { self.reset(); self.load_instructions(instructions)?; self.is_halted = false; diff --git a/src/lib.rs b/src/lib.rs index 825d617f2..2ba0135bb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ pub mod agent; pub mod emulation_core; pub mod parser; +pub mod shims; #[cfg(test)] pub mod tests; pub mod ui; diff --git a/src/shims.rs b/src/shims.rs new file mode 100644 index 000000000..625c13684 --- /dev/null +++ b/src/shims.rs @@ -0,0 +1,19 @@ +//! Temporary shims to get things working for demos. These should NOT be used in the final version. + +pub fn convert_to_u8_bytes(input: Vec) -> Vec { + let mut res = Vec::new(); + for int in input { + for byte in int.to_le_bytes() { + res.push(byte); + } + } + res +} + +pub fn convert_from_u8_bytes(input: Vec) -> Vec { + let mut res = Vec::new(); + for int_bytes in input.chunks(4) { + res.push(u32::from_le_bytes(int_bytes.try_into().unwrap())); + } + res +} From 45fe30ef89b7418af2484b41a5d74be77e28341b Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 8 Feb 2024 20:13:30 -0500 Subject: [PATCH 078/355] Fix tests --- src/tests/emulation_core/mips.rs | 284 +++++++++--------- .../integration/core_parser/arithmetic.rs | 8 +- .../core_parser/basic_immediate.rs | 20 +- .../core_parser/basic_operations.rs | 12 +- .../integration/core_parser/branch_jump.rs | 14 +- .../integration/core_parser/conditions.rs | 4 +- .../core_parser/coprocessor_move.rs | 12 +- .../core_parser/double_arithmetic.rs | 4 +- .../core_parser/double_immediate.rs | 10 +- .../integration/core_parser/fibonacci.rs | 2 +- .../core_parser/floating_point_arithmetic.rs | 4 +- .../core_parser/floating_point_branch.rs | 4 +- .../core_parser/floating_point_comparison.rs | 4 +- src/tests/integration/core_parser/mod.rs | 6 +- .../core_parser/store_load_word.rs | 10 +- 15 files changed, 199 insertions(+), 199 deletions(-) diff --git a/src/tests/emulation_core/mips.rs b/src/tests/emulation_core/mips.rs index f04ad427d..9483e3260 100644 --- a/src/tests/emulation_core/mips.rs +++ b/src/tests/emulation_core/mips.rs @@ -15,7 +15,7 @@ pub mod api { // Add instruction into emulation core memory. let instruction = String::from("ori $s0, $zero, 5"); let (_, instruction_bits) = parser(instruction); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.execute_instruction(); @@ -44,7 +44,7 @@ pub mod add { // $t1 = $t1 + $t1 // R-type t1 t1 t1 (shamt) ADD let instructions: Vec = vec![0b000000_01001_01001_01001_00000_100000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume the register $t1 has the value 5. datapath.registers[GpRegisterType::T1] = 5; @@ -63,7 +63,7 @@ pub mod add { // $s2 = $s0 + $s1 // R-type s0 s1 s2 (shamt) ADD let instructions: Vec = vec![0b000000_10000_10001_10010_00000_100000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 15; // $s0 datapath.registers.gpr[17] = 40; // $s1 @@ -85,7 +85,7 @@ pub mod add { // $zero = $t3 + $t3 // R-type t3 t3 zero (shamt) ADD let instructions: Vec = vec![0b000000_01011_01011_00000_00000_100000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[11] = 1234; // $t3 @@ -107,7 +107,7 @@ pub mod add { // $t1 = $t4 + $t4 // R-type t4 t4 t1 (shamt) ADD let instructions: Vec = vec![0b000000_01100_01100_01001_00000_100000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume register $t4 contains 2,454,267,026, a 32-bit integer. datapath.registers.gpr[12] = 0b10010010_01001001_00100100_10010010; @@ -133,7 +133,7 @@ pub mod add { // $t1 = $t4 + $t4 // R-type t4 t4 t1 (shamt) ADD let instructions: Vec = vec![0b000000_01100_01100_01001_00000_100000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume register $t4 contains 3,528,008,850, a 32-bit integer. datapath.registers.gpr[12] = 0b11010010_01001001_00100100_10010010; @@ -158,7 +158,7 @@ pub mod addu { // $t1 = $t1 + $t1 // R-type t1 t1 t1 (shamt) ADDU let instructions: Vec = vec![0b000000_01001_01001_01001_00000_100001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume the register $t1 has the value 5. datapath.registers[GpRegisterType::T1] = 5; @@ -177,7 +177,7 @@ pub mod addu { // $s2 = $s0 + $s1 // R-type s0 s1 s2 (shamt) ADDU let instructions: Vec = vec![0b000000_10000_10001_10010_00000_100001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 15; // $s0 datapath.registers.gpr[17] = 40; // $s1 @@ -199,7 +199,7 @@ pub mod addu { // $zero = $t3 + $t3 // R-type t3 t3 zero (shamt) ADDU let instructions: Vec = vec![0b000000_01011_01011_00000_00000_100001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[11] = 1234; // $t3 @@ -217,7 +217,7 @@ pub mod addu { // $t1 = $t4 + $t4 // R-type t4 t4 t1 (shamt) ADDU let instructions: Vec = vec![0b000000_01100_01100_01001_00000_100001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume register $t4 contains 2,454,267,026, a 32-bit integer. datapath.registers.gpr[12] = 0b10010010_01001001_00100100_10010010; @@ -239,7 +239,7 @@ pub mod addu { // $t1 = $t4 + $t4 // R-type t4 t4 t1 (shamt) ADDU let instructions: Vec = vec![0b000000_01100_01100_01001_00000_100001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume register $t4 contains 3,528,008,850, a 32-bit integer. datapath.registers.gpr[12] = 0b11010010_01001001_00100100_10010010; @@ -265,7 +265,7 @@ pub mod sub { // $s2 = $s3 - $s2 // R-type s3 s2 s2 (shamt) SUB let instructions: Vec = vec![0b000000_10011_10010_10010_00000_100010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[19] = 7; // $s3 datapath.registers.gpr[18] = 3; // $s2 @@ -284,7 +284,7 @@ pub mod sub { // $s0 = $s0 - $t0 // R-type s0 t0 s0 (shamt) SUB let instructions: Vec = vec![0b000000_10000_01000_10000_00000_100010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 5; // $s0 datapath.registers.gpr[8] = 20; // $t0 @@ -307,7 +307,7 @@ pub mod sub { // $s0 = $s0 - $t0 // R-type s0 t0 s0 (shamt) SUB let instructions: Vec = vec![0b000000_10000_01000_10000_00000_100010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 0; // $s0 datapath.registers.gpr[8] = 1; // $t0 @@ -333,7 +333,7 @@ pub mod mul { // $s5 = $t7 * $t6 // R-type t7 t6 s5 MUL SOP30 let instructions: Vec = vec![0b000000_01111_01110_10101_00010_011000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[15] = 8; // $t7 datapath.registers.gpr[14] = 95; // $t6 @@ -351,7 +351,7 @@ pub mod mul { // $s5 = $t7 * $t6 // R-type t7 t6 s5 MUL SOP30 let instructions: Vec = vec![0b000000_01111_01110_10101_00010_011000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[15] = 5; // $t7 datapath.registers.gpr[14] = -5_i64 as u64; // $t6 @@ -369,7 +369,7 @@ pub mod mul { // $s4 = $t6 * $t5 // R-type t6 t5 s4 MUL SOP30 let instructions: Vec = vec![0b000000_01110_01101_10100_00010_011000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[14] = 731_564_544; // $t6 datapath.registers.gpr[13] = 8; // $t5 @@ -397,7 +397,7 @@ pub mod div { // $s4 = $t6 / $t5 // R-type t6 t5 s4 DIV SOP32 let instructions: Vec = vec![0b000000_01110_01101_10100_00010_011010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[14] = 20; // $t6 datapath.registers.gpr[13] = 2; // $t5 @@ -415,7 +415,7 @@ pub mod div { // $s4 = $t6 / $t5 // R-type t6 t5 s4 DIV SOP32 let instructions: Vec = vec![0b000000_01110_01101_10100_00010_011010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[14] = 20; // $t6 datapath.registers.gpr[13] = -5_i64 as u64; // $t5 @@ -437,7 +437,7 @@ pub mod or { // $t1 = $t1 & $t1 // R-type t1 t1 t1 (shamt) OR let instructions: Vec = vec![0b000000_01001_01001_01001_00000_100101]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume the register $t1 has the value 5. datapath.registers[GpRegisterType::T1] = 0x5; @@ -454,7 +454,7 @@ pub mod or { // $s2 = $s0 & $s1 // R-type s0 s1 s2 (shamt) OR let instructions: Vec = vec![0b000000_10000_10001_10010_00000_100101]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 0x1234; // $s0 datapath.registers.gpr[17] = 0x4321; // $s1 @@ -474,7 +474,7 @@ pub mod or { // $s2 = $s0 & $s1 // R-type s0 s1 s2 (shamt) OR let instructions: Vec = vec![0b000000_10000_10001_10010_00000_100101]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 0x12341234; // $s0 datapath.registers.gpr[17] = 0x43214321; // $s1 @@ -494,7 +494,7 @@ pub mod or { // $s2 = $s0 & $s1 // R-type s0 s1 s2 (shamt) OR let instructions: Vec = vec![0b000000_10000_10001_10010_00000_100101]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 0x1234123412341234; // $s0 datapath.registers.gpr[17] = 0x4321432143214321; // $s1 @@ -516,7 +516,7 @@ pub mod or { // $zero = $t3 & $t3 // R-type t3 t3 zero (shamt) OR let instructions: Vec = vec![0b000000_01011_01011_00000_00000_100101]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[11] = 1234; // $t3 @@ -537,7 +537,7 @@ pub mod and { // $t1 = $t1 & $t1 // R-type t1 t1 t1 (shamt) AND let instructions: Vec = vec![0b000000_01001_01001_01001_00000_100100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume the register $t1 has the value 5. datapath.registers[GpRegisterType::T1] = 0x5; @@ -554,7 +554,7 @@ pub mod and { // $s2 = $s0 & $s1 // R-type s0 s1 s2 (shamt) AND let instructions: Vec = vec![0b000000_10000_10001_10010_00000_100100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 0x1234; // $s0 datapath.registers.gpr[17] = 0x4321; // $s1 @@ -574,7 +574,7 @@ pub mod and { // $s2 = $s0 & $s1 // R-type s0 s1 s2 (shamt) AND let instructions: Vec = vec![0b000000_10000_10001_10010_00000_100100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 0x12341234; // $s0 datapath.registers.gpr[17] = 0x43214321; // $s1 @@ -594,7 +594,7 @@ pub mod and { // $s2 = $s0 & $s1 // R-type s0 s1 s2 (shamt) AND let instructions: Vec = vec![0b000000_10000_10001_10010_00000_100100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 0x1234123412341234; // $s0 datapath.registers.gpr[17] = 0x4321432143214321; // $s1 @@ -616,7 +616,7 @@ pub mod and { // $zero = $t3 & $t3 // R-type t3 t3 zero (shamt) AND let instructions: Vec = vec![0b000000_01011_01011_00000_00000_100100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[11] = 1234; // $t3 @@ -638,7 +638,7 @@ pub mod sll { // something // R-type s1 s2 (shamt) SLL let instructions: Vec = vec![0b000000_00000_10001_10010_00000_000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[0b10001] = 123; datapath.registers.gpr[0b10010] = 321; @@ -655,7 +655,7 @@ pub mod sll { // Shift left by two logical // R-type s1 s2 (shamt) SLL let instructions: Vec = vec![0b000000_00000_10001_10010_00010_000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[0b10001] = 0b1010; datapath.registers.gpr[0b10010] = 0; @@ -672,7 +672,7 @@ pub mod sll { // Shift left by two logical // R-type s1 s2 (shamt) SLL let instructions: Vec = vec![0b000000_00000_10001_10010_00010_000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[0b10001] = 0x7fffffff; datapath.registers.gpr[0b10010] = 0x10101011; @@ -694,7 +694,7 @@ pub mod slt { // $s2 = $s0 < $s1 // R-type s0 s1 s2 (shamt) SLT let instructions: Vec = vec![0b000000_10000_10001_10010_00000_101010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::S0] = 1; datapath.registers[GpRegisterType::S1] = 123; @@ -712,7 +712,7 @@ pub mod slt { // $s2 = $s0 < $s1 // R-type s0 s1 s2 (shamt) SLT let instructions: Vec = vec![0b000000_10000_10001_10010_00000_101010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::S0] = 124; datapath.registers[GpRegisterType::S1] = 123; @@ -730,7 +730,7 @@ pub mod slt { // $s2 = $s0 < $s1 // R-type s0 s1 s2 (shamt) SLT let instructions: Vec = vec![0b000000_10000_10001_10010_00000_101010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::S0] = -124_i64 as u64; datapath.registers[GpRegisterType::S1] = 123; @@ -752,7 +752,7 @@ pub mod sltu { // $s2 = $s0 < $s1 // R-type s0 s1 s2 (shamt) SLTU let instructions: Vec = vec![0b000000_10000_10001_10010_00000_101011]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::S0] = 1; datapath.registers[GpRegisterType::S1] = 123; @@ -770,7 +770,7 @@ pub mod sltu { // $s2 = $s0 < $s1 // R-type s0 s1 s2 (shamt) SLTU let instructions: Vec = vec![0b000000_10000_10001_10010_00000_101011]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::S0] = 124; datapath.registers[GpRegisterType::S1] = 123; @@ -788,7 +788,7 @@ pub mod sltu { // $s2 = $s0 < $s1 // R-type s0 s1 s2 (shamt) SLTU let instructions: Vec = vec![0b000000_10000_10001_10010_00000_101011]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::S0] = -124_i64 as u64; datapath.registers[GpRegisterType::S1] = 123; @@ -809,7 +809,7 @@ pub mod andi { // $s0 = $zero & 12345 // andi $zero $s0 12345 let instructions: Vec = vec![0b001100_00000_10000_0011000000111001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); @@ -824,7 +824,7 @@ pub mod andi { // $s0 = $t0 & 12345 // andi $t0 $s0 12345 let instructions: Vec = vec![0b001100_01000_10000_0011000000111001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // In binary: 00111010 11011110 01101000 10110001 datapath.registers.gpr[8] = 987654321; // $t0 @@ -851,7 +851,7 @@ pub mod addi_addiu { // $s0 = $t0 + 0x4 // addi $t0 $s0 4 let instructions: Vec = vec![0b001000_01000_10000_0000000000000100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 1; datapath.registers[GpRegisterType::S0] = 123; datapath.execute_instruction(); @@ -871,7 +871,7 @@ pub mod addi_addiu { // $s0 = $t0 + 0x4 // addi $t0 $s0 4 let instructions: Vec = vec![0b001000_01000_10000_0000000000000100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 0xffffffff; datapath.registers[GpRegisterType::S0] = 123; datapath.execute_instruction(); @@ -888,7 +888,7 @@ pub mod addi_addiu { // $s0 = $t0 + 0x1 // addi $t0 $s0 1 let instructions: Vec = vec![0b001000_01000_10000_0000000000000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 0xfffffff1; datapath.execute_instruction(); @@ -903,7 +903,7 @@ pub mod addi_addiu { // $s0 = $t0 + 0x1 // addi $t0 $s0 1 let instructions: Vec = vec![0b001000_01000_10000_0000000000000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 0xfffffffe; datapath.execute_instruction(); @@ -918,7 +918,7 @@ pub mod addi_addiu { // $s0 = $t0 + 0x4 // addiu $t0 $s0 4 let instructions: Vec = vec![0b001001_01000_10000_0000000000000100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 1; datapath.registers[GpRegisterType::S0] = 123; datapath.execute_instruction(); @@ -934,7 +934,7 @@ pub mod addi_addiu { // $s0 = $t0 + 0x4 // addiu $t0 $s0 4 let instructions: Vec = vec![0b001001_01000_10000_0000000000000100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 0xffffffff; datapath.registers[GpRegisterType::S0] = 123; datapath.execute_instruction(); @@ -951,7 +951,7 @@ pub mod addi_addiu { // $s0 = $t0 + 0x1 // addi $t0 $s0 1 let instructions: Vec = vec![0b001000_01000_10000_0000000000000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 0xfffffff1; datapath.execute_instruction(); @@ -969,7 +969,7 @@ pub mod daddi_and_daddiu { // $s0 = $t0 + 0x4 // daddi $t0 $s0 4 let instructions: Vec = vec![0b011000_01000_10000_0000000000000100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 1; datapath.registers[GpRegisterType::S0] = 123; datapath.execute_instruction(); @@ -989,7 +989,7 @@ pub mod daddi_and_daddiu { // $s0 = $t0 + 0x1 // daddi $t0 $s0 1 let instructions: Vec = vec![0b011000_01000_10000_0000000000000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 0xffffffffffffffff; datapath.registers[GpRegisterType::S0] = 123; datapath.execute_instruction(); @@ -1005,7 +1005,7 @@ pub mod daddi_and_daddiu { // $s0 = $t0 + 0x1 // daddi $t0 $s0 1 let instructions: Vec = vec![0b011000_01000_10000_0000000000000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 0xfffffffffffffff1; datapath.execute_instruction(); @@ -1020,7 +1020,7 @@ pub mod daddi_and_daddiu { // $s0 = $t0 + 0x1 // daddi $t0 $s0 1 let instructions: Vec = vec![0b011000_01000_10000_0000000000000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 0xfffffffffffffffe; datapath.execute_instruction(); @@ -1035,7 +1035,7 @@ pub mod daddi_and_daddiu { // $s0 = $t0 + 0x4 // daddiu $t0 $s0 4 let instructions: Vec = vec![0b011001_01000_10000_0000000000000100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 1; datapath.registers[GpRegisterType::S0] = 123; datapath.execute_instruction(); @@ -1051,7 +1051,7 @@ pub mod daddi_and_daddiu { // $s0 = $t0 + 0x4 // daddiu $t0 $s0 4 let instructions: Vec = vec![0b011001_01000_10000_0000000000000100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 0xffffffffffffffff; datapath.registers[GpRegisterType::S0] = 123; datapath.execute_instruction(); @@ -1069,7 +1069,7 @@ pub mod daddi_and_daddiu { // $s0 = $t0 + 0x1 // daddiu $t0 $s0 1 let instructions: Vec = vec![0b011001_01000_10000_0000000000000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers[GpRegisterType::T0] = 0xfffffffffffffff1; datapath.execute_instruction(); @@ -1087,7 +1087,7 @@ pub mod ori { // $s0 = $zero | 12345 // ori $zero $s0 12345 let instructions: Vec = vec![0b001101_00000_10000_0011000000111001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); @@ -1102,7 +1102,7 @@ pub mod ori { // $s0 = $t0 | 12345 // ori $t0 $s0 12345 let instructions: Vec = vec![0b001101_01000_10000_0011000000111001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // In binary: 00111010 11011110 01101000 10110001 datapath.registers.gpr[8] = 987654321; // $t0 @@ -1133,7 +1133,7 @@ pub mod dadd_daddu { // SPECIAL rs rt rd 0 DADD // 13 13 2 let instructions: Vec = vec![0b000000_01101_01101_00010_00000_101100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume register $t5 contains 969,093,589,304, which is an integer // that takes up 39 bits. @@ -1159,7 +1159,7 @@ pub mod dadd_daddu { // SPECIAL rs rt rd 0 DADD // 13 13 2 let instructions: Vec = vec![0b000000_01101_01101_00010_00000_101100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume register $t5 contains 18,134,889,837,812,767,690, which is an integer // that takes up 64 bits. @@ -1182,7 +1182,7 @@ pub mod dadd_daddu { // SPECIAL rs rt rd 0 DADDU // 16 17 18 let instructions: Vec = vec![0b000000_10000_10001_10010_00000_101101]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 1_069_193_590_294; // $s0 datapath.registers.gpr[17] = 34_359_738_368; // $s1 @@ -1210,7 +1210,7 @@ pub mod dsub_dsubu { // $s4 $s3 $s5 DSUB // 18 17 19 let instructions: Vec = vec![0b000000_10010_10001_10011_00000_101110]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume registers $s3 and $s4 contain numbers larger than 32 bits, // but smaller than 64 bits. @@ -1240,7 +1240,7 @@ pub mod dsub_dsubu { // $s4 $s3 $s5 DSUB // 18 17 19 let instructions: Vec = vec![0b000000_10010_10001_10011_00000_101110]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume registers $s4 is the minimum possible integer and $s4 is 1. datapath.registers.gpr[18] = 0; // $s4 @@ -1263,7 +1263,7 @@ pub mod dsub_dsubu { // SPECIAL rs rt rd 0 DSUBU // 16 17 18 let instructions: Vec = vec![0b000000_10000_10001_10010_00000_101111]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 92_975_612_771_919; // $s0 datapath.registers.gpr[17] = 13_810_775_572_047; // $s1 @@ -1290,7 +1290,7 @@ pub mod dmul_dmulu { // SPECIAL $t8 $t9 $a0 DMUL SOP34 // 24 25 4 let instructions: Vec = vec![0b000000_11000_11001_00100_00010_011100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume register $t8 contains a number larger than 32 bits, // but smaller than 64 bits. @@ -1315,7 +1315,7 @@ pub mod dmul_dmulu { // SPECIAL $t7 $t6 $s7 DMUL SOP34 // 15 14 23 let instructions: Vec = vec![0b000000_01111_01110_10111_00010_011100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume register $t7 contains a number larger than 32 bits, // but smaller than 64 bits. @@ -1340,7 +1340,7 @@ pub mod dmul_dmulu { // SPECIAL $s4 $s3 $s2 DMUL SOP34 // 20 19 18 let instructions: Vec = vec![0b000000_10100_10011_10010_00010_011100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume registers $s4 and $s3 contain numbers larger than 32 bits, // but smaller than 64 bits. @@ -1369,7 +1369,7 @@ pub mod dmul_dmulu { // SPECIAL $s0 $s1 $s2 DMULU SOP35 // 16 17 18 let instructions: Vec = vec![0b000000_10000_10001_10010_00010_011101]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 17_592_186_044_416; // $s0 datapath.registers.gpr[17] = 1_000; // $s1 @@ -1397,7 +1397,7 @@ pub mod ddiv_ddivu { // 17 18 16 let instructions: Vec = vec![0b000000_10001_10010_10000_00010_011110]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume register $s1 contains a number larger than 32 bits, // but smaller than 64 bits. @@ -1425,7 +1425,7 @@ pub mod ddiv_ddivu { // 6 5 7 let instructions: Vec = vec![0b000000_00110_00101_00111_00010_011110]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // Assume register $a2 contains a number larger than 32 bits, // but smaller than 64 bits. @@ -1453,7 +1453,7 @@ pub mod ddiv_ddivu { // 16 17 18 let instructions: Vec = vec![0b000000_10000_10001_10010_00010_011111]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 10_213_202_487_240; // $s0 datapath.registers.gpr[17] = 11; // $s1 @@ -1479,7 +1479,7 @@ pub mod dahi_dati { // op rs rt immediate // REGIMM $a0 DAHI 1 let instructions: Vec = vec![0b000001_00100_00110_0000000000000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[4] = 0xABCD; // $a0 @@ -1501,7 +1501,7 @@ pub mod dahi_dati { // op rs rt immediate // REGIMM $a1 DATI 1 let instructions: Vec = vec![0b000001_00101_11110_0000000000000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[5] = 0xABCD; // $a1 @@ -1523,7 +1523,7 @@ pub mod load_word { // lw $t0 $s0 offset = 0 let instructions: Vec = vec![0b100011_01000_10000_0000000000000000]; - datapath.initialize(instructions.clone())?; + datapath.initialize_legacy(instructions.clone())?; datapath.execute_instruction(); assert_eq!(datapath.registers.gpr[16], instructions[0] as u64); Ok(()) @@ -1537,7 +1537,7 @@ pub mod load_word { // lw $t0 $s0 offset = 4 let instructions: Vec = vec![0b100011_01000_10000_0000000000000100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // place data at address datapath.memory.store_word(0b100, 0x10000)?; @@ -1556,7 +1556,7 @@ pub mod load_word { // lw $t0 $s0 offset = 0 let instructions: Vec = vec![0b100011_01000_10000_0000000000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // place data at address datapath.memory.store_word(0b100, 0x10000)?; @@ -1575,7 +1575,7 @@ pub mod load_word { // lw $t0 $s0 offset = 0 let instructions: Vec = vec![0b100011_01000_10000_0000000000000100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // place data at address datapath.memory.store_word(0b1000, 0x10000)?; @@ -1594,7 +1594,7 @@ pub mod load_word { // lw $t0 $s0 offset = 0 let instructions: Vec = vec![0b100011_01000_10000_1111111111111100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; // place data at address datapath.memory.store_word(0b1000, 0x10000)?; @@ -1615,7 +1615,7 @@ pub mod load_upper_imm { // lui $t0 $s0 offset = 42 let instructions: Vec = vec![0b001111_01000_10000_0010101010101010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); let t = datapath.registers[GpRegisterType::S0]; @@ -1629,7 +1629,7 @@ pub mod load_upper_imm { // lui $t0 $s0 offset = 42 let instructions: Vec = vec![0b001111_01000_10000_1010101010101010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); let t = datapath.registers[GpRegisterType::S0]; @@ -1645,7 +1645,7 @@ pub mod store_word { // sw $t0 $s0 offset = 0 let instructions: Vec = vec![0b101011_01000_10000_0000000000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); let t = datapath.memory.load_word(0)?; @@ -1659,7 +1659,7 @@ pub mod store_word { // sw $t0 $s0 offset = 4 let instructions: Vec = vec![0b101011_01000_10000_0000000000000100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[8] = 0; datapath.registers.gpr[16] = 0xff; @@ -1676,7 +1676,7 @@ pub mod store_word { // sw $t0 $s0 offset = 4 let instructions: Vec = vec![0b101011_01000_10000_0000000000000100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[8] = 4; datapath.registers.gpr[16] = 0xff; @@ -1693,7 +1693,7 @@ pub mod store_word { // sw $t0 $s0 offset = -4 let instructions: Vec = vec![0b101011_01000_10000_1111111111111100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[8] = 12; datapath.registers.gpr[16] = 0xff; @@ -1719,7 +1719,7 @@ pub mod coprocessor { // COP1 fmt ft fs fd function // s $f0 $f1 $f2 ADD let instructions: Vec = vec![0b010001_10000_00000_00001_00010_000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[0] = f32::to_bits(0.25f32) as u64; datapath.coprocessor.fpr[1] = f32::to_bits(0.5f32) as u64; @@ -1742,7 +1742,7 @@ pub mod coprocessor { // COP1 fmt ft fs fd function // d $f0 $f1 $f2 ADD let instructions: Vec = vec![0b010001_10001_00000_00001_00010_000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[0] = f64::to_bits(123.125); datapath.coprocessor.fpr[1] = f64::to_bits(0.5); @@ -1766,7 +1766,7 @@ pub mod coprocessor { // COP1 fmt ft fs fd function // s $f0 $f1 $f2 SUB let instructions: Vec = vec![0b010001_10000_00000_00001_00010_000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[0] = f32::to_bits(5.625f32) as u64; datapath.coprocessor.fpr[1] = f32::to_bits(3.125f32) as u64; @@ -1788,7 +1788,7 @@ pub mod coprocessor { // COP1 fmt ft fs fd function // d $f0 $f1 $f2 SUB let instructions: Vec = vec![0b010001_10001_00000_00001_00010_000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[0] = f64::to_bits(438.125); datapath.coprocessor.fpr[1] = f64::to_bits(98765.5); @@ -1810,7 +1810,7 @@ pub mod coprocessor { // COP1 fmt ft fs fd function // s $f4 $f5 $f9 MUL let instructions: Vec = vec![0b010001_10000_00100_00101_01001_000010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[5] = f32::to_bits(24.5f32) as u64; datapath.coprocessor.fpr[4] = f32::to_bits(0.5f32) as u64; @@ -1832,7 +1832,7 @@ pub mod coprocessor { // COP1 fmt ft fs fd function // d $f9 $f6 $f4 MUL let instructions: Vec = vec![0b010001_10001_01001_00110_00100_000010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[6] = f64::to_bits(-150.0625); datapath.coprocessor.fpr[9] = f64::to_bits(9.5); @@ -1854,7 +1854,7 @@ pub mod coprocessor { // COP1 fmt ft fs fd function // s $f17 $f16 $f15 DIV let instructions: Vec = vec![0b010001_10000_10001_10000_01111_000011]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[16] = f32::to_bits(901f32) as u64; datapath.coprocessor.fpr[17] = f32::to_bits(2f32) as u64; @@ -1879,7 +1879,7 @@ pub mod coprocessor { // COP1 fmt ft fs fd function // d $f20 $f10 $f1 DIV let instructions: Vec = vec![0b010001_10001_10100_01010_00001_000011]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[10] = f64::to_bits(95405.375); datapath.coprocessor.fpr[20] = f64::to_bits(2.0); @@ -1901,7 +1901,7 @@ pub mod coprocessor { // SWC1 base ft offset // $s1 $f3 0 let instructions: Vec = vec![0b111001_10001_00011_0000000000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[17] = 1028; // $s1 datapath.coprocessor.fpr[3] = f32::to_bits(1.0625f32) as u64; @@ -1927,7 +1927,7 @@ pub mod coprocessor { // SWC1 base ft offset // $s0 $f5 32 let instructions: Vec = vec![0b111001_10000_00101_0000000000100000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 2000; // $s0 datapath.coprocessor.fpr[5] = f32::to_bits(3.5f32) as u64; @@ -1957,7 +1957,7 @@ pub mod coprocessor { // SWC1 base ft offset // $s2 $f0 0 let instructions: Vec = vec![0b111001_10010_00000_0000000000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[18] = 1000; // $s2 datapath.coprocessor.fpr[0] = f64::to_bits(9853114.625); @@ -1982,7 +1982,7 @@ pub mod coprocessor { // LWC1 base ft offset // $t0 $f10 0 let instructions: Vec = vec![0b110001_01000_01010_0000000000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[8] = 500; // $t0 @@ -2013,7 +2013,7 @@ pub mod coprocessor { // LWC1 base ft offset // $t1 $f11 200 let instructions: Vec = vec![0b110001_01001_01011_0000000011001000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[9] = 1000; // $t1 @@ -2044,7 +2044,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // s $f2 $f1 0 EQ let instructions: Vec = vec![0b010001_10000_00010_00001_000_00_110010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[1] = f32::to_bits(15.5f32) as u64; datapath.coprocessor.fpr[2] = f32::to_bits(15.5f32) as u64; @@ -2067,7 +2067,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // s $f3 $f14 0 EQ let instructions: Vec = vec![0b010001_10000_00011_01110_000_00_110010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[14] = f32::to_bits(20.125f32) as u64; datapath.coprocessor.fpr[3] = f32::to_bits(100f32) as u64; @@ -2090,7 +2090,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // d $f9 $f5 0 EQ let instructions: Vec = vec![0b010001_10001_01001_00101_000_00_110010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[5] = f64::to_bits(12951.625); datapath.coprocessor.fpr[9] = f64::to_bits(12951.625); @@ -2113,7 +2113,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // d $f19 $f15 0 EQ let instructions: Vec = vec![0b010001_10001_10011_01111_000_00_110010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[15] = f64::to_bits(6016.25); datapath.coprocessor.fpr[19] = f64::to_bits(820.43); @@ -2136,7 +2136,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // s $f0 $f19 0 LT let instructions: Vec = vec![0b010001_10000_00000_10011_000_00_111100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[19] = f32::to_bits(2.875f32) as u64; datapath.coprocessor.fpr[0] = f32::to_bits(70.6f32) as u64; @@ -2159,7 +2159,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // s $f31 $f30 0 LT let instructions: Vec = vec![0b010001_10000_11111_11110_000_00_111100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[30] = f32::to_bits(90.7f32) as u64; datapath.coprocessor.fpr[31] = f32::to_bits(-87.44f32) as u64; @@ -2182,7 +2182,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // d $f29 $f12 0 LT let instructions: Vec = vec![0b010001_10001_11101_01100_000_00_111100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[12] = f64::to_bits(4.0); datapath.coprocessor.fpr[29] = f64::to_bits(30000.6); @@ -2205,7 +2205,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // d $f5 $f4 0 LT let instructions: Vec = vec![0b010001_10001_00101_00100_000_00_111100]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[4] = f64::to_bits(413.420); datapath.coprocessor.fpr[5] = f64::to_bits(-6600.9); @@ -2228,7 +2228,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // s $f1 $f0 0 LE let instructions: Vec = vec![0b010001_10000_00001_00000_000_00_111110]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[0] = f32::to_bits(171.937f32) as u64; datapath.coprocessor.fpr[1] = f32::to_bits(9930.829f32) as u64; @@ -2251,7 +2251,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // s $f3 $f2 0 LE let instructions: Vec = vec![0b010001_10000_00011_00010_000_00_111110]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[2] = f32::to_bits(6.5f32) as u64; datapath.coprocessor.fpr[3] = f32::to_bits(6.5f32) as u64; @@ -2274,7 +2274,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // s $f5 $f4 0 LE let instructions: Vec = vec![0b010001_10000_00101_00100_000_00_111110]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[4] = f32::to_bits(5742.006f32) as u64; datapath.coprocessor.fpr[5] = f32::to_bits(1336.568f32) as u64; @@ -2297,7 +2297,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // d $f7 $f6 0 LE let instructions: Vec = vec![0b010001_10001_00111_00110_000_00_111110]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[6] = f64::to_bits(3483.70216); datapath.coprocessor.fpr[7] = f64::to_bits(7201.56625); @@ -2320,7 +2320,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // d $f9 $f8 0 LE let instructions: Vec = vec![0b010001_10001_01001_01000_000_00_111110]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[8] = f64::to_bits(77.4009); datapath.coprocessor.fpr[9] = f64::to_bits(77.4009); @@ -2343,7 +2343,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // d $f11 $f10 0 LE let instructions: Vec = vec![0b010001_10001_01011_01010_000_00_111110]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[10] = f64::to_bits(9190.43309); datapath.coprocessor.fpr[11] = f64::to_bits(2869.57622); @@ -2366,7 +2366,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // s $f13 $f12 0 NGT let instructions: Vec = vec![0b010001_10000_01101_01100_000_00_111111]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[12] = f32::to_bits(2469.465f32) as u64; datapath.coprocessor.fpr[13] = f32::to_bits(3505.57f32) as u64; @@ -2389,7 +2389,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // s $f15 $f14 0 NGT let instructions: Vec = vec![0b010001_10000_01111_01110_000_00_111111]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[14] = f32::to_bits(7099.472f32) as u64; datapath.coprocessor.fpr[15] = f32::to_bits(87.198f32) as u64; @@ -2412,7 +2412,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // d $f17 $f16 0 NGT let instructions: Vec = vec![0b010001_10001_10001_10000_000_00_111111]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[16] = f64::to_bits(7726.4794015); datapath.coprocessor.fpr[17] = f64::to_bits(9345.7753943); @@ -2435,7 +2435,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // d $f19 $f18 0 NGT let instructions: Vec = vec![0b010001_10001_10011_10010_000_00_111111]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[18] = f64::to_bits(4688.2854359); datapath.coprocessor.fpr[19] = f64::to_bits(819.7956308); @@ -2458,7 +2458,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // s $f21 $f20 0 NGE let instructions: Vec = vec![0b010001_10000_10101_10100_000_00_111101]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[20] = f32::to_bits(3090.244f32) as u64; datapath.coprocessor.fpr[21] = f32::to_bits(7396.444f32) as u64; @@ -2481,7 +2481,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // s $f23 $f22 0 NGE let instructions: Vec = vec![0b010001_10000_10111_10110_000_00_111101]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[22] = f32::to_bits(6269.823f32) as u64; datapath.coprocessor.fpr[23] = f32::to_bits(3089.393f32) as u64; @@ -2504,7 +2504,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // d $f25 $f24 0 NGE let instructions: Vec = vec![0b010001_10001_11001_11000_000_00_111101]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[24] = f64::to_bits(819.7956308); datapath.coprocessor.fpr[25] = f64::to_bits(4688.2854359); @@ -2527,7 +2527,7 @@ pub mod coprocessor { // COP1 fmt ft fs cc __cond // d $f27 $f26 0 NGE let instructions: Vec = vec![0b010001_10001_11011_11010_000_00_111101]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[26] = f64::to_bits(9776.3465875); datapath.coprocessor.fpr[27] = f64::to_bits(1549.8268716); @@ -2557,7 +2557,7 @@ pub mod coprocessor { // 0 -1 (which becomes -4) 0b010001_01000_000_0_1_1111111111111110, ]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[5] = f64::to_bits(12951.625); datapath.coprocessor.fpr[9] = f64::to_bits(12951.625); @@ -2588,7 +2588,7 @@ pub mod coprocessor { // 0 -1 (which becomes -4) 0b010001_01000_000_0_1_1111111111111110, ]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[5] = f64::to_bits(12952.625); datapath.coprocessor.fpr[9] = f64::to_bits(12951.625); @@ -2619,7 +2619,7 @@ pub mod coprocessor { // 0 -1 (which becomes -4) 0b010001_01000_000_0_0_1111111111111110, ]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[4] = f32::to_bits(5742.006f32) as u64; datapath.coprocessor.fpr[5] = f32::to_bits(1336.568f32) as u64; @@ -2650,7 +2650,7 @@ pub mod coprocessor { // 0 -1 (which becomes -4) 0b010001_01000_000_0_0_1111111111111110, ]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[4] = f32::to_bits(742.006f32) as u64; datapath.coprocessor.fpr[5] = f32::to_bits(1336.568f32) as u64; @@ -2674,7 +2674,7 @@ pub mod coprocessor { // COP1 sub rt fs 0 // MT $s0 $f0 let instructions: Vec = vec![0b010001_00100_10000_00000_00000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 25; @@ -2696,7 +2696,7 @@ pub mod coprocessor { // COP1 sub rt fs 0 // MT $s1 $f1 let instructions: Vec = vec![0b010001_00100_10001_00001_00000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[17] = 0x1234_5678_ABCD_BEEF; @@ -2718,7 +2718,7 @@ pub mod coprocessor { // COP1 sub rt fs 0 // DMT $t0 $f30 let instructions: Vec = vec![0b010001_00101_01000_11110_00000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[8] = 0xDEAD_BEEF_FEED_DEED; @@ -2740,7 +2740,7 @@ pub mod coprocessor { // COP1 sub rt fs 0 // MF $s5 $f18 let instructions: Vec = vec![0b010001_00000_10101_10010_00000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[18] = 123; @@ -2762,7 +2762,7 @@ pub mod coprocessor { // COP1 sub rt fs 0 // MF $s6 $f19 let instructions: Vec = vec![0b010001_00000_10110_10011_00000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[19] = 0xABBA_BABB_3ABA_4444; @@ -2784,7 +2784,7 @@ pub mod coprocessor { // COP1 sub rt fs 0 // MF $s7 $f20 let instructions: Vec = vec![0b010001_00000_10111_10100_00000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[20] = 0xBADA_BEEF_BADA_B00E; @@ -2806,7 +2806,7 @@ pub mod coprocessor { // COP1 sub rt fs 0 // DMF $t8 $f21 let instructions: Vec = vec![0b010001_00001_11000_10101_00000000000]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.coprocessor.fpr[21] = 0xADDA_DADD_1BAA_CAFE; @@ -2826,7 +2826,7 @@ pub mod jump_tests { // J let instructions: Vec = vec![0b000010_00_00000000_00000000_00000010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); assert_eq!(datapath.registers.pc, 8); @@ -2839,7 +2839,7 @@ pub mod jump_tests { // J let instructions: Vec = vec![0x0800_0fff]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); assert_eq!(datapath.registers.pc, 0x3ffc); @@ -2853,7 +2853,7 @@ pub mod jump_tests { // J low_26 let instructions: Vec = vec![0x0800_0000 | 0x03ff_ffff]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); assert_eq!(datapath.registers.pc, 0x0fff_fffc); @@ -2870,7 +2870,7 @@ pub mod jump_and_link_tests { // J let instructions: Vec = vec![0b000011_00_00000000_00000000_00000010]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); assert_eq!(datapath.registers.pc, 8); @@ -2885,7 +2885,7 @@ pub mod jump_and_link_tests { // J let instructions: Vec = vec![0x0c00_0fff]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); assert_eq!(datapath.registers.pc, 0x3ffc); @@ -2901,7 +2901,7 @@ pub mod jump_and_link_tests { // J low_26 let instructions: Vec = vec![0x0c00_0000 | 0x03ff_ffff]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); assert_eq!(datapath.registers.pc, 0x0fff_fffc); @@ -2919,7 +2919,7 @@ pub mod jr_and_jalr_tests { // JR $r8 // Special $r8 $zero $zero JALR let instructions: Vec = vec![0b000000_01000_00000_00000_00000_001001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[0b01000] = 24; datapath.execute_instruction(); @@ -2935,7 +2935,7 @@ pub mod jr_and_jalr_tests { // JALR $r8 // Special $r8 $zero $ra JALR let instructions: Vec = vec![0, 0, 0b000000_01000_00000_11111_00000_001001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.pc = 8; let initial_pc = datapath.registers.pc; datapath.registers.gpr[0b01000] = 24; @@ -2955,7 +2955,7 @@ pub mod beq_tests { // beq let instructions: Vec = vec![0b000100_01000_10000_0000000000000001]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; let initial_pc = datapath.registers.pc; datapath.execute_instruction(); @@ -2973,7 +2973,7 @@ pub mod beq_tests { 0b000100_01000_10000_0000000000000001, 0b000100_01000_10000_0000000000000001, ]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[0b01000] = 1234; datapath.registers.gpr[0b10000] = 4321; @@ -2997,7 +2997,7 @@ pub mod beq_tests { 0, // 0x0c 0b000100_01000_10000_1111111111111011, // 0x10, Branch to 0x00 ]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[0b01000] = 1234; datapath.registers.gpr[0b10000] = 1234; @@ -3046,7 +3046,7 @@ pub mod bne_tests { let instructions: Vec = vec![0b000101_01000_10000_0000000000000001]; datapath.registers.gpr[0b01000] = 1234; datapath.registers.gpr[0b10000] = 1234; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.execute_instruction(); let expt_result = 4; // PC + 4, PC starts at 0 with the bne instruction at address 0, no branch acures assert_eq!(datapath.registers.pc, expt_result); @@ -3074,7 +3074,7 @@ pub mod bne_tests { 0, // 0x1c 0b000101_01000_10000_1111111111111001, // 0x20, bne r8, r16, -24, (branch -28 relative to next addres), branch to 0x08 ]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; datapath.registers.gpr[0b01000] = 1234; datapath.registers.gpr[0b10000] = 4321; @@ -3133,7 +3133,7 @@ pub mod syscall { // SPECIAL (code) SYSCALL 0b000000_00000000000000000000_001100, ]; - datapath.initialize(instructions)?; + datapath.initialize_legacy(instructions)?; assert!(!datapath.is_halted()); datapath.registers.gpr[9] = 5; // $t1 diff --git a/src/tests/integration/core_parser/arithmetic.rs b/src/tests/integration/core_parser/arithmetic.rs index be7583455..bf09ce6f0 100644 --- a/src/tests/integration/core_parser/arithmetic.rs +++ b/src/tests/integration/core_parser/arithmetic.rs @@ -9,7 +9,7 @@ fn basic_addu() -> Result<(), String> { let instructions = String::from("addu r20, r19, r18"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[18] = 6849841; datapath.registers.gpr[19] = 99816512; @@ -33,7 +33,7 @@ sll $s1, $s1, 3"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); @@ -54,7 +54,7 @@ move $s5, $s4"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); @@ -72,7 +72,7 @@ fn basic_nop() -> Result<(), String> { let instructions = String::from(r#"nop"#); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; let mut expected_registers = datapath.registers; expected_registers.pc = 4; diff --git a/src/tests/integration/core_parser/basic_immediate.rs b/src/tests/integration/core_parser/basic_immediate.rs index e7653d7c1..46ca3a88e 100644 --- a/src/tests/integration/core_parser/basic_immediate.rs +++ b/src/tests/integration/core_parser/basic_immediate.rs @@ -11,7 +11,7 @@ fn basic_addi() -> Result<(), String> { let instructions = String::from("addi r11, r15, 2"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[15] = 100; @@ -31,7 +31,7 @@ fn basic_addiu() -> Result<(), String> { let instructions = String::from("addiu r14, r17, 5"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[17] = 500; @@ -51,7 +51,7 @@ fn basic_subi() -> Result<(), String> { let instructions = String::from("subi r11, r15, 2"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[15] = 100; @@ -71,7 +71,7 @@ fn basic_muli() -> Result<(), String> { let instructions = String::from("muli r11, r15, 2"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[15] = 100; @@ -91,7 +91,7 @@ fn basic_divi() -> Result<(), String> { let instructions = String::from("divi r11, r15, 2"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[15] = 100; @@ -111,7 +111,7 @@ fn basic_ori() -> Result<(), String> { let instructions = String::from("ori r11, r15, 2"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[15] = 100; @@ -131,7 +131,7 @@ fn basic_andi() -> Result<(), String> { let instructions = String::from("andi r11, r15, 4"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[15] = 100; @@ -151,7 +151,7 @@ fn basic_li() -> Result<(), String> { let instructions = String::from("li r15, 56"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); @@ -170,7 +170,7 @@ fn basic_lui() -> Result<(), String> { let instructions = String::from("lui r20, 65530"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); @@ -190,7 +190,7 @@ fn basic_aui() -> Result<(), String> { let instructions = String::from("aui r15, r18, 4612"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[18] = 0x0000_0000_0030_ABCD; diff --git a/src/tests/integration/core_parser/basic_operations.rs b/src/tests/integration/core_parser/basic_operations.rs index fd2150e3b..4ea6f6728 100644 --- a/src/tests/integration/core_parser/basic_operations.rs +++ b/src/tests/integration/core_parser/basic_operations.rs @@ -9,7 +9,7 @@ fn basic_add() -> Result<(), String> { let instructions = String::from("add r11, r7, r8"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[7] = 51; datapath.registers.gpr[8] = 5; @@ -30,7 +30,7 @@ fn basic_sub() -> Result<(), String> { let instructions = String::from("sub r12, r7, r8"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[7] = 51; datapath.registers.gpr[8] = 5; @@ -51,7 +51,7 @@ fn basic_mul() -> Result<(), String> { let instructions = String::from("mul r13, r7, r8"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[7] = 51; datapath.registers.gpr[8] = 5; @@ -72,7 +72,7 @@ fn basic_div() -> Result<(), String> { let instructions = String::from("div r14, r7, r8"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[7] = 51; datapath.registers.gpr[8] = 5; @@ -93,7 +93,7 @@ fn basic_or() -> Result<(), String> { let instructions = String::from("or r15, r7, r8"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[7] = 51; datapath.registers.gpr[8] = 5; @@ -114,7 +114,7 @@ fn basic_and() -> Result<(), String> { let instructions = String::from("and r16, r7, r8"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[7] = 51; datapath.registers.gpr[8] = 5; diff --git a/src/tests/integration/core_parser/branch_jump.rs b/src/tests/integration/core_parser/branch_jump.rs index 72d55ab65..0cbbcedd5 100644 --- a/src/tests/integration/core_parser/branch_jump.rs +++ b/src/tests/integration/core_parser/branch_jump.rs @@ -17,7 +17,7 @@ j loop"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; // Execute the ori instruction. datapath.execute_instruction(); @@ -45,7 +45,7 @@ jr r15"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; // Execute 2 instructions. for _ in 0..2 { @@ -70,7 +70,7 @@ function: ori $t0, $zero, 5831"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); @@ -96,7 +96,7 @@ function: ori $t1, $zero, 9548"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; // Execute 3 instructions. for _ in 0..3 { @@ -145,7 +145,7 @@ change10: daddiu $s2, $s2, 10"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); @@ -186,7 +186,7 @@ changez: daddiu $s2, $s2, 20"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); @@ -218,7 +218,7 @@ bne $s0, $s2, loop"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; let mut iterations = 0; diff --git a/src/tests/integration/core_parser/conditions.rs b/src/tests/integration/core_parser/conditions.rs index 91d957f12..774cafe66 100644 --- a/src/tests/integration/core_parser/conditions.rs +++ b/src/tests/integration/core_parser/conditions.rs @@ -27,7 +27,7 @@ akin! { let instructions = String::from("*instruction_name r*destination_register, r5, r6"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[5] = *true_value1; datapath.registers.gpr[6] = *true_value2; @@ -46,7 +46,7 @@ akin! { let instructions = String::from("*instruction_name r*destination_register, r5, r6"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[5] = *false_value1; datapath.registers.gpr[6] = *false_value2; diff --git a/src/tests/integration/core_parser/coprocessor_move.rs b/src/tests/integration/core_parser/coprocessor_move.rs index 38de80480..bcff12b7f 100644 --- a/src/tests/integration/core_parser/coprocessor_move.rs +++ b/src/tests/integration/core_parser/coprocessor_move.rs @@ -8,7 +8,7 @@ fn basic_mtc1() -> Result<(), String> { let instructions = String::from("mtc1 $t2, $f5"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[10] = 658461658; // $t2 @@ -26,7 +26,7 @@ fn truncate_32_bit_mtc1() -> Result<(), String> { let instructions = String::from("mtc1 $t3, $f6"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[11] = 0x0000_02F2_AC71_AC41; // $t3 @@ -44,7 +44,7 @@ fn basic_mfc1() -> Result<(), String> { let instructions = String::from("mfc1 $t3, $f5"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.coprocessor.fpr[5] = 657861659; @@ -62,7 +62,7 @@ fn truncate_32_bit_mfc1() -> Result<(), String> { let instructions = String::from("mfc1 $t4, $f6"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.coprocessor.fpr[6] = 0x0003_7F80_E5E7_D785; @@ -80,7 +80,7 @@ fn basic_dmtc1() -> Result<(), String> { let instructions = String::from("dmtc1 $t3, $f6"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[11] = 0x0120_02F2_AC71_AC41; // $t3 @@ -98,7 +98,7 @@ fn basic_dmfc1() -> Result<(), String> { let instructions = String::from("dmfc1 $t4, $f6"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.coprocessor.fpr[6] = 0x0003_7F90_E5E7_D785; diff --git a/src/tests/integration/core_parser/double_arithmetic.rs b/src/tests/integration/core_parser/double_arithmetic.rs index 83ee30fdd..9c2c46e2e 100644 --- a/src/tests/integration/core_parser/double_arithmetic.rs +++ b/src/tests/integration/core_parser/double_arithmetic.rs @@ -17,7 +17,7 @@ akin! { let instructions = String::from(*instruction); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[16] = *value1; datapath.registers.gpr[17] = *value2; @@ -46,7 +46,7 @@ akin! { let instructions = String::from(*instruction); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[25] = *value1; datapath.registers.gpr[26] = *value2; diff --git a/src/tests/integration/core_parser/double_immediate.rs b/src/tests/integration/core_parser/double_immediate.rs index 4bd27b211..531f3795e 100644 --- a/src/tests/integration/core_parser/double_immediate.rs +++ b/src/tests/integration/core_parser/double_immediate.rs @@ -8,7 +8,7 @@ fn basic_dahi() -> Result<(), String> { let instructions = String::from("dahi r3, 123"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[3] = 0; @@ -29,7 +29,7 @@ fn dahi_sign_extend() -> Result<(), String> { let instructions = String::from("dahi r5, 43158"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[5] = 0; @@ -50,7 +50,7 @@ fn basic_dati() -> Result<(), String> { let instructions = String::from("dati r10, 4321"); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[10] = 0; @@ -78,7 +78,7 @@ akin! { let instructions = String::from(*instruction); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[20] = *rs_value; @@ -104,7 +104,7 @@ akin! { let instructions = String::from(*instruction); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.registers.gpr[20] = *rs_value; diff --git a/src/tests/integration/core_parser/fibonacci.rs b/src/tests/integration/core_parser/fibonacci.rs index de64e4399..f380aeaee 100644 --- a/src/tests/integration/core_parser/fibonacci.rs +++ b/src/tests/integration/core_parser/fibonacci.rs @@ -75,7 +75,7 @@ fn recursive_fibonacci() -> Result<(), String> { ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); diff --git a/src/tests/integration/core_parser/floating_point_arithmetic.rs b/src/tests/integration/core_parser/floating_point_arithmetic.rs index c88473c28..7f3466d48 100644 --- a/src/tests/integration/core_parser/floating_point_arithmetic.rs +++ b/src/tests/integration/core_parser/floating_point_arithmetic.rs @@ -19,7 +19,7 @@ akin! { let instructions = String::from(*instruction); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.coprocessor.fpr[15] = *value1; datapath.coprocessor.fpr[16] = *value2; @@ -50,7 +50,7 @@ akin! { let instructions = String::from(*instruction); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.coprocessor.fpr[15] = *value1; datapath.coprocessor.fpr[16] = *value2; diff --git a/src/tests/integration/core_parser/floating_point_branch.rs b/src/tests/integration/core_parser/floating_point_branch.rs index 59db68d78..fb74fd44f 100644 --- a/src/tests/integration/core_parser/floating_point_branch.rs +++ b/src/tests/integration/core_parser/floating_point_branch.rs @@ -31,7 +31,7 @@ bc1t loop"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); @@ -74,7 +74,7 @@ bc1f loop"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); diff --git a/src/tests/integration/core_parser/floating_point_comparison.rs b/src/tests/integration/core_parser/floating_point_comparison.rs index 6b663a17d..45e9ed632 100644 --- a/src/tests/integration/core_parser/floating_point_comparison.rs +++ b/src/tests/integration/core_parser/floating_point_comparison.rs @@ -17,7 +17,7 @@ akin! { let instructions = String::from(*instruction); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.coprocessor.fpr[15] = *value1; datapath.coprocessor.fpr[16] = *value2; @@ -46,7 +46,7 @@ akin! { let instructions = String::from(*instruction); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.coprocessor.fpr[15] = *value1; datapath.coprocessor.fpr[16] = *value2; diff --git a/src/tests/integration/core_parser/mod.rs b/src/tests/integration/core_parser/mod.rs index 1951eeb01..79b7166a5 100644 --- a/src/tests/integration/core_parser/mod.rs +++ b/src/tests/integration/core_parser/mod.rs @@ -31,7 +31,7 @@ add $s1, $s0, $s0"#, // Parse instructions and load into emulation core memory. let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; // Execute 2 instructions. for _ in 0..2 { @@ -70,7 +70,7 @@ dati r1, 43982"#, // Parse instructions and load into emulation core memory. let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; // Execute 4 instructions. for _ in 0..4 { @@ -97,7 +97,7 @@ dmuli r8, r7, 2"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); diff --git a/src/tests/integration/core_parser/store_load_word.rs b/src/tests/integration/core_parser/store_load_word.rs index 68e4473e3..00e7811ec 100644 --- a/src/tests/integration/core_parser/store_load_word.rs +++ b/src/tests/integration/core_parser/store_load_word.rs @@ -13,7 +13,7 @@ sw r25, 0(r14)"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); @@ -34,7 +34,7 @@ lw r25, 0(r14)"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.memory.memory[403] = 36; @@ -62,7 +62,7 @@ sw $s2, secret_number"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); @@ -89,7 +89,7 @@ swc1 $f25, 0($s0)"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; while !datapath.is_halted() { datapath.execute_instruction(); @@ -110,7 +110,7 @@ lwc1 $f12, 0($t4)"#, ); let (_, instruction_bits) = parser(instructions); - datapath.initialize(instruction_bits)?; + datapath.initialize_legacy(instruction_bits)?; datapath.memory.memory[403] = 36; From e61f1cb7d1c75a7c65b61a1f109c6626d2f844a0 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 8 Feb 2024 20:27:13 -0500 Subject: [PATCH 079/355] Send assembled code to the worker thread when the assemble button is clicked --- src/agent.rs | 4 ++-- src/agent/datapath_communicator.rs | 4 ++-- src/agent/messages.rs | 2 +- src/bin/main.rs | 9 ++++++++- src/emulation_core/datapath.rs | 2 +- src/emulation_core/mips/datapath.rs | 4 +++- 6 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index 497a0b2fb..666e0f9a1 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -85,8 +85,8 @@ impl EmulatorCoreAgentState { Command::SetCore(_architecture) => { todo!() // Implement once we have a RISCV datapath } - Command::Initialize(mem) => { - self.current_datapath.initialize(mem).unwrap(); + Command::Initialize(initial_pc, mem) => { + self.current_datapath.initialize(initial_pc, mem).unwrap(); } Command::SetExecuteSpeed(speed) => { self.speed = speed; diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index 18c5d772e..d9cccbec6 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -88,8 +88,8 @@ impl DatapathCommunicator { } /// Resets and loads the parsed/assembled instructions provided into the current emulator core. - pub fn initialize(&self, instructions: Vec) { - self.send_message(Command::Initialize(instructions)); + pub fn initialize(&self, initial_pc: usize, instructions: Vec) { + self.send_message(Command::Initialize(initial_pc, instructions)); } /// Sets the execution speed of the emulator core to the provided speed in hz. If set to zero, the emulator core diff --git a/src/agent/messages.rs b/src/agent/messages.rs index 63a24a1cf..26cad3db9 100644 --- a/src/agent/messages.rs +++ b/src/agent/messages.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Serialize, Deserialize)] pub enum Command { SetCore(AvailableDatapaths), - Initialize(Vec), + Initialize(usize, Vec), SetExecuteSpeed(u32), SetRegister(String, u64), SetMemory(usize, Vec), diff --git a/src/bin/main.rs b/src/bin/main.rs index ddcb01140..27fae92fa 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -19,6 +19,7 @@ use swim::emulation_core::datapath::Datapath; use swim::emulation_core::mips::datapath::MipsDatapath; use swim::emulation_core::mips::datapath::Stage; use swim::parser::parser_assembler_main::parser; +use swim::shims; use swim::ui::console::component::Console; use swim::ui::regview::component::Regview; use wasm_bindgen::{JsCast, JsValue}; @@ -103,6 +104,7 @@ fn app(props: &AppProps) -> Html { let datapath = Rc::clone(&datapath); let parser_text_output = parser_text_output.clone(); let trigger = use_force_update(); + let communicator = props.communicator; let executed_line = executed_line.clone(); let not_highlighted = not_highlighted.clone(); @@ -158,7 +160,7 @@ fn app(props: &AppProps) -> Html { // Proceed with loading into memory and expand pseudo-instructions if there are no errors. if marker_jsarray.length() == 0 { // Load the binary into the datapath's memory - match datapath.initialize_legacy(assembled) { + match datapath.initialize_legacy(assembled.clone()) { Ok(_) => (), Err(msg) => { // In the case of an error, note this and stop early. @@ -168,6 +170,11 @@ fn app(props: &AppProps) -> Html { // log!(datapath.memory.to_string()); text_model.set_value(&program_info.updated_monaco_string); // Expands pseudo-instructions to their hardware counterpart. datapath.registers.pc = program_info.pc_starting_point as u64; + // Send the binary over to the emulation core thread + communicator.initialize( + program_info.pc_starting_point, + shims::convert_to_u8_bytes(assembled), + ) } trigger.force_update(); diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index 47ceb3217..fbcb96e55 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -50,7 +50,7 @@ pub trait Datapath { /// Reset the datapath, load instructions into memory, and un-sets the `is_halted` /// flag. If the process fails, an [`Err`] is returned. - fn initialize(&mut self, instructions: Vec) -> Result<(), String>; + fn initialize(&mut self, initial_pc: usize, instructions: Vec) -> Result<(), String>; /// Retrieve all memory as-is. fn get_memory(&self) -> &Memory; diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index fbddacd88..6f6a5612d 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -273,9 +273,10 @@ impl Datapath for MipsDatapath { todo!() } - fn initialize(&mut self, instructions: Vec) -> Result<(), String> { + fn initialize(&mut self, initial_pc: usize, instructions: Vec) -> Result<(), String> { self.reset(); self.load_instructions(shims::convert_from_u8_bytes(instructions))?; + self.registers.pc = initial_pc as u64; self.is_halted = false; Ok(()) @@ -300,6 +301,7 @@ impl Datapath for MipsDatapath { impl MipsDatapath { // ===================== General Functions ===================== + /// Legacy initialize function, to be removed later. pub fn initialize_legacy(&mut self, instructions: Vec) -> Result<(), String> { self.reset(); self.load_instructions(instructions)?; From 4fed19e404ec4a7f9da9b06866d15fcf398a14b9 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 8 Feb 2024 21:22:04 -0500 Subject: [PATCH 080/355] Utilize the new reducer from the UI in the register view --- src/agent.rs | 4 +++ src/agent/datapath_communicator.rs | 19 +++++++--- src/agent/datapath_reducer.rs | 58 ++++++++++++++++++++++++++++++ src/agent/messages.rs | 1 + src/bin/main.rs | 15 ++++++-- 5 files changed, 89 insertions(+), 8 deletions(-) create mode 100644 src/agent/datapath_reducer.rs diff --git a/src/agent.rs b/src/agent.rs index 666e0f9a1..fe2cbeb67 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -12,6 +12,7 @@ use yew::platform::time::sleep; use yew_agent::prelude::*; pub mod datapath_communicator; +pub mod datapath_reducer; pub mod messages; /// The main logic for the emulation core agent. All code within this function runs on a worker thread as opposed to @@ -109,6 +110,9 @@ impl EmulatorCoreAgentState { Command::Pause => { self.executing = false; } + Command::Reset => { + self.current_datapath.reset(); + } } } diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index d9cccbec6..b10dc6d1d 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -1,3 +1,4 @@ +use crate::agent::datapath_reducer::DatapathReducer; use crate::agent::messages::Command; use crate::agent::EmulationCoreAgent; use crate::emulation_core::architectures::AvailableDatapaths; @@ -8,7 +9,7 @@ use futures::StreamExt; use gloo_console::log; use gloo_console::warn; use std::cell::RefCell; -use yew::UseForceUpdateHandle; +use yew::UseReducerDispatcher; use yew_agent::reactor::ReactorBridge; /// This struct provides an abstraction over all communication with the worker thread. Any commands to the worker @@ -46,7 +47,10 @@ impl DatapathCommunicator { /// from the main app component. After updating internal state, the component this was called from will be force /// updated. #[allow(clippy::await_holding_refcell_ref)] - pub async fn listen_for_updates(&self, update_handle: UseForceUpdateHandle) { + pub async fn listen_for_updates( + &self, + dispatcher_handle: UseReducerDispatcher, + ) { let mut reader = match self.reader.try_borrow_mut() { Ok(reader) => reader, Err(_) => { @@ -59,10 +63,10 @@ impl DatapathCommunicator { log!("Waiting..."); let update = reader.next().await; log!(format!("Got update {:?}", update)); - if update.is_none() { - return; + match update { + None => return, + Some(update) => dispatcher_handle.dispatch(update), } - update_handle.force_update(); } } @@ -128,4 +132,9 @@ impl DatapathCommunicator { pub fn pause_core(&self) { self.send_message(Command::Pause); } + + /// Resets the current core to its default state. + pub fn reset(&self) { + self.send_message(Command::Reset); + } } diff --git a/src/agent/datapath_reducer.rs b/src/agent/datapath_reducer.rs new file mode 100644 index 000000000..e102cfbf1 --- /dev/null +++ b/src/agent/datapath_reducer.rs @@ -0,0 +1,58 @@ +use crate::agent::messages::MipsStateUpdate; +use crate::emulation_core::architectures::AvailableDatapaths::MIPS; +use crate::emulation_core::architectures::{AvailableDatapaths, DatapathUpdate}; +use crate::emulation_core::mips::datapath::DatapathState; +use crate::emulation_core::mips::memory::Memory; +use crate::emulation_core::mips::registers::GpRegisters; +use std::rc::Rc; +use yew::Reducible; + +pub struct DatapathReducer { + pub current_architecture: AvailableDatapaths, + pub mips: MipsState, +} + +#[derive(Default)] +pub struct MipsState { + pub state: DatapathState, + pub registers: GpRegisters, + pub memory: Memory, +} + +impl Default for DatapathReducer { + fn default() -> Self { + Self { + current_architecture: MIPS, + mips: MipsState::default(), + } + } +} + +impl Reducible for DatapathReducer { + type Action = DatapathUpdate; + + fn reduce(self: Rc, action: Self::Action) -> Rc { + Rc::from(match action { + DatapathUpdate::MIPS(update) => Self { + current_architecture: AvailableDatapaths::MIPS, + mips: match update { + MipsStateUpdate::UpdateState(state) => MipsState { + state, + registers: self.mips.registers, + memory: self.mips.memory.clone(), + }, + MipsStateUpdate::UpdateRegisters(registers) => MipsState { + state: self.mips.state.clone(), + registers, + memory: self.mips.memory.clone(), + }, + MipsStateUpdate::UpdateMemory(memory) => MipsState { + state: self.mips.state.clone(), + registers: self.mips.registers, + memory, + }, + }, + }, + }) + } +} diff --git a/src/agent/messages.rs b/src/agent/messages.rs index 26cad3db9..b92c23208 100644 --- a/src/agent/messages.rs +++ b/src/agent/messages.rs @@ -16,6 +16,7 @@ pub enum Command { ExecuteInstruction, ExecuteStage, Pause, + Reset, } /// Information about the emulator core's state sent from the worker thread to the UI thread. diff --git a/src/bin/main.rs b/src/bin/main.rs index 27fae92fa..8136bd1c2 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -14,6 +14,7 @@ use monaco::{ }; use std::rc::Rc; use swim::agent::datapath_communicator::DatapathCommunicator; +use swim::agent::datapath_reducer::DatapathReducer; use swim::agent::EmulationCoreAgent; use swim::emulation_core::datapath::Datapath; use swim::emulation_core::mips::datapath::MipsDatapath; @@ -86,13 +87,15 @@ fn app(props: &AppProps) -> Html { // the ability to access and change its contents be mutable. let datapath = use_mut_ref(MipsDatapath::default); + let datapath_state = use_reducer(DatapathReducer::default); + // Start listening for messages from the communicator. This effectively links the worker thread to the main thread // and will force updates whenever its internal state changes. { - let trigger = use_force_update(); + let dispatcher = datapath_state.dispatcher(); use_effect_with_deps( move |communicator| { - spawn_local(communicator.listen_for_updates(trigger)); + spawn_local(communicator.listen_for_updates(dispatcher)); }, props.communicator, ); @@ -193,6 +196,7 @@ fn app(props: &AppProps) -> Html { let text_model = Rc::clone(&text_model); let datapath = Rc::clone(&datapath); let trigger = use_force_update(); + let communicator = props.communicator; let executed_line = executed_line.clone(); let not_highlighted = not_highlighted.clone(); @@ -248,6 +252,7 @@ fn app(props: &AppProps) -> Html { // log!(not_highlighted.at(0)); datapath.execute_instruction(); + communicator.execute_instruction(); // done with the highlight, prepare for the next one. executed_line.pop(); @@ -269,6 +274,7 @@ fn app(props: &AppProps) -> Html { let not_highlighted = not_highlighted.clone(); let highlight_decor = highlight_decor; let trigger = use_force_update(); + let communicator = props.communicator; use_callback( move |_, _| { @@ -305,6 +311,7 @@ fn app(props: &AppProps) -> Html { } else { datapath.execute_stage(); } + communicator.execute_stage(); trigger.force_update(); }, (), @@ -318,6 +325,7 @@ fn app(props: &AppProps) -> Html { let datapath = Rc::clone(&datapath); let trigger = use_force_update(); let parser_text_output = parser_text_output.clone(); + let communicator = props.communicator; let executed_line = executed_line; let not_highlighted = not_highlighted; @@ -336,6 +344,7 @@ fn app(props: &AppProps) -> Html { ); parser_text_output.set("".to_string()); datapath.reset(); + communicator.reset(); trigger.force_update(); }, (), @@ -481,7 +490,7 @@ fn app(props: &AppProps) -> Html {
// Right column - +
} From 290e0fbd4fe3bf52beea96b50a5420869a698a30 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 8 Feb 2024 21:34:07 -0500 Subject: [PATCH 081/355] Add some documentation and clean up code --- src/agent.rs | 4 +++- src/emulation_core/datapath.rs | 6 +++--- src/emulation_core/mips/datapath.rs | 6 +++++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index fe2cbeb67..add746df6 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -36,6 +36,7 @@ pub async fn emulation_core_agent(scope: ReactorScope) _ = sleep(Duration::from_millis(execution_delay)).fuse() => {}, } } else { + // If we're not currently executing, wait indefinitely until the next message comes in. match state.scope.next().await { Some(msg) => state.handle_command(msg), None => return, @@ -48,6 +49,7 @@ pub async fn emulation_core_agent(scope: ReactorScope) // Part 3: Processing State/Sending Updates to UI // TODO: This is a very naive implementation. Optimization is probably a good idea. + // TODO: Add support for the FP coprocessor updates in MIPS match state.current_datapath.as_datapath_ref() { DatapathRef::MIPS(datapath) => { let state_update = @@ -96,7 +98,7 @@ impl EmulatorCoreAgentState { self.current_datapath.set_register_by_str(®ister, value); } Command::SetMemory(ptr, data) => { - self.current_datapath.set_memory(ptr, &data); + self.current_datapath.set_memory(ptr, data); } Command::Execute => { self.executing = true; diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index fbcb96e55..4529ab819 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -55,9 +55,7 @@ pub trait Datapath { /// Retrieve all memory as-is. fn get_memory(&self) -> &Memory; - fn set_memory(&mut self, _ptr: usize, _data: &[u8]) { - todo!() - } + fn set_memory(&mut self, ptr: usize, data: Vec); /// Returns if the datapath is in a "halted" or "stopped" state. This may /// be true in the case where an error had occurred previously. @@ -66,6 +64,8 @@ pub trait Datapath { /// Restore the datapath to its default state. fn reset(&mut self); + /// Obtain a reference to the concrete datapath type. Used when datapath-specific logic is + /// needed while dealing with a datapath as a trait object. fn as_datapath_ref(&self) -> DatapathRef; } diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index 6f6a5612d..322fb262d 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -41,7 +41,7 @@ //! # Notes on `is_halted` //! //! - The datapath starts with the `is_halted` flag set. -//! - [`MipsDatapath::initialize_legacy()`] should be used to un-set `is_halted`. +//! - [`MipsDatapath::initialize()`] should be used to un-set `is_halted`. //! - The `syscall` instruction simply performs a no-operation instruction, except for //! setting the boolean flag `is_halted`. //! - Invalid instructions will cause the datapath to set the `is_halted` flag. @@ -286,6 +286,10 @@ impl Datapath for MipsDatapath { &self.memory } + fn set_memory(&mut self, _ptr: usize, _data: Vec) { + todo!() + } + fn is_halted(&self) -> bool { self.is_halted } From 5f7be64fd0d9548b3afb3ede05255312b1e70523 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 8 Feb 2024 21:48:33 -0500 Subject: [PATCH 082/355] Rename MipsState to MipsCoreState --- src/agent/datapath_reducer.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/agent/datapath_reducer.rs b/src/agent/datapath_reducer.rs index e102cfbf1..55f073675 100644 --- a/src/agent/datapath_reducer.rs +++ b/src/agent/datapath_reducer.rs @@ -9,11 +9,11 @@ use yew::Reducible; pub struct DatapathReducer { pub current_architecture: AvailableDatapaths, - pub mips: MipsState, + pub mips: MipsCoreState, } #[derive(Default)] -pub struct MipsState { +pub struct MipsCoreState { pub state: DatapathState, pub registers: GpRegisters, pub memory: Memory, @@ -23,7 +23,7 @@ impl Default for DatapathReducer { fn default() -> Self { Self { current_architecture: MIPS, - mips: MipsState::default(), + mips: MipsCoreState::default(), } } } @@ -34,19 +34,19 @@ impl Reducible for DatapathReducer { fn reduce(self: Rc, action: Self::Action) -> Rc { Rc::from(match action { DatapathUpdate::MIPS(update) => Self { - current_architecture: AvailableDatapaths::MIPS, + current_architecture: MIPS, mips: match update { - MipsStateUpdate::UpdateState(state) => MipsState { + MipsStateUpdate::UpdateState(state) => MipsCoreState { state, registers: self.mips.registers, memory: self.mips.memory.clone(), }, - MipsStateUpdate::UpdateRegisters(registers) => MipsState { + MipsStateUpdate::UpdateRegisters(registers) => MipsCoreState { state: self.mips.state.clone(), registers, memory: self.mips.memory.clone(), }, - MipsStateUpdate::UpdateMemory(memory) => MipsState { + MipsStateUpdate::UpdateMemory(memory) => MipsCoreState { state: self.mips.state.clone(), registers: self.mips.registers, memory, From a419b1e363163f2cd4734bfe2f2797ba7316cf0c Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Fri, 16 Feb 2024 16:06:15 -0500 Subject: [PATCH 083/355] Go back to using Vec for instructions --- src/agent/datapath_communicator.rs | 2 +- src/agent/messages.rs | 2 +- src/bin/main.rs | 6 +----- src/emulation_core/datapath.rs | 2 +- src/emulation_core/mips/datapath.rs | 5 ++--- src/lib.rs | 1 - src/shims.rs | 19 ------------------- 7 files changed, 6 insertions(+), 31 deletions(-) delete mode 100644 src/shims.rs diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index b10dc6d1d..5d068388a 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -92,7 +92,7 @@ impl DatapathCommunicator { } /// Resets and loads the parsed/assembled instructions provided into the current emulator core. - pub fn initialize(&self, initial_pc: usize, instructions: Vec) { + pub fn initialize(&self, initial_pc: usize, instructions: Vec) { self.send_message(Command::Initialize(initial_pc, instructions)); } diff --git a/src/agent/messages.rs b/src/agent/messages.rs index b92c23208..1bd4379ca 100644 --- a/src/agent/messages.rs +++ b/src/agent/messages.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Serialize, Deserialize)] pub enum Command { SetCore(AvailableDatapaths), - Initialize(usize, Vec), + Initialize(usize, Vec), SetExecuteSpeed(u32), SetRegister(String, u64), SetMemory(usize, Vec), diff --git a/src/bin/main.rs b/src/bin/main.rs index 8136bd1c2..1027bb9e8 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -20,7 +20,6 @@ use swim::emulation_core::datapath::Datapath; use swim::emulation_core::mips::datapath::MipsDatapath; use swim::emulation_core::mips::datapath::Stage; use swim::parser::parser_assembler_main::parser; -use swim::shims; use swim::ui::console::component::Console; use swim::ui::regview::component::Regview; use wasm_bindgen::{JsCast, JsValue}; @@ -174,10 +173,7 @@ fn app(props: &AppProps) -> Html { text_model.set_value(&program_info.updated_monaco_string); // Expands pseudo-instructions to their hardware counterpart. datapath.registers.pc = program_info.pc_starting_point as u64; // Send the binary over to the emulation core thread - communicator.initialize( - program_info.pc_starting_point, - shims::convert_to_u8_bytes(assembled), - ) + communicator.initialize(program_info.pc_starting_point, assembled) } trigger.force_update(); diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index 4529ab819..4744d3d65 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -50,7 +50,7 @@ pub trait Datapath { /// Reset the datapath, load instructions into memory, and un-sets the `is_halted` /// flag. If the process fails, an [`Err`] is returned. - fn initialize(&mut self, initial_pc: usize, instructions: Vec) -> Result<(), String>; + fn initialize(&mut self, initial_pc: usize, instructions: Vec) -> Result<(), String>; /// Retrieve all memory as-is. fn get_memory(&self) -> &Memory; diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index 322fb262d..bdec0ddfd 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -53,7 +53,6 @@ use super::datapath_signals::*; use super::instruction::*; use super::{coprocessor::MipsFpCoprocessor, memory::Memory, registers::GpRegisters}; use crate::emulation_core::architectures::DatapathRef; -use crate::shims; use serde::{Deserialize, Serialize}; /// An implementation of a datapath for the MIPS64 ISA. @@ -273,9 +272,9 @@ impl Datapath for MipsDatapath { todo!() } - fn initialize(&mut self, initial_pc: usize, instructions: Vec) -> Result<(), String> { + fn initialize(&mut self, initial_pc: usize, instructions: Vec) -> Result<(), String> { self.reset(); - self.load_instructions(shims::convert_from_u8_bytes(instructions))?; + self.load_instructions(instructions)?; self.registers.pc = initial_pc as u64; self.is_halted = false; diff --git a/src/lib.rs b/src/lib.rs index 2ba0135bb..825d617f2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,6 @@ pub mod agent; pub mod emulation_core; pub mod parser; -pub mod shims; #[cfg(test)] pub mod tests; pub mod ui; diff --git a/src/shims.rs b/src/shims.rs deleted file mode 100644 index 625c13684..000000000 --- a/src/shims.rs +++ /dev/null @@ -1,19 +0,0 @@ -//! Temporary shims to get things working for demos. These should NOT be used in the final version. - -pub fn convert_to_u8_bytes(input: Vec) -> Vec { - let mut res = Vec::new(); - for int in input { - for byte in int.to_le_bytes() { - res.push(byte); - } - } - res -} - -pub fn convert_from_u8_bytes(input: Vec) -> Vec { - let mut res = Vec::new(); - for int_bytes in input.chunks(4) { - res.push(u32::from_le_bytes(int_bytes.try_into().unwrap())); - } - res -} From dbd583855eef544ce9b8b0c07be7d3b38284bc1c Mon Sep 17 00:00:00 2001 From: rharding8 Date: Fri, 2 Feb 2024 18:09:44 -0500 Subject: [PATCH 084/355] Emulation core updated incorporating correct RISCV control signals in the datapath, minus memory operations. STILL TODO: Memory operations Adding operations Making it all work --- src/emulation_core.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/emulation_core.rs b/src/emulation_core.rs index ac45cc291..9a0df17e2 100644 --- a/src/emulation_core.rs +++ b/src/emulation_core.rs @@ -2,4 +2,4 @@ pub mod architectures; pub mod datapath; -pub mod mips; +pub mod mips; \ No newline at end of file From 7373a9a5a9c9ddd1dc9f7b7bc16860ea3a9a6113 Mon Sep 17 00:00:00 2001 From: rharding8 Date: Wed, 7 Feb 2024 15:23:44 -0500 Subject: [PATCH 085/355] Updated some memory sections of the Datapath. Now moving onto branching and jumping handling. --- src/emulation_core.rs | 3 ++- src/emulation_core/riscv/datapath.rs | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/emulation_core.rs b/src/emulation_core.rs index 9a0df17e2..d8e854554 100644 --- a/src/emulation_core.rs +++ b/src/emulation_core.rs @@ -2,4 +2,5 @@ pub mod architectures; pub mod datapath; -pub mod mips; \ No newline at end of file +pub mod mips; +pub mod riscv; \ No newline at end of file diff --git a/src/emulation_core/riscv/datapath.rs b/src/emulation_core/riscv/datapath.rs index d43fbc62e..ebe10e58f 100644 --- a/src/emulation_core/riscv/datapath.rs +++ b/src/emulation_core/riscv/datapath.rs @@ -46,12 +46,16 @@ //! setting the boolean flag `is_halted`. //! - Invalid instructions will cause the datapath to set the `is_halted` flag. +use crate::tests::emulation_core::mips::add; + use super::super::datapath::Datapath; use super::constants::*; use super::control_signals::*; +use super::control_signals::*; use super::datapath_signals::*; use super::instruction::*; use super::{memory::Memory, registers::GpRegisters}; +use super::{memory::Memory, registers::GpRegisters}; /// An implementation of a datapath for the MIPS64 ISA. #[derive(Clone, PartialEq)] @@ -316,6 +320,9 @@ impl RiscDatapath { self.set_immediate(); self.read_registers(); + // Upper part of datapath, PC calculation + self.construct_jump_address(); + /* Finish this instruction out of the datapath and halt if this is a syscall. if let Instruction::SyscallType(_) = self.instruction { self.is_halted = true; From 8959b53cddd65de4b2c6b059112ea865939d6176 Mon Sep 17 00:00:00 2001 From: rharding8 Date: Fri, 16 Feb 2024 17:04:01 -0500 Subject: [PATCH 086/355] Removed RISC-V from main module rs. Just to test GitHub. --- src/emulation_core.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/emulation_core.rs b/src/emulation_core.rs index d8e854554..9a0df17e2 100644 --- a/src/emulation_core.rs +++ b/src/emulation_core.rs @@ -2,5 +2,4 @@ pub mod architectures; pub mod datapath; -pub mod mips; -pub mod riscv; \ No newline at end of file +pub mod mips; \ No newline at end of file From 3cf32f6045f14c4f2ae6971cb3a20e8f894dc030 Mon Sep 17 00:00:00 2001 From: rharding8 Date: Fri, 16 Feb 2024 17:10:25 -0500 Subject: [PATCH 087/355] Another test. --- src/emulation_core.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/emulation_core.rs b/src/emulation_core.rs index 9a0df17e2..ac45cc291 100644 --- a/src/emulation_core.rs +++ b/src/emulation_core.rs @@ -2,4 +2,4 @@ pub mod architectures; pub mod datapath; -pub mod mips; \ No newline at end of file +pub mod mips; From 398100b1fcdf6b7a3153dead72be7809fab364d5 Mon Sep 17 00:00:00 2001 From: rharding8 Date: Fri, 16 Feb 2024 18:25:29 -0500 Subject: [PATCH 088/355] Rebased + Smoothed Out Files --- src/emulation_core/mips/memory.rs | 48 ++++++++++++++++++++++++++++ src/emulation_core/riscv/datapath.rs | 44 ++++++++++++++----------- 2 files changed, 73 insertions(+), 19 deletions(-) diff --git a/src/emulation_core/mips/memory.rs b/src/emulation_core/mips/memory.rs index 6dae642cf..48df0801e 100644 --- a/src/emulation_core/mips/memory.rs +++ b/src/emulation_core/mips/memory.rs @@ -48,6 +48,29 @@ impl Memory { } } + // A byte is 8 bits. + pub fn store_byte(&mut self, address: u64, data: u8) -> Result<(), String> { + let address = address as usize; + + self.check_valid_address(address)?; + + self.memory[address] = (data & 0b11111111) as u8; + + Ok(()) + } + + // A word is 32 bits. + pub fn store_half(&mut self, address: u64, data: u16) -> Result<(), String> { + let address = address as usize; + + self.check_valid_address(address)?; + + self.memory[address] = ((data >> 8) & 0b11111111) as u8; + self.memory[address + 1] = (data & 0b11111111) as u8; + + Ok(()) + } + // A word is 32 bits. pub fn store_word(&mut self, address: u64, data: u32) -> Result<(), String> { let address = address as usize; @@ -73,6 +96,31 @@ impl Memory { Ok(()) } + // A byte is 8 bits. + pub fn load_byte(&self, address: u64) -> Result { + let address = address as usize; + + self.check_valid_address(address)?; + + let mut result: u8 = 0; + result |= self.memory[address]; + + Ok(result) + } + + // A half-word is 16 bits. + pub fn load_half(&self, address: u64) -> Result { + let address = address as usize; + + self.check_valid_address(address)?; + + let mut result: u16 = 0; + result |= (self.memory[address] as u16) << 8; + result |= self.memory[address + 1] as u16; + + Ok(result) + } + // A word is 32 bits. pub fn load_word(&self, address: u64) -> Result { let address = address as usize; diff --git a/src/emulation_core/riscv/datapath.rs b/src/emulation_core/riscv/datapath.rs index ebe10e58f..586b39c18 100644 --- a/src/emulation_core/riscv/datapath.rs +++ b/src/emulation_core/riscv/datapath.rs @@ -46,16 +46,13 @@ //! setting the boolean flag `is_halted`. //! - Invalid instructions will cause the datapath to set the `is_halted` flag. -use crate::tests::emulation_core::mips::add; - use super::super::datapath::Datapath; use super::constants::*; use super::control_signals::*; -use super::control_signals::*; use super::datapath_signals::*; use super::instruction::*; -use super::{memory::Memory, registers::GpRegisters}; -use super::{memory::Memory, registers::GpRegisters}; +use crate::emulation_core::architectures::DatapathRef; +use super::{super::mips::memory::Memory, registers::GpRegisters}; /// An implementation of a datapath for the MIPS64 ISA. #[derive(Clone, PartialEq)] @@ -215,7 +212,16 @@ impl Default for RiscDatapath { impl Datapath for RiscDatapath { type RegisterData = u64; type RegisterEnum = super::registers::GpRegisterType; - type MemoryType = Memory; + + /// Reset the datapath, load instructions into memory, and un-sets the `is_halted` + /// flag. If the process fails, an [`Err`] is returned. + fn initialize(&mut self, initial_pc: usize, instructions: Vec) -> Result<(), String> { + self.reset(); + self.load_instructions(instructions)?; + self.is_halted = false; + + Ok(()) + } fn execute_instruction(&mut self) { loop { @@ -256,10 +262,18 @@ impl Datapath for RiscDatapath { self.registers[register] } - fn get_memory(&self) -> &Self::MemoryType { + fn set_register_by_str(&mut self, _register: &str, _data: Self::RegisterData) { + todo!() + } + + fn get_memory(&self) -> &Memory { &self.memory } + fn set_memory(&mut self, ptr: usize, data: Vec) { + todo!(); + } + fn is_halted(&self) -> bool { self.is_halted } @@ -267,19 +281,14 @@ impl Datapath for RiscDatapath { fn reset(&mut self) { std::mem::take(self); } + + fn as_datapath_ref(&self) -> DatapathRef { + todo!(); + } } impl RiscDatapath { // ===================== General Functions ===================== - /// Reset the datapath, load instructions into memory, and un-sets the `is_halted` - /// flag. If the process fails, an [`Err`] is returned. - pub fn initialize(&mut self, instructions: Vec) -> Result<(), String> { - self.reset(); - self.load_instructions(instructions)?; - self.is_halted = false; - - Ok(()) - } /// Load a vector of 32-bit instructions into memory. If the process fails, /// from a lack of space or otherwise, an [`Err`] is returned. @@ -320,9 +329,6 @@ impl RiscDatapath { self.set_immediate(); self.read_registers(); - // Upper part of datapath, PC calculation - self.construct_jump_address(); - /* Finish this instruction out of the datapath and halt if this is a syscall. if let Instruction::SyscallType(_) = self.instruction { self.is_halted = true; From 34ba2a3610c5f71f192e78857800ea4932406392 Mon Sep 17 00:00:00 2001 From: rharding8 Date: Fri, 16 Feb 2024 18:28:30 -0500 Subject: [PATCH 089/355] Fixed memory format issue. --- src/emulation_core/mips/memory.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/emulation_core/mips/memory.rs b/src/emulation_core/mips/memory.rs index 48df0801e..5f6a4b92f 100644 --- a/src/emulation_core/mips/memory.rs +++ b/src/emulation_core/mips/memory.rs @@ -54,7 +54,7 @@ impl Memory { self.check_valid_address(address)?; - self.memory[address] = (data & 0b11111111) as u8; + self.memory[address] = data; Ok(()) } From d02826467daa7d46ff1b99bbc0f37f68b601d45c Mon Sep 17 00:00:00 2001 From: Cay Date: Fri, 16 Feb 2024 18:51:47 -0500 Subject: [PATCH 090/355] Run cargo fmt --- src/agent.rs | 4 +- src/agent/datapath_reducer.rs | 2 +- src/agent/messages.rs | 4 +- src/bin/main.rs | 77 ++++++++----- src/emulation_core/mips/instruction.rs | 137 ++++++++++++------------ src/emulation_core/mips/memory.rs | 8 +- src/emulation_core/mips/registers.rs | 4 +- src/parser/parser_assembler_main.rs | 8 +- src/parser/parser_structs_and_enums.rs | 5 +- src/tests/emulation_core.rs | 2 +- src/tests/emulation_core/instruction.rs | 7 +- src/ui.rs | 3 +- src/ui/assembled_view/component.rs | 70 ++++++------ src/ui/assembled_view/mod.rs | 2 +- src/ui/console/component.rs | 74 +++++++------ src/ui/console/mod.rs | 2 +- src/ui/footer/component.rs | 14 +-- src/ui/hex_editor/component.rs | 31 +++--- src/ui/regview/component.rs | 32 ++++-- src/ui/swim_editor/component.rs | 42 +++++--- src/ui/swim_editor/mod.rs | 2 +- 21 files changed, 297 insertions(+), 233 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index a21634060..9fa449491 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -58,7 +58,9 @@ pub async fn emulation_core_agent(scope: ReactorScope) DatapathUpdate::MIPS(MipsStateUpdate::UpdateRegisters(datapath.registers)); let memory_update = DatapathUpdate::MIPS(MipsStateUpdate::UpdateMemory(datapath.memory.clone())); - let stage_update = DatapathUpdate::MIPS(MipsStateUpdate::UpdateStage(datapath.current_stage.clone())); + let stage_update = DatapathUpdate::MIPS(MipsStateUpdate::UpdateStage( + datapath.current_stage.clone(), + )); state.scope.send(state_update).await.unwrap(); state.scope.send(register_update).await.unwrap(); state.scope.send(memory_update).await.unwrap(); diff --git a/src/agent/datapath_reducer.rs b/src/agent/datapath_reducer.rs index bbde6e936..88e77eaaf 100644 --- a/src/agent/datapath_reducer.rs +++ b/src/agent/datapath_reducer.rs @@ -18,7 +18,7 @@ pub struct MipsCoreState { pub state: DatapathState, pub registers: GpRegisters, pub memory: Memory, - pub current_stage: Stage + pub current_stage: Stage, } impl Default for DatapathReducer { diff --git a/src/agent/messages.rs b/src/agent/messages.rs index 6c4ff504a..664c2deaa 100644 --- a/src/agent/messages.rs +++ b/src/agent/messages.rs @@ -1,7 +1,7 @@ -use crate::emulation_core::{architectures::AvailableDatapaths, mips::datapath::Stage}; use crate::emulation_core::mips::datapath::DatapathState; use crate::emulation_core::mips::memory::Memory; use crate::emulation_core::mips::registers::GpRegisters; +use crate::emulation_core::{architectures::AvailableDatapaths, mips::datapath::Stage}; use serde::{Deserialize, Serialize}; /// Commands sent from the UI thread to the worker thread. @@ -25,5 +25,5 @@ pub enum MipsStateUpdate { UpdateState(DatapathState), UpdateRegisters(GpRegisters), UpdateMemory(Memory), - UpdateStage(Stage) + UpdateStage(Stage), } diff --git a/src/bin/main.rs b/src/bin/main.rs index 5579ab39a..db6fdea3c 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -3,31 +3,35 @@ use log::debug; // use monaco::sys::editor::IModelContentChangedEvent; use gloo_console::log; use js_sys::Object; +use log::Level; use monaco::{ api::TextModel, - sys::{ - editor::IMarkerData, - MarkerSeverity, - } + sys::{editor::IMarkerData, MarkerSeverity}, }; -use swim::{emulation_core::{architectures::AvailableDatapaths, mips::instruction::get_string_version}, ui::{footer::component::FooterTabState, hex_editor::component::{parse_hexdump, UpdatedLine}, swim_editor::component::EditorTabState}}; -use swim::parser::parser_structs_and_enums::ProgramInfo; use std::rc::Rc; use swim::agent::datapath_communicator::DatapathCommunicator; use swim::agent::datapath_reducer::DatapathReducer; use swim::agent::EmulationCoreAgent; use swim::emulation_core::mips::datapath::MipsDatapath; use swim::emulation_core::mips::datapath::Stage; -use swim::ui::footer::component::Footer; use swim::parser::parser_assembler_main::parser; +use swim::parser::parser_structs_and_enums::ProgramInfo; +use swim::ui::footer::component::Footer; use swim::ui::regview::component::Regview; use swim::ui::swim_editor::component::SwimEditor; +use swim::{ + emulation_core::{architectures::AvailableDatapaths, mips::instruction::get_string_version}, + ui::{ + footer::component::FooterTabState, + hex_editor::component::{parse_hexdump, UpdatedLine}, + swim_editor::component::EditorTabState, + }, +}; use wasm_bindgen::{JsCast, JsValue}; use wasm_bindgen_futures::spawn_local; use web_sys::HtmlInputElement; use yew::prelude::*; use yew::{html, Html, Properties}; -use log::Level; use yew_agent::Spawnable; use yew_hooks::prelude::*; @@ -70,7 +74,8 @@ fn app(props: &AppProps) -> Html { let program_info_ref = use_mut_ref(ProgramInfo::default); let binary_ref = use_mut_ref(Vec::::new); - let memory_text_model = use_state_eq(|| TextModel::create(&memory_text_output, Some("ini"), None).unwrap()); + let memory_text_model = + use_state_eq(|| TextModel::create(&memory_text_output, Some("ini"), None).unwrap()); // Show input let show_input = use_state_eq(|| bool::default()); @@ -176,7 +181,12 @@ fn app(props: &AppProps) -> Html { trigger.force_update(); }, - (text_model, editor_curr_line, memory_curr_instr, datapath_state), + ( + text_model, + editor_curr_line, + memory_curr_instr, + datapath_state, + ), ) }; @@ -250,7 +260,8 @@ fn app(props: &AppProps) -> Html { let programinfo = programinfo.borrow().clone(); let list_of_line_numbers = programinfo.address_to_line_number; let index = datapath_state.mips.registers.pc as usize / 4; - editor_curr_line.set(*list_of_line_numbers.get(index).unwrap_or(&0) as f64 + 1.0); + editor_curr_line + .set(*list_of_line_numbers.get(index).unwrap_or(&0) as f64 + 1.0); memory_curr_instr.set(datapath_state.mips.registers.pc); communicator.execute_stage(); } else { @@ -295,24 +306,20 @@ fn app(props: &AppProps) -> Html { match parse_hexdump(¤t_memory_text_model_value) { Ok(instructions) => { - let mut changed_lines: Vec = vec![]; for (i, data) in instructions.iter().enumerate() { let address = i as u64; // change string version based on architecture let string_version = match datapath_state.current_architecture { - AvailableDatapaths::MIPS => { - match get_string_version(*data) { - Ok(string) => string, - Err(string) => string, - } + AvailableDatapaths::MIPS => match get_string_version(*data) { + Ok(string) => string, + Err(string) => string, }, - AvailableDatapaths::RISCV => { - String::from("") - } + AvailableDatapaths::RISCV => String::from(""), }; - let curr_word = match datapath_state.mips.memory.load_word(address * 4) { + let curr_word = match datapath_state.mips.memory.load_word(address * 4) + { Ok(data) => data, Err(e) => { debug!("{:?}", e); @@ -333,7 +340,9 @@ fn app(props: &AppProps) -> Html { for line in changed_lines { // Check if we're updating or appending instruction if line.line_number < program_info.address_to_line_number.len() { - let updated_line = program_info.address_to_line_number[line.line_number] as f64 + 1.0; + let updated_line = + program_info.address_to_line_number[line.line_number] as f64 + + 1.0; let curr_model = text_model.as_ref(); // Get the current line's contents in the code editor @@ -347,8 +356,18 @@ fn app(props: &AppProps) -> Html { break; } } - let edit_range = monaco::sys::Range::new(updated_line, start_line_column, updated_line, end_line_column); - let before_cursor_state = monaco::sys::Selection::new(updated_line, start_line_column, updated_line,end_line_column); + let edit_range = monaco::sys::Range::new( + updated_line, + start_line_column, + updated_line, + end_line_column, + ); + let before_cursor_state = monaco::sys::Selection::new( + updated_line, + start_line_column, + updated_line, + end_line_column, + ); // Create the edit operation using the range and new text let edit_operations: monaco::sys::editor::IIdentifiedSingleEditOperation = Object::new().unchecked_into(); edit_operations.set_range(&edit_range); @@ -359,7 +378,11 @@ fn app(props: &AppProps) -> Html { let before_cursor_state_array = js_sys::Array::new(); before_cursor_state_array.push(&before_cursor_state); // Do the edit! - curr_model.push_edit_operations(&before_cursor_state_array, &edit_operations_array, None); + curr_model.push_edit_operations( + &before_cursor_state_array, + &edit_operations_array, + None, + ); } else if line.line_number == lines_beyond_counter { // Append instruction if !add_new_lines { @@ -376,7 +399,7 @@ fn app(props: &AppProps) -> Html { if add_new_lines { text_model.set_value(&curr_value); } - }, + } Err(err) => { debug!("Error updating memory: {}", err) } @@ -387,7 +410,6 @@ fn app(props: &AppProps) -> Html { *program_info_ref.borrow_mut() = program_info.clone(); trigger.force_update(); - }, datapath_state, ) @@ -411,7 +433,6 @@ fn app(props: &AppProps) -> Html { use_callback( move |_, (editor_curr_line, datapath_state)| { - // Set highlighted line to 0 editor_curr_line.set(0.0); memory_curr_instr.set(datapath_state.mips.registers.pc); diff --git a/src/emulation_core/mips/instruction.rs b/src/emulation_core/mips/instruction.rs index b07970297..dd30b027d 100644 --- a/src/emulation_core/mips/instruction.rs +++ b/src/emulation_core/mips/instruction.rs @@ -304,7 +304,6 @@ impl TryFrom for Instruction { } } - pub fn find_register_name(binary: u8) -> Option<&'static str> { for register in GP_REGISTERS { if register.binary == binary { @@ -322,13 +321,13 @@ pub fn get_string_version(value: u32) -> Result { let rs = ((value >> 21) & 0x1F) as u8; let rt = ((value >> 16) & 0x1F) as u8; let rd = ((value >> 11) & 0x1F) as u8; - let mut immediate = (value & 0xFFFF) as u16; + let mut immediate = (value & 0xFFFF) as u16; let mut imm_with_sign: i32 = 0; let mut imm_is_negative = false; if op == 0 && rs == 0 && rt == 0 && rd == 0 && immediate == 0 { - return Err(String::from("empty instruction")) + return Err(String::from("empty instruction")); } if value & 0xF000 > 0 { @@ -383,61 +382,61 @@ pub fn get_string_version(value: u32) -> Result { FUNCT_ADD => { string_version = format!("{} {} {} {}", "add", str_rd, str_rs, str_rt); Ok(string_version) - }, + } FUNCT_ADDU => { string_version = format!("{} {} {} {}", "addu", str_rd, str_rs, str_rt); Ok(string_version) - }, + } FUNCT_DADD => { string_version = format!("{} {} {} {}", "dadd", str_rd, str_rs, str_rt); Ok(string_version) - }, + } FUNCT_DADDU => { string_version = format!("{} {} {} {}", "daddu", str_rd, str_rs, str_rt); Ok(string_version) - }, + } FUNCT_SUB => { string_version = format!("{} {} {} {}", "sub", str_rd, str_rs, str_rt); Ok(string_version) - }, + } FUNCT_DSUB => { string_version = format!("{} {} {} {}", "dsub", str_rd, str_rs, str_rt); Ok(string_version) - }, + } FUNCT_DSUBU => { string_version = format!("{} {} {} {}", "dsubu", str_rd, str_rs, str_rt); Ok(string_version) - }, + } FUNCT_AND => { string_version = format!("{} {} {} {}", "and", str_rd, str_rs, str_rt); Ok(string_version) - }, + } FUNCT_OR => { string_version = format!("{} {} {} {}", "or", str_rd, str_rs, str_rt); Ok(string_version) - }, + } FUNCT_SLL => { string_version = format!("{} {} {} {}", "sll", str_rd, str_rs, str_shamt); Ok(string_version) - }, + } FUNCT_SLT => { string_version = format!("{} {} {} {}", "slt", str_rd, str_rs, str_rt); Ok(string_version) - }, + } FUNCT_SLTU => { string_version = format!("{} {} {} {}", "sltu", str_rd, str_rs, str_shamt); Ok(string_version) - }, + } FUNCT_SOP32 => { string_version = format!("{} {} {} {}", "or", str_rd, str_rs, str_rt); Ok(string_version) - }, + } FUNCT_SOP36 => match shamt as u8 { // ENC_DIV == ENC_DDIV ENC_DIV => { string_version = format!("{} {} {}", "div", str_rs, str_rt); Ok(string_version) - }, + } _ => { string_version = String::from("###"); Ok(string_version) @@ -448,7 +447,7 @@ pub fn get_string_version(value: u32) -> Result { ENC_DIVU => { string_version = format!("{} {} {}", "divu", str_rs, str_rt); Ok(string_version) - }, + } _ => { string_version = String::from("###"); Ok(string_version) @@ -459,7 +458,7 @@ pub fn get_string_version(value: u32) -> Result { ENC_MUL => { string_version = format!("{} {} {} {}", "mul", str_rd, str_rs, str_rt); Ok(string_version) - }, + } _ => { string_version = String::from("###"); Ok(string_version) @@ -470,7 +469,7 @@ pub fn get_string_version(value: u32) -> Result { ENC_MULU => { string_version = format!("{} {} {} {}", "mulu", str_rd, str_rs, str_rt); Ok(string_version) - }, + } _ => { string_version = String::from("###"); Ok(string_version) @@ -514,96 +513,92 @@ pub fn get_string_version(value: u32) -> Result { FUNCTION_ADD => { let string_version = format!("add.s {} {} {}", str_fd, str_fs, str_ft); Ok(string_version) - }, + } FUNCTION_SUB => { let string_version = format!("sub.s {} {} {}", str_fd, str_fs, str_ft); Ok(string_version) - }, + } FUNCTION_MUL => { let string_version = format!("mul.s {} {} {}", str_fd, str_fs, str_ft); Ok(string_version) - }, + } FUNCTION_DIV => { let string_version = format!("add.s {} {} {}", str_fd, str_fs, str_ft); Ok(string_version) - }, + } // Comparison instructions: // c.eq.fmt, c.lt.fmt, c.le.fmt, c.ngt.fmt, c.nge.fmt FUNCTION_C_EQ => { let string_version = format!("c.eq.s {} {}", str_fs, str_ft); Ok(string_version) - }, + } FUNCTION_C_LT => { let string_version = format!("c.lt.s {} {}", str_fs, str_ft); Ok(string_version) - }, + } FUNCTION_C_NGE => { let string_version = format!("c.nge.s {} {}", str_fs, str_ft); Ok(string_version) - }, + } FUNCTION_C_LE => { let string_version = format!("c.le.s {} {}", str_fs, str_ft); Ok(string_version) - }, + } FUNCTION_C_NGT => { let string_version = format!("c.ngt.s {} {}", str_fs, str_ft); Ok(string_version) - }, - _ => { - Err(format!( - "function `{function}` not supported for opcode {op}" - )) - }, + } + _ => Err(format!( + "function `{function}` not supported for opcode {op}" + )), } - }, + } FMT_DOUBLE => { match function { // add.fmt, sub.fmt, mul.fmt, div.fmt FUNCTION_ADD => { let string_version = format!("add.d {} {} {}", str_fd, str_fs, str_ft); Ok(string_version) - }, + } FUNCTION_SUB => { let string_version = format!("sub.d {} {} {}", str_fd, str_fs, str_ft); Ok(string_version) - }, + } FUNCTION_MUL => { let string_version = format!("mul.d {} {} {}", str_fd, str_fs, str_ft); Ok(string_version) - }, + } FUNCTION_DIV => { let string_version = format!("add.d {} {} {}", str_fd, str_fs, str_ft); Ok(string_version) - }, + } // Comparison instructions: // c.eq.fmt, c.lt.fmt, c.le.fmt, c.ngt.fmt, c.nge.fmt FUNCTION_C_EQ => { let string_version = format!("c.eq.d {} {}", str_fs, str_ft); Ok(string_version) - }, + } FUNCTION_C_LT => { let string_version = format!("c.lt.d {} {}", str_fs, str_ft); Ok(string_version) - }, + } FUNCTION_C_NGE => { let string_version = format!("c.nge.d {} {}", str_fs, str_ft); Ok(string_version) - }, + } FUNCTION_C_LE => { let string_version = format!("c.le.d {} {}", str_fs, str_ft); Ok(string_version) - }, + } FUNCTION_C_NGT => { let string_version = format!("c.ngt.d {} {}", str_fs, str_ft); Ok(string_version) - }, - _ => { - Err(format!( - "function `{function}` not supported for opcode {op}" - )) - }, + } + _ => Err(format!( + "function `{function}` not supported for opcode {op}" + )), } - }, + } // Move word to coprocessor 1 (mtc1) // Move doubleword to coprocessor 1 (dmtc1) @@ -612,26 +607,26 @@ pub fn get_string_version(value: u32) -> Result { SUB_MT => { let string_version = format!("mtc1 {} {}", str_ft, str_fs); Ok(string_version) - }, + } SUB_DMT => { let string_version = format!("dmtc1 {} {}", str_ft, str_fs); Ok(string_version) - }, + } SUB_MF => { let string_version = format!("mfc1 {} {}", str_ft, str_fs); Ok(string_version) - }, + } SUB_DMF => { let string_version = format!("dfmc1 {} {}", str_ft, str_fs); Ok(string_version) - }, + } // Branch on coprocessor 1 true (bc1t) // Branch on coprocessor 1 false (bc1f) SUB_BC => { string_version.push_str("bc1t"); Ok(string_version) - }, + } _ => Err(format!("sub code `{sub}` not supported for opcode {op}")), } @@ -641,67 +636,67 @@ pub fn get_string_version(value: u32) -> Result { OPCODE_ADDI => { let string_version = format!("addi {} {} {}", str_rt, str_rs, str_immediate); Ok(string_version) - }, + } OPCODE_ADDIU => { let string_version = format!("addiu {} {} {}", str_rt, str_rs, str_immediate); Ok(string_version) - }, + } OPCODE_DADDI => { let string_version = format!("daddi {} {} {}", str_rt, str_rs, str_immediate); Ok(string_version) - }, + } OPCODE_DADDIU => { let string_version = format!("daddi {} {} {}", str_rt, str_rs, str_immediate); Ok(string_version) - }, + } OPCODE_LW => { let string_version = format!("lw {}, {} ({})", str_rt, str_immediate, str_rs); Ok(string_version) - }, + } OPCODE_SW => { let string_version = format!("sw {}, {} ({})", str_rt, str_immediate, str_rs); Ok(string_version) - }, + } OPCODE_LUI => { let string_version = format!("lui {} , {}", str_rt, str_immediate); Ok(string_version) - }, + } OPCODE_ORI => { let string_version = format!("ori {} {} {}", str_rt, str_rs, str_immediate); Ok(string_version) - }, + } OPCODE_ANDI => { let string_version = format!("andi {} {} {}", str_rt, str_rs, str_immediate); Ok(string_version) - }, + } OPCODE_REGIMM => { let string_version = format!(" dahi {} {}", str_rs, str_immediate); Ok(string_version) - }, + } OPCODE_BEQ => { let string_version = format!("beq {} {} {}", str_rs, str_rt, str_immediate); Ok(string_version) - }, + } OPCODE_BNE => { let string_version = format!("beq {} {} {}", str_rs, str_rt, str_immediate); Ok(string_version) - }, + } // Store/load word to Coprocessor 1 OPCODE_SWC1 => { let string_version = format!("swc1 {} {} {}", str_ft, str_offset, str_base); Ok(string_version) - }, + } OPCODE_LWC1 => { let string_version = format!("lwc1 {} {} {}", str_ft, str_offset, str_base); Ok(string_version) - }, + } OPCODE_J => { let addr = value & 0x03ffffff; let str_addr = format!("{:b}", addr); let str_addr = str_addr.as_str(); let string_version = format!("j {}", str_addr); Ok(string_version) - }, + } OPCODE_JAL => { let addr = value & 0x03ffffff; let str_addr = format!("{:b}", addr); @@ -709,7 +704,7 @@ pub fn get_string_version(value: u32) -> Result { let string_version = format!("jal {}", str_addr); Ok(string_version) - }, + } _ => Err(format!("opcode `{op}` not supported")), } diff --git a/src/emulation_core/mips/memory.rs b/src/emulation_core/mips/memory.rs index 6f3be6ab8..fc8d8a49a 100644 --- a/src/emulation_core/mips/memory.rs +++ b/src/emulation_core/mips/memory.rs @@ -179,7 +179,7 @@ impl<'a> MemoryIter<'a> { pub fn new(memory: &'a Memory) -> MemoryIter<'a> { MemoryIter { memory, - current_address: 0 + current_address: 0, } } } @@ -192,9 +192,7 @@ impl<'a> Iterator for MemoryIter<'a> { if self.current_address + 16 <= self.memory.memory.len() { let address = self.current_address; let words = (0..4) - .map(|i| self.memory - .load_word(address as u64 + (i * 4)) - .unwrap()) + .map(|i| self.memory.load_word(address as u64 + (i * 4)).unwrap()) .collect(); self.current_address += 16; @@ -203,4 +201,4 @@ impl<'a> Iterator for MemoryIter<'a> { None } } -} \ No newline at end of file +} diff --git a/src/emulation_core/mips/registers.rs b/src/emulation_core/mips/registers.rs index 341352876..a67a50664 100644 --- a/src/emulation_core/mips/registers.rs +++ b/src/emulation_core/mips/registers.rs @@ -69,11 +69,11 @@ impl GpRegisterType { GpRegisterType::Pc => { // Check if PC is more than the number of instructions or not word-aligned value <= pc_limit as u64 && value % 4 == 0 - }, + } GpRegisterType::Sp => { // Check if SP is more than memory capacity or not word-aligned value <= CAPACITY_BYTES as u64 && value % 4 == 0 - }, + } _ => true, // Other registers are always considered valid } } diff --git a/src/parser/parser_assembler_main.rs b/src/parser/parser_assembler_main.rs index 922823859..1b8478864 100644 --- a/src/parser/parser_assembler_main.rs +++ b/src/parser/parser_assembler_main.rs @@ -50,7 +50,8 @@ pub fn parser(file_string: String) -> (ProgramInfo, Vec) { &mut program_info.monaco_line_info, ); - let (binary, data_starting_point) = create_binary_vec(program_info.instructions.clone(), vec_of_data); + let (binary, data_starting_point) = + create_binary_vec(program_info.instructions.clone(), vec_of_data); for entry in &program_info.monaco_line_info { program_info @@ -1532,7 +1533,10 @@ pub fn determine_pc_starting_point(labels: HashMap) -> usize { } ///Creates a vector of u32 from the data found in the parser / assembler to put into memory. -pub fn create_binary_vec(instructions: Vec, mut vec_of_data: Vec) -> (Vec, usize) { +pub fn create_binary_vec( + instructions: Vec, + mut vec_of_data: Vec, +) -> (Vec, usize) { //push all instructions let mut binary: Vec = Vec::new(); for instruction in instructions { diff --git a/src/parser/parser_structs_and_enums.rs b/src/parser/parser_structs_and_enums.rs index dbe3797c2..714129844 100644 --- a/src/parser/parser_structs_and_enums.rs +++ b/src/parser/parser_structs_and_enums.rs @@ -150,10 +150,7 @@ impl Data { ///Takes the operator, operands, and label(optional) associated with an instruction and recreates the string version pub fn recreate_string(&self) -> String { let mut recreated_string = "".to_string(); - recreated_string.push_str(&format!( - "{}: ", - self.label.clone().token_name - )); + recreated_string.push_str(&format!("{}: ", self.label.clone().token_name)); recreated_string.push_str(&self.data_type.token_name.to_string()); for token in &self.data_entries { diff --git a/src/tests/emulation_core.rs b/src/tests/emulation_core.rs index e37c6290d..3378c0993 100644 --- a/src/tests/emulation_core.rs +++ b/src/tests/emulation_core.rs @@ -1,4 +1,4 @@ +pub mod instruction; pub mod memory; pub mod mips; pub mod registers; -pub mod instruction; diff --git a/src/tests/emulation_core/instruction.rs b/src/tests/emulation_core/instruction.rs index 219241042..fb8e2a0f7 100644 --- a/src/tests/emulation_core/instruction.rs +++ b/src/tests/emulation_core/instruction.rs @@ -7,7 +7,7 @@ fn get_string_version_from_binary() { assert!(match get_string_version(instruction) { Ok(string) => { string.contains("ori $t6 $zero 500") - }, + } _ => false, }); } @@ -18,18 +18,17 @@ fn get_string_version_from_hex() { assert!(match get_string_version(instruction) { Ok(string) => { string.contains("ori $t6 $zero 500") - }, + } _ => false, }); } #[test] fn err_on_empty_instruction() { - let instruction: u32 = 0b00000000000000000000000000000000; assert!(match get_string_version(instruction) { Err(e) => e.contains("empty instruction"), _ => false, }); -} \ No newline at end of file +} diff --git a/src/ui.rs b/src/ui.rs index 5decab0cf..15b4fdff2 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,10 +1,9 @@ //! User interface using Yew, organized into components. - pub mod assembled_view; +pub mod console; pub mod footer; pub mod hex_editor; pub mod regview; pub mod swim_editor; pub mod visual_datapath; -pub mod console; \ No newline at end of file diff --git a/src/ui/assembled_view/component.rs b/src/ui/assembled_view/component.rs index bef4bfc46..5269371f2 100644 --- a/src/ui/assembled_view/component.rs +++ b/src/ui/assembled_view/component.rs @@ -2,15 +2,14 @@ use std::cell::RefCell; use std::rc::Rc; // use monaco::api::TextModel; -use web_sys::{HtmlElement, HtmlInputElement}; -use yew::{Properties, Html}; -use yew::prelude::*; -use wasm_bindgen::JsCast; -use log::debug; use crate::parser::parser_structs_and_enums::ProgramInfo; use crate::ui::footer::component::FooterTabState; use crate::ui::swim_editor::component::EditorTabState; - +use log::debug; +use wasm_bindgen::JsCast; +use web_sys::{HtmlElement, HtmlInputElement}; +use yew::prelude::*; +use yew::{Html, Properties}; #[derive(PartialEq, Properties)] pub struct TextSegmentProps { @@ -20,7 +19,7 @@ pub struct TextSegmentProps { pub editor_curr_line: UseStateHandle, pub pc: u64, pub editor_active_tab: UseStateHandle, - pub console_active_tab: UseStateHandle + pub console_active_tab: UseStateHandle, } #[derive(PartialEq, Properties)] pub struct DataSegmentProps { @@ -31,7 +30,7 @@ pub struct DataSegmentProps { pub editor_curr_line: UseStateHandle, pub editor_active_tab: UseStateHandle, pub console_active_tab: UseStateHandle, - pub pc_limit: usize + pub pc_limit: usize, } #[function_component] @@ -62,29 +61,34 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html { if input.checked() { debug!("Breakpoint set at {:08x}", address); } - }); // Go to the memory address in hex editor let on_address_click = { let memory_curr_instr = memory_curr_instr.clone(); let console_active_tab = console_active_tab.clone(); - use_callback(move |args: (MouseEvent, usize), memory_curr_instr| { - let (_e, address) = args; - memory_curr_instr.set(address as u64); - console_active_tab.set(FooterTabState::HexEditor); - }, memory_curr_instr) + use_callback( + move |args: (MouseEvent, usize), memory_curr_instr| { + let (_e, address) = args; + memory_curr_instr.set(address as u64); + console_active_tab.set(FooterTabState::HexEditor); + }, + memory_curr_instr, + ) }; // Go to the line in code editor let on_assembled_click = { let editor_curr_line = editor_curr_line.clone(); let editor_active_tab = editor_active_tab.clone(); - use_callback(move |args: (MouseEvent, usize), _| { - let (_e, line_number) = args; - editor_curr_line.set(line_number as f64 + 1.0); - editor_active_tab.set(EditorTabState::Editor); - }, ()) + use_callback( + move |args: (MouseEvent, usize), _| { + let (_e, line_number) = args; + editor_curr_line.set(line_number as f64 + 1.0); + editor_active_tab.set(EditorTabState::Editor); + }, + (), + ) }; let mut address = -4; @@ -182,22 +186,28 @@ pub fn DataSegment(props: &DataSegmentProps) -> Html { let on_address_click = { let memory_curr_instr = memory_curr_instr.clone(); let console_active_tab = console_active_tab.clone(); - use_callback(move |args: (MouseEvent, usize), memory_curr_instr| { - let (_e, address) = args; - memory_curr_instr.set(address as u64); - console_active_tab.set(FooterTabState::HexEditor); - }, memory_curr_instr) + use_callback( + move |args: (MouseEvent, usize), memory_curr_instr| { + let (_e, address) = args; + memory_curr_instr.set(address as u64); + console_active_tab.set(FooterTabState::HexEditor); + }, + memory_curr_instr, + ) }; // Go to the line in code editor let on_assembled_click = { let editor_curr_line = editor_curr_line.clone(); let editor_active_tab = editor_active_tab.clone(); - use_callback(move |args: (MouseEvent, usize), _| { - let (_e, line_number) = args; - editor_curr_line.set(line_number as f64); - editor_active_tab.set(EditorTabState::Editor); - }, ()) + use_callback( + move |args: (MouseEvent, usize), _| { + let (_e, line_number) = args; + editor_curr_line.set(line_number as f64); + editor_active_tab.set(EditorTabState::Editor); + }, + (), + ) }; html! { @@ -244,4 +254,4 @@ pub fn DataSegment(props: &DataSegmentProps) -> Html { }
- {format!("0x{:08x}", binary[data.line_number])} + {format!("0x{:08x}", binary[data_binary_index])} {recreated_string} - {format!("{}: {:?}", data.line_number, lines_content.get(data.line_number).unwrap_or(&String::from("")))} + {format!("{}: {:?}", data.line_number + 1, lines_content.get(data.line_number).unwrap_or(&String::from("")))}
{get_gpr_name(register)}{register.get_gpr_name()} (); + let val: u64 = match input.value().parse() { + Ok(value) => { + input.set_class_name("valid"); + value + }, + Err(_err) => { + input.set_class_name("invalid"); + return + } + }; + if register.is_valid_register_value(val, pc_limit) { + communicator.set_register(register.to_string(), val); + input.set_class_name("valid"); + } else { + input.set_class_name("invalid"); + } + }} value={(data as i64).to_string()}/>
{get_gpr_name(register)}{register.get_gpr_name()} {format!("{data:#04x?}").to_string()}
{get_gpr_name(register)}{register.get_gpr_name()} {format!("{data:#b}").to_string()}
diff --git a/src/ui/console/component.rs b/src/ui/console/component.rs index ba5c087ac..3b1acb09d 100644 --- a/src/ui/console/component.rs +++ b/src/ui/console/component.rs @@ -7,23 +7,28 @@ use wasm_bindgen::JsCast; pub struct Consoleprops { pub communicator: &'static DatapathCommunicator, pub parsermsg: String, + pub command: UseStateHandle, pub show_input: UseStateHandle } #[function_component(Console)] pub fn console(props: &Consoleprops) -> Html { let show_input = props.show_input.clone(); + let command = props.command.clone(); let input_value = use_state_eq(String::new); let error_msg = use_state_eq(|| ""); + let answered = use_state_eq(|| false); let on_keyup = { let error_msg = error_msg.clone(); let input_value = input_value.clone(); - use_callback(move |event: KeyboardEvent, (input_value, error_msg)| { + let answered = answered.clone(); + use_callback(move |event: KeyboardEvent, (input_value, error_msg, answered)| { // let communicator = props.communicator; let key_code = event.key_code(); let error_msg = error_msg.clone(); let input_value = input_value.clone(); + let answered = answered.clone(); // If Enter was pressed parse and send input to emulator core if key_code == 13 { let input_value = &*input_value; @@ -38,18 +43,25 @@ pub fn console(props: &Consoleprops) -> Html { return } }; + answered.set(true); + log::debug!("{}", val); // Send Input command } - }, (input_value, error_msg)) + }, (input_value, error_msg, answered)) }; - let on_input = Callback::from(move |event: InputEvent| { - // let communicator = props.communicator; - let target = event.target(); - let input = target.unwrap().unchecked_into::(); + let on_input = { + let input_value = input_value.clone(); + let answered = answered.clone(); + use_callback(move |event: InputEvent, (input_value, answered)| { + // let communicator = props.communicator; + let target = event.target(); + let input = target.unwrap().unchecked_into::(); - input_value.set(input.value()); - }); + input_value.set(input.value()); + answered.set(false); + }, (input_value, answered)) + }; html! {
@@ -57,11 +69,18 @@ pub fn console(props: &Consoleprops) -> Html {
{*error_msg}
+ if *answered { +
+ // { previous_input.iter().collect::() } + {"You answered: "} { (*input_value).clone() } +
+ } if *show_input {
+
{ (*command).clone() } { ": " }
} diff --git a/src/ui/footer/component.rs b/src/ui/footer/component.rs index e693aaf4c..604853ea1 100644 --- a/src/ui/footer/component.rs +++ b/src/ui/footer/component.rs @@ -15,6 +15,7 @@ pub struct Footerprops { pub datapath: MipsDatapath, pub parsermsg: String, pub show_input: UseStateHandle, + pub command: UseStateHandle, pub memory_text_model: UseStateHandle, pub memory_curr_instr: UseStateHandle, pub active_tab: UseStateHandle, @@ -88,7 +89,7 @@ pub fn footer(props: &Footerprops) -> Html { // Console buttons if **active_tab == FooterTabState::Console {
- +
} else if **active_tab == FooterTabState::Datapath {
diff --git a/src/ui/regview/component.rs b/src/ui/regview/component.rs index c5bff9728..01f644c90 100644 --- a/src/ui/regview/component.rs +++ b/src/ui/regview/component.rs @@ -70,92 +70,283 @@ pub fn generate_gpr_rows(props: &Regviewprops) -> Html { }) .collect::() } -pub fn generate_gpr_rows_hex(gp: GpRegisters) -> Html { - gp.into_iter() +pub fn generate_gpr_rows_hex(props: &Regviewprops) -> Html { + let communicator = props.communicator; + let pc_limit = props.pc_limit; + + props.gp.into_iter() .map(|(register, data)| { html! {
{register.get_gpr_name()}{format!("{data:#04x?}").to_string()} + (); + let input_string = input.value(); + let val = match u64::from_str_radix(&input_string[2..], 16) { + Ok(value) => { + input.set_class_name("valid"); + value + }, + Err(_err) => { + input.set_class_name("invalid"); + return + } + }; + if register.is_valid_register_value(val, pc_limit) { + communicator.set_register(register.to_string(), val); + input.set_class_name("valid"); + } else { + input.set_class_name("invalid"); + } + }} + value={format!("{data:#04x?}").to_string()}/> +
{register.get_gpr_name()}{format!("{data:#b}").to_string()} + (); + let input_string = input.value(); + let val = match u64::from_str_radix(&input_string[2..], 2) { + Ok(value) => { + input.set_class_name("valid"); + value + }, + Err(_err) => { + input.set_class_name("invalid"); + return + } + }; + if register.is_valid_register_value(val, pc_limit) { + communicator.set_register(register.to_string(), val); + input.set_class_name("valid"); + } else { + input.set_class_name("invalid"); + } + }} + value={format!("{data:#b}").to_string()}/> +
{format!("f{register}")}{(*data as i64).to_string()} + (); + let input_string = input.value(); + let val = match u64::from_str_radix(&input_string, 10) { + Ok(value) => { + input.set_class_name("valid"); + value + }, + Err(_err) => { + input.set_class_name("invalid"); + return + } + }; + log::debug!("{}", val as i64); + // communicator.set_register(register.to_string(), val); + // if register.is_valid_register_value(val, pc_limit) { + // input.set_class_name("valid"); + // } else { + // input.set_class_name("invalid"); + // } + }} + value={(*data as i64).to_string()}/> +
{format!("f{register}")}{format!("{data:#04x?}").to_string()} + (); + let input_string = input.value(); + let val = match u64::from_str_radix(&input_string[2..], 16) { + Ok(value) => { + input.set_class_name("valid"); + value + }, + Err(_err) => { + input.set_class_name("invalid"); + return + } + }; + log::debug!("{val:#04x?}"); + // communicator.set_register(register.to_string(), val); + // if register.is_valid_register_value(val, pc_limit) { + // input.set_class_name("valid"); + // } else { + // input.set_class_name("invalid"); + // } + }} + value={format!("{data:#04x?}").to_string()}/> +
{format!("f{register}")}{format!("{data:#b}").to_string()} + (); + let input_string = input.value(); + let val = match u64::from_str_radix(&input_string[2..], 2) { + Ok(value) => { + input.set_class_name("valid"); + value + }, + Err(_err) => { + input.set_class_name("invalid"); + return + } + }; + log::debug!("{val:#b}"); + // communicator.set_register(register.to_string(), val); + // if register.is_valid_register_value(val, pc_limit) { + // input.set_class_name("valid"); + // } else { + // input.set_class_name("invalid"); + // } + }} + value={format!("{data:#b}").to_string()}/> +
{format!("f{register}")}{format!("{:e}",f32::from_bits((*data).try_into().unwrap())).to_string()} + (); + let input_string = input.value(); + let value = match input_string.parse::() { + Ok(value) => { + input.set_class_name("valid"); + value + }, + Err(_err) => { + input.set_class_name("invalid"); + return + } + }; + log::debug!("{:e}", value); + // communicator.set_register(register.to_string(), val); + // if register.is_valid_register_value(val, pc_limit) { + // input.set_class_name("valid"); + // } else { + // input.set_class_name("invalid"); + // } + }} + value={format!("{:e}",f32::from_bits((*data).try_into().unwrap())).to_string()}/> +
{format!("f{register}")}{format!("{:e}", f64::from_bits(*data)).to_string()} + (); + let input_string = input.value(); + let value = match input_string.parse::() { + Ok(value) => { + input.set_class_name("valid"); + value + }, + Err(_err) => { + input.set_class_name("invalid"); + return + } + }; + log::debug!("{:e}", value); + // communicator.set_register(register.to_string(), val); + // if register.is_valid_register_value(val, pc_limit) { + // input.set_class_name("valid"); + // } else { + // input.set_class_name("invalid"); + // } + }} + value={format!("{:e}", f64::from_bits(*data)).to_string()}/> +
} -} \ No newline at end of file +} diff --git a/src/ui/assembled_view/mod.rs b/src/ui/assembled_view/mod.rs index 519c53d92..9cea807e4 100644 --- a/src/ui/assembled_view/mod.rs +++ b/src/ui/assembled_view/mod.rs @@ -1 +1 @@ -pub mod component; \ No newline at end of file +pub mod component; diff --git a/src/ui/console/component.rs b/src/ui/console/component.rs index 3b1acb09d..3f1100cc2 100644 --- a/src/ui/console/component.rs +++ b/src/ui/console/component.rs @@ -1,14 +1,14 @@ use crate::agent::datapath_communicator::DatapathCommunicator; -use web_sys::{KeyboardEvent, InputEvent, HtmlInputElement}; -use yew::prelude::*; use wasm_bindgen::JsCast; +use web_sys::{HtmlInputElement, InputEvent, KeyboardEvent}; +use yew::prelude::*; #[derive(PartialEq, Properties)] pub struct Consoleprops { pub communicator: &'static DatapathCommunicator, pub parsermsg: String, pub command: UseStateHandle, - pub show_input: UseStateHandle + pub show_input: UseStateHandle, } #[function_component(Console)] @@ -23,44 +23,48 @@ pub fn console(props: &Consoleprops) -> Html { let error_msg = error_msg.clone(); let input_value = input_value.clone(); let answered = answered.clone(); - use_callback(move |event: KeyboardEvent, (input_value, error_msg, answered)| { - // let communicator = props.communicator; - let key_code = event.key_code(); - let error_msg = error_msg.clone(); - let input_value = input_value.clone(); - let answered = answered.clone(); - // If Enter was pressed parse and send input to emulator core - if key_code == 13 { - let input_value = &*input_value; - log::debug!("Input: {}", (input_value)); - // Parse based on syscall type (int, float, string) - let val: String = match input_value.parse() { - Ok(value) => { - value - }, - Err(_err) => { - error_msg.set("Invalid input"); - return - } - }; - answered.set(true); - log::debug!("{}", val); - // Send Input command - } - }, (input_value, error_msg, answered)) + use_callback( + move |event: KeyboardEvent, (input_value, error_msg, answered)| { + // let communicator = props.communicator; + let key_code = event.key_code(); + let error_msg = error_msg.clone(); + let input_value = input_value.clone(); + let answered = answered.clone(); + // If Enter was pressed parse and send input to emulator core + if key_code == 13 { + let input_value = &*input_value; + log::debug!("Input: {}", (input_value)); + // Parse based on syscall type (int, float, string) + let val: String = match input_value.parse() { + Ok(value) => value, + Err(_err) => { + error_msg.set("Invalid input"); + return; + } + }; + answered.set(true); + log::debug!("{}", val); + // Send Input command + } + }, + (input_value, error_msg, answered), + ) }; let on_input = { let input_value = input_value.clone(); let answered = answered.clone(); - use_callback(move |event: InputEvent, (input_value, answered)| { - // let communicator = props.communicator; - let target = event.target(); - let input = target.unwrap().unchecked_into::(); + use_callback( + move |event: InputEvent, (input_value, answered)| { + // let communicator = props.communicator; + let target = event.target(); + let input = target.unwrap().unchecked_into::(); - input_value.set(input.value()); - answered.set(false); - }, (input_value, answered)) + input_value.set(input.value()); + answered.set(false); + }, + (input_value, answered), + ) }; html! { diff --git a/src/ui/console/mod.rs b/src/ui/console/mod.rs index 519c53d92..9cea807e4 100644 --- a/src/ui/console/mod.rs +++ b/src/ui/console/mod.rs @@ -1 +1 @@ -pub mod component; \ No newline at end of file +pub mod component; diff --git a/src/ui/footer/component.rs b/src/ui/footer/component.rs index 604853ea1..11da3beb7 100644 --- a/src/ui/footer/component.rs +++ b/src/ui/footer/component.rs @@ -1,13 +1,13 @@ +use crate::agent::datapath_communicator::DatapathCommunicator; +use crate::emulation_core::mips::datapath::MipsDatapath; +use crate::ui::console::component::Console; +use crate::ui::hex_editor::component::HexEditor; +use crate::ui::visual_datapath::{DatapathSize, VisualDatapath}; +use monaco::api::TextModel; use wasm_bindgen::JsCast; use web_sys::HtmlElement; use yew::prelude::*; use yew_hooks::prelude::*; -use monaco::api::TextModel; -use crate::agent::datapath_communicator::DatapathCommunicator; -use crate::emulation_core::mips::datapath::MipsDatapath; -use crate::ui::visual_datapath::{DatapathSize, VisualDatapath}; -use crate::ui::hex_editor::component::HexEditor; -use crate::ui::console::component::Console; #[derive(PartialEq, Properties)] pub struct Footerprops { @@ -26,7 +26,7 @@ pub enum FooterTabState { #[default] Console, Datapath, - HexEditor + HexEditor, } #[function_component(Footer)] diff --git a/src/ui/hex_editor/component.rs b/src/ui/hex_editor/component.rs index 0bbc72f26..ec8e7f7b7 100644 --- a/src/ui/hex_editor/component.rs +++ b/src/ui/hex_editor/component.rs @@ -3,8 +3,8 @@ use std::ops::Deref; use std::rc::Rc; use wasm_bindgen::JsCast; use wasm_bindgen::{closure::Closure, JsValue}; -use yew::{function_component, html, use_callback, Html, Properties, UseStateHandle}; use yew::prelude::*; +use yew::{function_component, html, use_callback, Html, Properties, UseStateHandle}; use monaco::{ api::TextModel, @@ -36,14 +36,11 @@ pub struct HexEditorProps { #[derive(Clone, Debug, PartialEq)] pub struct UpdatedLine { pub text: String, - pub line_number: usize + pub line_number: usize, } impl UpdatedLine { pub fn new(text: String, line_number: usize) -> Self { - UpdatedLine { - text, - line_number - } + UpdatedLine { text, line_number } } } @@ -69,7 +66,8 @@ pub fn hex_editor(props: &HexEditorProps) -> Html { let start_line_number = selection.selection_start_line_number(); let start_column = selection.start_column(); let end_column = selection.end_column(); - let (start_column, end_column) = calculate_ascii_columns(start_column as usize, end_column as usize); + let (start_column, end_column) = + calculate_ascii_columns(start_column as usize, end_column as usize); let range = Range::new( start_line_number, start_column, @@ -78,14 +76,13 @@ pub fn hex_editor(props: &HexEditorProps) -> Html { ); // Style the highlighting - let highlight_decoration: IModelDeltaDecoration = js_sys::Object::new().unchecked_into(); + let highlight_decoration: IModelDeltaDecoration = + js_sys::Object::new().unchecked_into(); let highlight_options: IModelDecorationOptions = js_sys::Object::new().unchecked_into(); highlight_options.set_inline_class_name("highlightHex".into()); highlight_options.set_is_whole_line(false.into()); highlight_decoration.set_options(&highlight_options); - let range_js = range - .dyn_into::() - .expect("Range is not found."); + let range_js = range.dyn_into::().expect("Range is not found."); highlight_decoration.set_range(&monaco::sys::IRange::from(range_js)); let decoration_js = highlight_decoration .dyn_into::() @@ -103,7 +100,8 @@ pub fn hex_editor(props: &HexEditorProps) -> Html { let existing_decorations = text_model.get_all_decorations(None, None); text_model.delta_decorations(&decorations, ¬_highlighted, None); // Set new decorations and save their IDs - *decorations = text_model.delta_decorations(&existing_decorations, &executed_line, None); + *decorations = + text_model.delta_decorations(&existing_decorations, &executed_line, None); }, ) as Box); @@ -126,7 +124,12 @@ pub fn hex_editor(props: &HexEditorProps) -> Html { // Calculates which columns in the ASCII portion belong to the given hex portion fn calculate_ascii_columns(hex_start_column: usize, hex_end_column: usize) -> (f64, f64) { - if hex_start_column > 8 && hex_start_column < 46 && hex_end_column > 8 && hex_end_column < 46 && hex_end_column > hex_start_column { + if hex_start_column > 8 + && hex_start_column < 46 + && hex_end_column > 8 + && hex_end_column < 46 + && hex_end_column > hex_start_column + { let ascii_length = (hex_end_column - hex_start_column) / 2; let start_column = 46 + ((hex_start_column - 8) / 2) - 1; let end_column = start_column + ascii_length; @@ -229,4 +232,4 @@ pub fn parse_hexdump(input: &str) -> Result, String> { } } Ok(words) -} \ No newline at end of file +} diff --git a/src/ui/regview/component.rs b/src/ui/regview/component.rs index 01f644c90..32a1cd238 100644 --- a/src/ui/regview/component.rs +++ b/src/ui/regview/component.rs @@ -1,7 +1,7 @@ use crate::agent::datapath_communicator::DatapathCommunicator; use crate::emulation_core::mips::registers::GpRegisters; use wasm_bindgen::JsCast; -use web_sys::{InputEvent, HtmlInputElement}; +use web_sys::{HtmlInputElement, InputEvent}; use yew::prelude::*; use yew::{html, Html}; @@ -10,7 +10,7 @@ pub struct Regviewprops { pub gp: GpRegisters, pub fp: [u64; 32], pub pc_limit: usize, - pub communicator: &'static DatapathCommunicator + pub communicator: &'static DatapathCommunicator, } #[derive(PartialEq, Properties)] pub struct Viewswitch { @@ -36,7 +36,9 @@ pub fn generate_gpr_rows(props: &Regviewprops) -> Html { let communicator = props.communicator; let pc_limit = props.pc_limit; - props.gp.into_iter() + props + .gp + .into_iter() .map(|(register, data)| { html! { @@ -74,7 +76,9 @@ pub fn generate_gpr_rows_hex(props: &Regviewprops) -> Html { let communicator = props.communicator; let pc_limit = props.pc_limit; - props.gp.into_iter() + props + .gp + .into_iter() .map(|(register, data)| { html! { @@ -113,7 +117,9 @@ pub fn generate_gpr_rows_bin(props: &Regviewprops) -> Html { let communicator = props.communicator; let pc_limit = props.pc_limit; - props.gp.into_iter() + props + .gp + .into_iter() .map(|(register, data)| { html! { @@ -153,7 +159,9 @@ pub fn generate_gpr_rows_bin(props: &Regviewprops) -> Html { pub fn generate_fpr_rows(props: &Regviewprops) -> Html { // let communicator = props.communicator; - props.fp.iter() + props + .fp + .iter() .enumerate() .map(|(register, data)| { html! { @@ -193,7 +201,9 @@ pub fn generate_fpr_rows(props: &Regviewprops) -> Html { pub fn generate_fpr_rows_hex(props: &Regviewprops) -> Html { // let communicator = props.communicator; - props.fp.iter() + props + .fp + .iter() .enumerate() .map(|(register, data)| { html! { @@ -233,7 +243,9 @@ pub fn generate_fpr_rows_hex(props: &Regviewprops) -> Html { pub fn generate_fpr_rows_bin(props: &Regviewprops) -> Html { // let communicator = props.communicator; - props.fp.iter() + props + .fp + .iter() .enumerate() .map(|(register, data)| { html! { @@ -315,7 +327,9 @@ pub fn generate_fpr_rows_float(props: &Regviewprops) -> Html { pub fn generate_fpr_rows_double(props: &Regviewprops) -> Html { // let communicator = props.communicator; - props.fp.iter() + props + .fp + .iter() .enumerate() .map(|(register, data)| { html! { diff --git a/src/ui/swim_editor/component.rs b/src/ui/swim_editor/component.rs index 3d9e9d2ed..d5ab4b7ef 100644 --- a/src/ui/swim_editor/component.rs +++ b/src/ui/swim_editor/component.rs @@ -1,14 +1,29 @@ use std::{cell::RefCell, rc::Rc}; -use monaco::{api::TextModel, sys::{editor::{ - IEditorMinimapOptions, IEditorScrollbarOptions, IModelDecorationOptions, IModelDeltaDecoration, IStandaloneEditorConstructionOptions, ISuggestOptions, ScrollType -}, IMarkdownString, Range}, yew::{CodeEditor, CodeEditorLink}}; +use monaco::{ + api::TextModel, + sys::{ + editor::{ + IEditorMinimapOptions, IEditorScrollbarOptions, IModelDecorationOptions, + IModelDeltaDecoration, IStandaloneEditorConstructionOptions, ISuggestOptions, + ScrollType, + }, + IMarkdownString, Range, + }, + yew::{CodeEditor, CodeEditorLink}, +}; +use wasm_bindgen::{JsCast, JsValue}; +use yew::prelude::*; use yew::{html, Callback, Properties}; use yew_hooks::prelude::*; -use yew::prelude::*; -use wasm_bindgen::{JsCast, JsValue}; -use crate::{parser::parser_structs_and_enums::ProgramInfo, ui::{assembled_view::component::{DataSegment, TextSegment}, footer::component::FooterTabState}}; +use crate::{ + parser::parser_structs_and_enums::ProgramInfo, + ui::{ + assembled_view::component::{DataSegment, TextSegment}, + footer::component::FooterTabState, + }, +}; #[derive(PartialEq, Properties)] pub struct SwimEditorProps { @@ -21,7 +36,7 @@ pub struct SwimEditorProps { pub memory_curr_instr: UseStateHandle, pub editor_curr_line: UseStateHandle, pub editor_active_tab: UseStateHandle, - pub console_active_tab: UseStateHandle + pub console_active_tab: UseStateHandle, } #[derive(Default, PartialEq)] @@ -29,7 +44,7 @@ pub enum EditorTabState { #[default] Editor, TextSegment, - DataSegment + DataSegment, } fn get_options() -> IStandaloneEditorConstructionOptions { @@ -112,7 +127,7 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html { raw_editor.delta_decorations(¬_highlighted, &executed_line); }) { Some(_) => (), - None => () + None => (), }; }, curr_line, @@ -122,7 +137,11 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html { let change_tab = { let editor_active_tab = editor_active_tab.clone(); Callback::from(move |event: MouseEvent| { - let target = event.target().unwrap().dyn_into::().unwrap(); + let target = event + .target() + .unwrap() + .dyn_into::() + .unwrap(); let tab_name = target .get_attribute("label") .unwrap_or(String::from("editor")); @@ -138,7 +157,6 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html { }) }; - // We'll have the Mouse Hover event running at all times. { let text_model = text_model.clone(); @@ -234,4 +252,4 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html { } } -} \ No newline at end of file +} diff --git a/src/ui/swim_editor/mod.rs b/src/ui/swim_editor/mod.rs index 519c53d92..9cea807e4 100644 --- a/src/ui/swim_editor/mod.rs +++ b/src/ui/swim_editor/mod.rs @@ -1 +1 @@ -pub mod component; \ No newline at end of file +pub mod component; From bd3f60adb682d3c6b5cca519cd59a8c7d1c4d967 Mon Sep 17 00:00:00 2001 From: Cay Date: Fri, 16 Feb 2024 18:54:16 -0500 Subject: [PATCH 091/355] Run clippy --- src/agent.rs | 2 +- src/agent/datapath_reducer.rs | 6 ++-- src/bin/main.rs | 12 ++++---- src/emulation_core/mips/instruction.rs | 40 +++++++------------------- src/emulation_core/mips/memory.rs | 2 +- src/ui/assembled_view/component.rs | 4 +-- src/ui/hex_editor/component.rs | 8 +++--- src/ui/regview/component.rs | 16 +++++------ src/ui/swim_editor/component.rs | 4 +-- 9 files changed, 38 insertions(+), 56 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index 9fa449491..5a3d50f6b 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -59,7 +59,7 @@ pub async fn emulation_core_agent(scope: ReactorScope) let memory_update = DatapathUpdate::MIPS(MipsStateUpdate::UpdateMemory(datapath.memory.clone())); let stage_update = DatapathUpdate::MIPS(MipsStateUpdate::UpdateStage( - datapath.current_stage.clone(), + datapath.current_stage, )); state.scope.send(state_update).await.unwrap(); state.scope.send(register_update).await.unwrap(); diff --git a/src/agent/datapath_reducer.rs b/src/agent/datapath_reducer.rs index 88e77eaaf..63bfc7902 100644 --- a/src/agent/datapath_reducer.rs +++ b/src/agent/datapath_reducer.rs @@ -42,19 +42,19 @@ impl Reducible for DatapathReducer { state, registers: self.mips.registers, memory: self.mips.memory.clone(), - current_stage: self.mips.current_stage.clone(), + current_stage: self.mips.current_stage, }, MipsStateUpdate::UpdateRegisters(registers) => MipsCoreState { state: self.mips.state.clone(), registers, memory: self.mips.memory.clone(), - current_stage: self.mips.current_stage.clone(), + current_stage: self.mips.current_stage, }, MipsStateUpdate::UpdateMemory(memory) => MipsCoreState { state: self.mips.state.clone(), registers: self.mips.registers, memory, - current_stage: self.mips.current_stage.clone(), + current_stage: self.mips.current_stage, }, MipsStateUpdate::UpdateStage(stage) => MipsCoreState { state: self.mips.state.clone(), diff --git a/src/bin/main.rs b/src/bin/main.rs index db6fdea3c..ef48b08eb 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -78,7 +78,7 @@ fn app(props: &AppProps) -> Html { use_state_eq(|| TextModel::create(&memory_text_output, Some("ini"), None).unwrap()); // Show input - let show_input = use_state_eq(|| bool::default()); + let show_input = use_state_eq(bool::default); show_input.set(true); let command = use_state_eq(|| String::from("(Test) Enter a string")); @@ -294,7 +294,7 @@ fn app(props: &AppProps) -> Html { use_callback( move |_, datapath_state| { - let communicator = communicator.clone(); + // let communicator = communicator.clone(); let text_model = text_model.clone(); let program_info_ref = Rc::clone(&program_info_ref); @@ -335,7 +335,7 @@ fn app(props: &AppProps) -> Html { // Memory updated successfully let program_info = program_info_ref.borrow().clone(); let mut lines_beyond_counter = program_info.address_to_line_number.len(); - let mut curr_value = text_model.get_value().to_owned(); + let mut curr_value = text_model.get_value(); let mut add_new_lines = false; for line in changed_lines { // Check if we're updating or appending instruction @@ -391,7 +391,7 @@ fn app(props: &AppProps) -> Html { add_new_lines = true; curr_value = text_model.get_value(); } - curr_value.push_str("\n"); + curr_value.push('\n'); curr_value.push_str(&line.text); lines_beyond_counter += 1; } @@ -407,7 +407,7 @@ fn app(props: &AppProps) -> Html { // Update the parsed info for text and data segment views let (program_info, _) = parser(text_model.get_value()); - *program_info_ref.borrow_mut() = program_info.clone(); + *program_info_ref.borrow_mut() = program_info; trigger.force_update(); }, @@ -424,7 +424,7 @@ fn app(props: &AppProps) -> Html { let communicator = props.communicator; // Code editor - let parser_text_output = parser_text_output.clone(); + let parser_text_output = parser_text_output; let editor_curr_line = editor_curr_line.clone(); // Hex editor diff --git a/src/emulation_core/mips/instruction.rs b/src/emulation_core/mips/instruction.rs index dd30b027d..932487edf 100644 --- a/src/emulation_core/mips/instruction.rs +++ b/src/emulation_core/mips/instruction.rs @@ -333,21 +333,12 @@ pub fn get_string_version(value: u32) -> Result { if value & 0xF000 > 0 { imm_is_negative = true; immediate = !(immediate) + 1; - imm_with_sign = -1 * immediate as i32; + imm_with_sign = -(immediate as i32); } - let str_rt = match find_register_name(rt) { - Some(name) => name, - None => "##", - }; - let str_rs = match find_register_name(rs) { - Some(name) => name, - None => "##", - }; - let str_rd = match find_register_name(rd) { - Some(name) => name, - None => "##", - }; + let str_rt = find_register_name(rt).unwrap_or("##"); + let str_rs = find_register_name(rs).unwrap_or("##"); + let str_rd = find_register_name(rd).unwrap_or("##"); let mut string_imm = immediate.to_string(); let mut str_immediate = string_imm.as_str(); @@ -431,7 +422,7 @@ pub fn get_string_version(value: u32) -> Result { string_version = format!("{} {} {} {}", "or", str_rd, str_rs, str_rt); Ok(string_version) } - FUNCT_SOP36 => match shamt as u8 { + FUNCT_SOP36 => match shamt { // ENC_DIV == ENC_DDIV ENC_DIV => { string_version = format!("{} {} {}", "div", str_rs, str_rt); @@ -442,7 +433,7 @@ pub fn get_string_version(value: u32) -> Result { Ok(string_version) } }, - FUNCT_SOP33 | FUNCT_SOP37 => match shamt as u8 { + FUNCT_SOP33 | FUNCT_SOP37 => match shamt { // ENC_DIVU == ENC_DDIVU ENC_DIVU => { string_version = format!("{} {} {}", "divu", str_rs, str_rt); @@ -453,7 +444,7 @@ pub fn get_string_version(value: u32) -> Result { Ok(string_version) } }, - FUNCT_SOP30 | FUNCT_SOP34 => match shamt as u8 { + FUNCT_SOP30 | FUNCT_SOP34 => match shamt { // ENC_MUL == ENC_DMUL ENC_MUL => { string_version = format!("{} {} {} {}", "mul", str_rd, str_rs, str_rt); @@ -464,7 +455,7 @@ pub fn get_string_version(value: u32) -> Result { Ok(string_version) } }, - FUNCT_SOP31 | FUNCT_SOP35 => match shamt as u8 { + FUNCT_SOP31 | FUNCT_SOP35 => match shamt { // ENC_MULU == ENC_DMULU ENC_MULU => { string_version = format!("{} {} {} {}", "mulu", str_rd, str_rs, str_rt); @@ -492,18 +483,9 @@ pub fn get_string_version(value: u32) -> Result { let fs = ((value >> 11) & 0x1F) as u8; // also rs let fd = ((value >> 6) & 0x1F) as u8; let function = (value & 0x3F) as u8; - let str_fs = match find_register_name(fs) { - Some(name) => name, - None => "##", - }; - let str_ft = match find_register_name(ft) { - Some(name) => name, - None => "##", - }; - let str_fd = match find_register_name(fd) { - Some(name) => name, - None => "##", - }; + let str_fs = find_register_name(fs).unwrap_or("##"); + let str_ft = find_register_name(ft).unwrap_or("##"); + let str_fd = find_register_name(fd).unwrap_or("##"); match sub { // If it is the "s" or "d" fmts, use the `function` field. diff --git a/src/emulation_core/mips/memory.rs b/src/emulation_core/mips/memory.rs index fc8d8a49a..3906d092d 100644 --- a/src/emulation_core/mips/memory.rs +++ b/src/emulation_core/mips/memory.rs @@ -137,7 +137,7 @@ impl Memory { // } pub fn generate_formatted_hex(&self) -> String { - let iterator = MemoryIter::new(&self); + let iterator = MemoryIter::new(self); let mut string: String = "".to_string(); diff --git a/src/ui/assembled_view/component.rs b/src/ui/assembled_view/component.rs index 5269371f2..5697a9ffb 100644 --- a/src/ui/assembled_view/component.rs +++ b/src/ui/assembled_view/component.rs @@ -112,7 +112,7 @@ pub fn TextSegment(props: &TextSegmentProps) -> Html { let executed_ref = executed_ref.clone(); address += 4; - let line_number = instruction.line_number.clone(); + let line_number = instruction.line_number; let mut conditional_class = ""; if props.pc as i64 == address + 4 { @@ -220,7 +220,7 @@ pub fn DataSegment(props: &DataSegmentProps) -> Html { {"Source"} { - if program_info.instructions.len() > 0 && binary.len() > 0 { + if !program_info.instructions.is_empty() && !binary.is_empty() { let mut address = program_info.instructions.len() * 4 - 4; let mut data_binary_index = program_info.data_starting_point - 1; program_info.data.iter().enumerate().map(|(index, data)| { diff --git a/src/ui/hex_editor/component.rs b/src/ui/hex_editor/component.rs index ec8e7f7b7..b7452a4f9 100644 --- a/src/ui/hex_editor/component.rs +++ b/src/ui/hex_editor/component.rs @@ -113,13 +113,13 @@ pub fn hex_editor(props: &HexEditorProps) -> Html { let start_column = offset + ((instruction_num % 16) * 2 + ((instruction_num % 16) / 4)); let end_column = start_column + 8; - let coords = HexCoord { + + + HexCoord { line_number: line_number as f64, start_column: start_column as f64, end_column: end_column as f64, - }; - - coords + } } // Calculates which columns in the ASCII portion belong to the given hex portion diff --git a/src/ui/regview/component.rs b/src/ui/regview/component.rs index 32a1cd238..c24deb716 100644 --- a/src/ui/regview/component.rs +++ b/src/ui/regview/component.rs @@ -457,24 +457,24 @@ pub fn regview(props: &Regviewprops) -> Html { if *switch_flag{ if *active_view == UnitState::Bin { - {generate_gpr_rows_bin(&props)} + {generate_gpr_rows_bin(props)} } else if *active_view == UnitState::Hex { - {generate_gpr_rows_hex(&props)} + {generate_gpr_rows_hex(props)} } else { - {generate_gpr_rows(&props)} + {generate_gpr_rows(props)} } } else { if *active_view == UnitState::Bin { - {generate_fpr_rows_bin(&props)} + {generate_fpr_rows_bin(props)} } else if *active_view == UnitState::Hex{ - {generate_fpr_rows_hex(&props)} + {generate_fpr_rows_hex(props)} } else if *active_view == UnitState::Float{ - {generate_fpr_rows_float(&props)} + {generate_fpr_rows_float(props)} } else if *active_view == UnitState::Double{ - {generate_fpr_rows_double(&props)} + {generate_fpr_rows_double(props)} } else if *active_view == UnitState::Dec { - {generate_fpr_rows(&props)} + {generate_fpr_rows(props)} } } diff --git a/src/ui/swim_editor/component.rs b/src/ui/swim_editor/component.rs index d5ab4b7ef..6cf1acd6f 100644 --- a/src/ui/swim_editor/component.rs +++ b/src/ui/swim_editor/component.rs @@ -244,9 +244,9 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html { }
if **editor_active_tab == EditorTabState::Editor { - + } else if **editor_active_tab == EditorTabState::TextSegment { - + } else if **editor_active_tab == EditorTabState::DataSegment { } From e8742921b80d0f4af01c3a295d71d35ee79ddb70 Mon Sep 17 00:00:00 2001 From: Cay Date: Fri, 16 Feb 2024 18:55:45 -0500 Subject: [PATCH 092/355] Run cargo fmt again --- src/bin/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index ef48b08eb..011ea91d2 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -294,7 +294,6 @@ fn app(props: &AppProps) -> Html { use_callback( move |_, datapath_state| { - // let communicator = communicator.clone(); let text_model = text_model.clone(); let program_info_ref = Rc::clone(&program_info_ref); From d6ac4c98e5c2785e5c36ce7600bcb6933130b18f Mon Sep 17 00:00:00 2001 From: Cay Date: Fri, 16 Feb 2024 18:57:10 -0500 Subject: [PATCH 093/355] Actually run cargo fmt --- src/agent.rs | 5 ++--- src/ui/hex_editor/component.rs | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index 5a3d50f6b..a93658f6a 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -58,9 +58,8 @@ pub async fn emulation_core_agent(scope: ReactorScope) DatapathUpdate::MIPS(MipsStateUpdate::UpdateRegisters(datapath.registers)); let memory_update = DatapathUpdate::MIPS(MipsStateUpdate::UpdateMemory(datapath.memory.clone())); - let stage_update = DatapathUpdate::MIPS(MipsStateUpdate::UpdateStage( - datapath.current_stage, - )); + let stage_update = + DatapathUpdate::MIPS(MipsStateUpdate::UpdateStage(datapath.current_stage)); state.scope.send(state_update).await.unwrap(); state.scope.send(register_update).await.unwrap(); state.scope.send(memory_update).await.unwrap(); diff --git a/src/ui/hex_editor/component.rs b/src/ui/hex_editor/component.rs index b7452a4f9..29e2ce6a2 100644 --- a/src/ui/hex_editor/component.rs +++ b/src/ui/hex_editor/component.rs @@ -113,8 +113,6 @@ pub fn hex_editor(props: &HexEditorProps) -> Html { let start_column = offset + ((instruction_num % 16) * 2 + ((instruction_num % 16) / 4)); let end_column = start_column + 8; - - HexCoord { line_number: line_number as f64, start_column: start_column as f64, From 96aad8e1e3ca69859cf37f1b29e3434c81900965 Mon Sep 17 00:00:00 2001 From: Cay Date: Fri, 16 Feb 2024 19:06:30 -0500 Subject: [PATCH 094/355] all hail clippy --- src/ui/regview/component.rs | 2 +- src/ui/swim_editor/component.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ui/regview/component.rs b/src/ui/regview/component.rs index c24deb716..be351b855 100644 --- a/src/ui/regview/component.rs +++ b/src/ui/regview/component.rs @@ -173,7 +173,7 @@ pub fn generate_fpr_rows(props: &Regviewprops) -> Html { let target = e.target(); let input = target.unwrap().unchecked_into::(); let input_string = input.value(); - let val = match u64::from_str_radix(&input_string, 10) { + let val = match input_string.parse::() { Ok(value) => { input.set_class_name("valid"); value diff --git a/src/ui/swim_editor/component.rs b/src/ui/swim_editor/component.rs index 6cf1acd6f..dc29e46cb 100644 --- a/src/ui/swim_editor/component.rs +++ b/src/ui/swim_editor/component.rs @@ -126,8 +126,8 @@ pub fn SwimEditor(props: &SwimEditorProps) -> Html { executed_line.push(&decoration_js); raw_editor.delta_decorations(¬_highlighted, &executed_line); }) { - Some(_) => (), - None => (), + Some(()) => log::debug!("Swim Editor linked!"), + None => log::debug!("No swim editor :<"), }; }, curr_line, From 214fda97fdafaedb6f96ebaa60ff969d06d64540 Mon Sep 17 00:00:00 2001 From: Cay Date: Sat, 17 Feb 2024 10:39:03 -0500 Subject: [PATCH 095/355] Fix compilation error in parser --- src/parser/parser_assembler_main.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/parser/parser_assembler_main.rs b/src/parser/parser_assembler_main.rs index 1b68cc919..ac33dccef 100644 --- a/src/parser/parser_assembler_main.rs +++ b/src/parser/parser_assembler_main.rs @@ -32,8 +32,6 @@ pub fn parser(file_string: String) -> (ProgramInfo, Vec) { &mut program_info.monaco_line_info, ); - let vec_of_data = assemble_data_binary(&mut program_info.data); - let labels: HashMap = create_label_map(&mut program_info.instructions, &mut program_info.data); @@ -56,8 +54,6 @@ pub fn parser(file_string: String) -> (ProgramInfo, Vec) { &mut program_info.monaco_line_info, ); - let binary = create_binary_vec(program_info.instructions.clone(), vec_of_data); - for entry in &program_info.monaco_line_info { program_info .updated_monaco_string @@ -107,6 +103,7 @@ pub fn parser(file_string: String) -> (ProgramInfo, Vec) { } program_info.pc_starting_point = determine_pc_starting_point(labels); + program_info.data_starting_point = data_starting_point; (program_info.clone(), binary) } else { @@ -150,7 +147,7 @@ pub fn parser(file_string: String) -> (ProgramInfo, Vec) { &mut program_info.monaco_line_info, ); - let binary = create_binary_vec(program_info.instructions.clone(), vec_of_data); + let (binary, data_starting_point): (Vec, usize) = create_binary_vec(program_info.instructions.clone(), vec_of_data); for entry in &program_info.monaco_line_info { program_info From 2ebaff28d242c7d63b76126b2e545d7767d6410c Mon Sep 17 00:00:00 2001 From: Cay Date: Sat, 17 Feb 2024 10:53:08 -0500 Subject: [PATCH 096/355] Fix parser function merge conflict --- src/parser/parser_assembler_main.rs | 48 +++++------------------------ 1 file changed, 8 insertions(+), 40 deletions(-) diff --git a/src/parser/parser_assembler_main.rs b/src/parser/parser_assembler_main.rs index ac33dccef..4a04a7c81 100644 --- a/src/parser/parser_assembler_main.rs +++ b/src/parser/parser_assembler_main.rs @@ -32,43 +32,6 @@ pub fn parser(file_string: String) -> (ProgramInfo, Vec) { &mut program_info.monaco_line_info, ); - let labels: HashMap = - create_label_map(&mut program_info.instructions, &mut program_info.data); - - complete_lw_sw_pseudo_instructions( - &mut program_info.instructions, - &labels, - &mut program_info.monaco_line_info, - ); - - read_instructions( - &mut program_info.instructions, - &labels, - &mut program_info.monaco_line_info, - ); - - program_info.console_out_post_assembly = suggest_error_corrections( - &mut program_info.instructions, - &mut program_info.data, - &labels, - &mut program_info.monaco_line_info, - ); - - for entry in &program_info.monaco_line_info { - program_info - .updated_monaco_string - .push_str(&format!("{}\n", entry.updated_monaco_string)); - } - - (program_info.instructions, program_info.data) = - separate_data_and_text(&mut program_info.monaco_line_info); - - expand_pseudo_instructions_and_assign_instruction_numbers( - &mut program_info.instructions, - &program_info.data, - &mut program_info.monaco_line_info, - ); - let vec_of_data = assemble_data_binary(&mut program_info.data); let labels: HashMap = @@ -93,8 +56,7 @@ pub fn parser(file_string: String) -> (ProgramInfo, Vec) { &mut program_info.monaco_line_info, ); - let (binary, data_starting_point) = - create_binary_vec(program_info.instructions.clone(), vec_of_data); + let (binary, data_starting_point) = create_binary_vec(program_info.instructions.clone(), vec_of_data); for entry in &program_info.monaco_line_info { program_info @@ -102,6 +64,12 @@ pub fn parser(file_string: String) -> (ProgramInfo, Vec) { .push_str(&format!("{}\n", entry.updated_monaco_string)); } + for instruction in program_info.instructions.clone() { + program_info + .address_to_line_number + .push(instruction.line_number); + } + program_info.pc_starting_point = determine_pc_starting_point(labels); program_info.data_starting_point = data_starting_point; @@ -147,7 +115,7 @@ pub fn parser(file_string: String) -> (ProgramInfo, Vec) { &mut program_info.monaco_line_info, ); - let (binary, data_starting_point): (Vec, usize) = create_binary_vec(program_info.instructions.clone(), vec_of_data); + let (binary, data_starting_point) = create_binary_vec(program_info.instructions.clone(), vec_of_data); for entry in &program_info.monaco_line_info { program_info From 4d039375deb558ff482a7266d869a3bed768f9c9 Mon Sep 17 00:00:00 2001 From: Cay Date: Sun, 18 Feb 2024 18:25:27 -0500 Subject: [PATCH 097/355] Add UpdateStage and UpdateCoprocessor, add a visual_line_to_data function that uses datapath_state --- src/agent.rs | 5 +- src/agent/datapath_reducer.rs | 19 +- src/agent/messages.rs | 4 +- src/bin/main.rs | 2 +- src/emulation_core/mips/control_signals.rs | 25 +- src/emulation_core/mips/coprocessor.rs | 5 +- src/emulation_core/mips/instruction.rs | 21 +- src/emulation_core/mips/line_info.rs | 314 +++++++++++++++++++++ src/emulation_core/riscv/line_info.rs | 311 ++++++++++++++++++++ src/ui/footer/component.rs | 6 +- src/ui/visual_datapath/mod.rs | 84 +++--- src/ui/visual_datapath/utils.rs | 19 +- 12 files changed, 732 insertions(+), 83 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index a93658f6a..794b80830 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -58,12 +58,13 @@ pub async fn emulation_core_agent(scope: ReactorScope) DatapathUpdate::MIPS(MipsStateUpdate::UpdateRegisters(datapath.registers)); let memory_update = DatapathUpdate::MIPS(MipsStateUpdate::UpdateMemory(datapath.memory.clone())); - let stage_update = - DatapathUpdate::MIPS(MipsStateUpdate::UpdateStage(datapath.current_stage)); + let stage_update = DatapathUpdate::MIPS(MipsStateUpdate::UpdateStage(datapath.current_stage.clone())); + let coprocessor_update = DatapathUpdate::MIPS(MipsStateUpdate::UpdateCoprocessor(datapath.coprocessor.clone())); state.scope.send(state_update).await.unwrap(); state.scope.send(register_update).await.unwrap(); state.scope.send(memory_update).await.unwrap(); state.scope.send(stage_update).await.unwrap(); + state.scope.send(coprocessor_update).await.unwrap(); } } } diff --git a/src/agent/datapath_reducer.rs b/src/agent/datapath_reducer.rs index 63bfc7902..dcbe98b5a 100644 --- a/src/agent/datapath_reducer.rs +++ b/src/agent/datapath_reducer.rs @@ -1,6 +1,7 @@ use crate::agent::messages::MipsStateUpdate; use crate::emulation_core::architectures::AvailableDatapaths::MIPS; use crate::emulation_core::architectures::{AvailableDatapaths, DatapathUpdate}; +use crate::emulation_core::mips::coprocessor::MipsFpCoprocessor; use crate::emulation_core::mips::datapath::{DatapathState, Stage}; use crate::emulation_core::mips::memory::Memory; use crate::emulation_core::mips::registers::GpRegisters; @@ -19,6 +20,7 @@ pub struct MipsCoreState { pub registers: GpRegisters, pub memory: Memory, pub current_stage: Stage, + pub coprocessor: MipsFpCoprocessor } impl Default for DatapathReducer { @@ -42,25 +44,36 @@ impl Reducible for DatapathReducer { state, registers: self.mips.registers, memory: self.mips.memory.clone(), - current_stage: self.mips.current_stage, + current_stage: self.mips.current_stage.clone(), + coprocessor: self.mips.coprocessor.clone(), }, MipsStateUpdate::UpdateRegisters(registers) => MipsCoreState { state: self.mips.state.clone(), registers, memory: self.mips.memory.clone(), - current_stage: self.mips.current_stage, + current_stage: self.mips.current_stage.clone(), + coprocessor: self.mips.coprocessor.clone(), }, MipsStateUpdate::UpdateMemory(memory) => MipsCoreState { state: self.mips.state.clone(), registers: self.mips.registers, memory, - current_stage: self.mips.current_stage, + current_stage: self.mips.current_stage.clone(), + coprocessor: self.mips.coprocessor.clone(), }, MipsStateUpdate::UpdateStage(stage) => MipsCoreState { state: self.mips.state.clone(), registers: self.mips.registers, memory: self.mips.memory.clone(), current_stage: stage, + coprocessor: self.mips.coprocessor.clone(), + }, + MipsStateUpdate::UpdateCoprocessor(coprocessor) => MipsCoreState { + state: self.mips.state.clone(), + registers: self.mips.registers, + memory: self.mips.memory.clone(), + current_stage: self.mips.current_stage.clone(), + coprocessor }, }, }, diff --git a/src/agent/messages.rs b/src/agent/messages.rs index 664c2deaa..d44f41dd3 100644 --- a/src/agent/messages.rs +++ b/src/agent/messages.rs @@ -1,7 +1,8 @@ +use crate::emulation_core::mips::coprocessor::MipsFpCoprocessor; +use crate::emulation_core::{architectures::AvailableDatapaths, mips::datapath::Stage}; use crate::emulation_core::mips::datapath::DatapathState; use crate::emulation_core::mips::memory::Memory; use crate::emulation_core::mips::registers::GpRegisters; -use crate::emulation_core::{architectures::AvailableDatapaths, mips::datapath::Stage}; use serde::{Deserialize, Serialize}; /// Commands sent from the UI thread to the worker thread. @@ -26,4 +27,5 @@ pub enum MipsStateUpdate { UpdateRegisters(GpRegisters), UpdateMemory(Memory), UpdateStage(Stage), + UpdateCoprocessor(MipsFpCoprocessor), } diff --git a/src/bin/main.rs b/src/bin/main.rs index 011ea91d2..5f505212c 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -522,7 +522,7 @@ fn app(props: &AppProps) -> Html {
// Console -
+
// Right column diff --git a/src/emulation_core/mips/control_signals.rs b/src/emulation_core/mips/control_signals.rs index 5ff0ad324..2336fc558 100644 --- a/src/emulation_core/mips/control_signals.rs +++ b/src/emulation_core/mips/control_signals.rs @@ -278,9 +278,10 @@ pub enum RegWrite { } pub mod floating_point { + use serde::{Deserialize, Serialize}; use super::super::constants::*; - #[derive(Clone, Default, PartialEq)] + #[derive(Clone, Default, PartialEq, Serialize, Deserialize, Debug)] pub struct FpuControlSignals { pub cc: Cc, pub cc_write: CcWrite, @@ -300,7 +301,7 @@ pub mod floating_point { /// /// For the sake of this project, it will usually be assumed that this will /// be 0, however the functionality is available to be extended. - #[derive(Clone, Default, PartialEq)] + #[derive(Clone, Default, PartialEq, Serialize, Deserialize, Debug)] pub enum Cc { /// Use condition code register 0. Default in most operations. Can be /// additionally used in the case where the condition code register is @@ -310,7 +311,7 @@ pub mod floating_point { } /// Determines if the condition code register file should be written to. - #[derive(Clone, Default, PartialEq)] + #[derive(Clone, Default, PartialEq, Serialize, Deserialize, Debug)] pub enum CcWrite { #[default] NoWrite = 0, @@ -321,7 +322,7 @@ pub mod floating_point { /// /// This is a special intermediary register that facilitates passing data between /// the main processing unit and the floating-point unit. - #[derive(Clone, Default, PartialEq)] + #[derive(Clone, Default, PartialEq, Serialize, Deserialize, Debug)] pub enum DataSrc { /// Use data from the main processing unit. Specifically, the data from register /// `rt` from a given instruction. This value can additionally be used in the cases @@ -342,7 +343,7 @@ pub mod floating_point { /// For the latter two functions, it is imperative to unset the [`RegWrite`](super::RegWrite) and /// [`FpuRegWrite`] control signals in cases where registers should not be modified /// with unintended data. - #[derive(Clone, Default, PartialEq)] + #[derive(Clone, Default, PartialEq, Serialize, Deserialize, Debug)] pub enum DataWrite { /// - Do not write to the data register. /// - Source data to write to the main processing unit register file from the main @@ -373,7 +374,7 @@ pub mod floating_point { /// /// *Implementation note:* The bits set for the comparator are intended to match /// the bits used in the `cond` field of a `c.cond.fmt` instruction. - #[derive(Clone, Debug, Default, PartialEq)] + #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] pub enum FpuAluOp { #[default] /// `_0000` (0): @@ -437,7 +438,7 @@ pub mod floating_point { /// /// This directly overrides any branch decisions decided by the main processing unit. /// The [`Branch`](super::Branch) control signal should not be set in addition to this signal. - #[derive(Clone, Default, PartialEq)] + #[derive(Clone, Default, PartialEq, Serialize, Deserialize, Debug)] pub enum FpuBranch { /// Do not consider branching. #[default] @@ -451,7 +452,7 @@ pub mod floating_point { /// register's new data will be. /// /// This decision, if set, overrides the decision from the [`DataWrite`] control signal. - #[derive(Clone, Default, PartialEq)] + #[derive(Clone, Default, PartialEq, Serialize, Deserialize, Debug)] pub enum FpuMemToReg { /// Do not use data from memory. Use the result of the [`DataWrite`] control signal. #[default] @@ -463,7 +464,7 @@ pub mod floating_point { /// Determines, given that [`FpuRegWrite`] is set, which destination register to write /// to, which largely depends on the instruction format. - #[derive(Clone, Default, PartialEq)] + #[derive(Clone, Default, PartialEq, Serialize, Deserialize, Debug)] pub enum FpuRegDst { /// Use register `ft`. Reg1 = 0, @@ -480,7 +481,7 @@ pub mod floating_point { /// /// While all buses carrying information are 64-bits wide, some bits of the bus may be /// ignored in the case of this control signal. - #[derive(Clone, Default, PartialEq)] + #[derive(Clone, Default, PartialEq, Serialize, Deserialize, Debug)] pub enum FpuRegWidth { /// Use words (32 bits). Equivalent to a single-precision floating-point value. Word = 0, @@ -503,7 +504,7 @@ pub mod floating_point { } /// Determines if the floating-point register file should be written to. - #[derive(Clone, Default, PartialEq)] + #[derive(Clone, Default, PartialEq, Serialize, Deserialize, Debug)] pub enum FpuRegWrite { /// Do not write to the floating-point register file. #[default] @@ -517,7 +518,7 @@ pub mod floating_point { /// to follow through with a branch. /// /// This signal is what is sent to the main processor. - #[derive(Clone, Default, PartialEq)] + #[derive(Clone, Default, PartialEq, Serialize, Deserialize, Debug)] pub enum FpuTakeBranch { #[default] NoBranch = 0, diff --git a/src/emulation_core/mips/coprocessor.rs b/src/emulation_core/mips/coprocessor.rs index c0c40fe85..8a3e75146 100644 --- a/src/emulation_core/mips/coprocessor.rs +++ b/src/emulation_core/mips/coprocessor.rs @@ -1,5 +1,6 @@ //! Implementation of a MIPS64 floating-point coprocessor. +use serde::{Deserialize, Serialize}; use super::constants::*; use super::control_signals::floating_point::*; use super::instruction::Instruction; @@ -8,7 +9,7 @@ use super::instruction::Instruction; /// /// Different from the main processor, much of the functionality of the coprocessor /// is controlled remotely using its available API calls. -#[derive(Clone, Default, PartialEq)] +#[derive(Clone, Default, PartialEq, Serialize, Debug, Deserialize)] pub struct MipsFpCoprocessor { instruction: Instruction, pub signals: FpuControlSignals, @@ -20,7 +21,7 @@ pub struct MipsFpCoprocessor { pub data: u64, } -#[derive(Clone, Default, PartialEq)] +#[derive(Clone, Default, PartialEq, Debug, Serialize, Deserialize)] pub struct FpuState { pub instruction: u32, pub op: u32, diff --git a/src/emulation_core/mips/instruction.rs b/src/emulation_core/mips/instruction.rs index 932487edf..70a45b0f9 100644 --- a/src/emulation_core/mips/instruction.rs +++ b/src/emulation_core/mips/instruction.rs @@ -1,5 +1,6 @@ //! Abstract representation of an instruction. +use serde::{Deserialize, Serialize}; use crate::parser::parser_structs_and_enums::GP_REGISTERS; use super::constants::*; @@ -24,7 +25,7 @@ use super::constants::*; /// determining the type of instruction executed (in `mul`, `dmul`, `dmulu`, `div`, `ddiv`, /// `ddivu`), or be used as a "hint" field for certain instructions (of note are `jr` and `jalr`). /// - function: Secondary field for determining the type of instruction executed. -#[derive(Clone, Copy, Debug, Default, PartialEq)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)] pub struct RType { pub op: u8, pub rs: u8, @@ -34,7 +35,7 @@ pub struct RType { pub funct: u8, } -#[derive(Clone, Copy, Debug, Default, PartialEq)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)] pub struct IType { pub op: u8, pub rs: u8, @@ -42,7 +43,7 @@ pub struct IType { pub immediate: u16, } -#[derive(Clone, Copy, Debug, Default, PartialEq)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)] pub struct JType { pub op: u8, pub addr: u32, @@ -62,14 +63,14 @@ pub struct JType { /// - opcode: SPECIAL (`000000`) /// - code: Available for use as software parameters. /// - funct: SYSCALL (`001100`) -#[derive(Clone, Copy, Debug, Default, PartialEq)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)] pub struct SyscallType { pub op: u8, pub code: u32, pub funct: u8, } -#[derive(Clone, Copy, Debug, Default, PartialEq)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)] pub struct FpuRType { pub op: u8, pub fmt: u8, @@ -79,7 +80,7 @@ pub struct FpuRType { pub function: u8, } -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] pub struct FpuIType { pub op: u8, pub base: u8, @@ -105,7 +106,7 @@ pub struct FpuIType { /// - sub: Operation subcode field for COP1 register immediate-mode instructions. /// - rt: CPU register - can be either source or destination. /// - fs: FPU register - can be either source or destination. -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] pub struct FpuRegImmType { pub op: u8, pub sub: u8, @@ -113,7 +114,7 @@ pub struct FpuRegImmType { pub fs: u8, } -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] pub struct FpuCompareType { pub op: u8, pub fmt: u8, @@ -142,7 +143,7 @@ pub struct FpuCompareType { /// - nd: Nullify delay. If set, the branch is Likely, and the delay slot instruction is not executed. (Not necessary for this project.) /// - tf: True/False. The type of condition for a comparison. /// - offset: Signed offset field used in address calculations. -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] pub struct FpuBranchType { pub op: u8, pub bcc1: u8, @@ -152,7 +153,7 @@ pub struct FpuBranchType { pub offset: u16, } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum Instruction { RType(RType), IType(IType), diff --git a/src/emulation_core/mips/line_info.rs b/src/emulation_core/mips/line_info.rs index add7c20ec..1467d8e16 100644 --- a/src/emulation_core/mips/line_info.rs +++ b/src/emulation_core/mips/line_info.rs @@ -1,6 +1,9 @@ //! Module for mapping lines in the visual datapath to information //! and variables in the coded datapath. +use yew::UseReducerHandle; +use crate::agent::datapath_reducer::DatapathReducer; + use super::super::datapath::VisualDatapath; use super::datapath::MipsDatapath; @@ -330,3 +333,314 @@ impl VisualDatapath for MipsDatapath { } } } + +pub fn visual_line_to_data(variable: &str, datapath_state: &UseReducerHandle) -> LineInformation { + match variable { + "alu_input2" => LineInformation { + title: String::from("ALU Input 2"), + description: String::from("The second input to the ALU. This is determined by the ALUSrc control signal to select between register data, a sign-extended and left-shifted immediate value, or a zero-extended immediate value."), + value: datapath_state.mips.state.alu_input2, + bits: 64, + }, + "alu_result" => LineInformation { + title: String::from("ALU Result"), + description: String::from("The result of the calculation performed by the ALU. This is used either as an address to access memory or as a value that is saved into a register."), + value: datapath_state.mips.state.alu_result, + bits: 64, + }, + "data_result" => LineInformation { + title: String::from("Writeback Data"), + description: String::from("After finishing processing the instruction, this will either be the ALU result, data from memory, or PC + 4, based on the MemToReg control signal. This data is saved into registers."), + value: datapath_state.mips.state.data_result, + bits: 64, + }, + "fpu_alu_result" => LineInformation { + title: String::from("Floating-Point ALU Result"), + description: String::from("The result of the calculation performed by the floating-point ALU. This is used as an option to be written to a floating-point register, based on the DataWrite and FpuMemToReg control signals."), + value: datapath_state.mips.coprocessor.state.alu_result, + bits: 64, + }, + "fpu_branch_decision" => LineInformation { + title: String::from("FPU Branch Decision"), + description: String::from("Based on the true/false branch flag, determines whether to branch. (The FpuBranch control signal must also be set.)"), + value: datapath_state.mips.coprocessor.state.condition_code_mux as u64, + bits: 1, + }, + "fpu_branch_flag" => LineInformation { + title: String::from("Instruction [16] (True/False Branch Flag)"), + description: String::from("The true/false branch flag of branching datapath_state.mips.coprocessor instructions. This flag specifies whether a floating-point branch instruction is BC1T or BC1F."), + value: datapath_state.mips.coprocessor.state.branch_flag as u64, + bits: 1, + }, + "fpu_comparator_result" => LineInformation { + title: String::from("Floating-Point Comparator Result"), + description: String::from("The result of the comparison of two floating-point values. This is routed to the \"Condition Code\" (cc) register, and will be written there if the CcWrite control signal is set."), + value: datapath_state.mips.coprocessor.state.comparator_result, + bits: 64, + }, + "fpu_condition_code" => LineInformation { + title: String::from("Condition Code Value"), + description: String::from("Data retrieved from the \"Condition Code\" (cc) register. This specifies whether a previous conditional instruction was true or false."), + value: datapath_state.mips.coprocessor.state.condition_code_bit as u64, + bits: 1, + }, + "fpu_condition_code_inverted" => LineInformation { + title: String::from("Condition Code Value (Inverted)"), + description: String::from("Inverted form of the condition code register value."), + value: datapath_state.mips.coprocessor.state.condition_code_bit_inverted as u64, + bits: 1, + }, + "fpu_data" => LineInformation { + title: String::from("Floating-Point Data Register Value"), + description: String::from("Data retrieved from the \"Data\" register. This register acts as a means to communicate data between the main processor and floating-point datapath_state.mips.coprocessor in MTC1 and MFC1 instructions."), + value: datapath_state.mips.coprocessor.state.fmt as u64, + bits: 64, + }, + "fpu_data_writeback" => LineInformation { + title: String::from("Floating-Point Data Writeback"), + description: String::from("The value from the floating-point unit's \"Data\" register. Depending on the FpuRegWidth control signal, this will be 64-bit data or sign-extended 32-bit data."), + value: datapath_state.mips.coprocessor.state.data_writeback, + bits: 64, + }, + "fpu_destination" => LineInformation { + title: String::from("Floating-Point Write Register"), + description: String::from("The register that will be written to, assuming FpuRegWrite is set. Depending on the FpuRegDst control signal, this will consist of the fs, ft, or fd register."), + value: datapath_state.mips.coprocessor.state.destination as u64, + bits: 5, + }, + "fpu_fd" => LineInformation { + title: String::from("Instruction [10-6] (fd)"), + description: String::from("The fd field. Depending on the FpuRegDst control signal, this will be the register written to in a floating-point operation. This register is used as the destination for most floating-point arithmetic instructions."), + value: datapath_state.mips.coprocessor.state.fd as u64, + bits: 5, + }, + "fpu_fmt" => LineInformation { + title: String::from("Instruction [25-21] (fmt)"), + description: String::from("The fmt field. This is used to distinguish between single-precision and double-precision floating-point instructions."), + value: datapath_state.mips.coprocessor.state.fmt as u64, + bits: 5, + }, + "fpu_fp_register_data_from_main_processor" => LineInformation { + title: String::from("Writeback Data (To Floating-Point Coprocessor)"), + description: String::from("This data is written to a floating-point register, given FpuMemToReg is set. This line allows data to load from memory to a floating-point register, specifically in the case of the LWC1 instruction."), + value: datapath_state.mips.coprocessor.state.fp_register_data_from_main_processor, + bits: 64, + }, + "fpu_fp_register_to_memory" => LineInformation { + title: String::from("Memory Write Data (from FPU)"), + description: String::from("If the MemWriteSrc control signal is set, this data will be written to memory. This is used for the SWC1 instruction."), + value: datapath_state.mips.coprocessor.state.fp_register_to_memory, + bits: 64, + }, + "fpu_fs" => LineInformation { + title: String::from("Instruction [15-11] (fs)"), + description: String::from("The fs field. Contains the first register to be read for a floating-point instruction."), + value: datapath_state.mips.coprocessor.state.fs as u64, + bits: 5, + }, + "fpu_ft" => LineInformation { + title: String::from("Instruction [20-16] (ft)"), + description: String::from("The ft field. Contains the second register to be read for a floating-point instruction."), + value: datapath_state.mips.coprocessor.state.ft as u64, + bits: 5, + }, + "fpu_new_data" => LineInformation { + title: String::from("New Floating-Point Data Register Value"), + description: String::from("Data sent to the \"Data\" register. Depending on the DataSrc control signal, this will either be data from the main processor or the floating-point datapath_state.mips.coprocessor. This register acts as a means to communicate data between the main processor and floating-point datapath_state.mips.coprocessor in MTC1 and MFC1 instructions."), + value: datapath_state.mips.coprocessor.state.fmt as u64, + bits: 64, + }, + "fpu_read_data_1" => LineInformation { + title: String::from("FPU Read Data 1"), + description: String::from("Data retrieved from the register specified by the fs instruction field. This is used as the first inputs to the floating-point ALU and comparator. This can additionally be written to the \"Data\" register, based on the DataSrc and DataWrite control signals."), + value: datapath_state.mips.coprocessor.state.read_data_1, + bits: 64, + }, + "fpu_read_data_2" => LineInformation { + title: String::from("FPU Read Data 2"), + description: String::from("Data retrieved from the register specified by the ft instruction field. This is used as the second inputs to the floating-point ALU and comparator. This can additionally be used as data to be written to memory, based on the MemWriteSrc control signal."), + value: datapath_state.mips.coprocessor.state.read_data_2, + bits: 64, + }, + "fpu_register_write_data" => LineInformation { + title: String::from("FPU Register Write Data"), + description: String::from("Data that will be written to a floating-point register, given that FpuRegWrite is set."), + value: datapath_state.mips.coprocessor.state.register_write_data, + bits: 64, + }, + "fpu_register_write_mux_to_mux" => LineInformation { + title: String::from("FPU Register Write Data (When FpuMemToReg is Unset)"), + description: String::from("Based on the DataWrite control signal, this will either be the result of the floating-point ALU or the contents of the \"Data\" register. (The \"Data\" register is used for transferring data between the processor and floating-point datapath_state.mips.coprocessor.)"), + value: datapath_state.mips.coprocessor.state.register_write_mux_to_mux, + bits: 64, + }, + "fpu_sign_extend_data" => LineInformation { + title: String::from("Floating-Point Data Register Value (Sign-Extended)"), + description: String::from("In the case where FpuRegWidth indicates a 32-bit width, this is the bottom 32 bits of the value from the \"Data\" register, then sign-extended to 64 bits."), + value: datapath_state.mips.coprocessor.state.sign_extend_data, + bits: 64, + }, + "funct" => LineInformation { + title: String::from("Instruction [5-0] (funct)"), + description: String::from("The funct field. Contains the type of operation to execute for R-type instructions."), + value: datapath_state.mips.state.funct as u64, + bits: 6, + }, + "imm" => LineInformation { + title: String::from("Instruction [15-0] (immediate)"), + description: String::from("The immediate field. Contains the 16-bit constant value used for I-type instructions."), + value: datapath_state.mips.state.imm as u64, + bits: 16, + }, + "instruction" => LineInformation { + title: String::from("Instruction"), + description: String::from("The currently-loaded instruction. This is broken down into different fields, where each field serves a different purpose in identifying what the instruction does."), + value: datapath_state.mips.state.instruction as u64, + bits: 32, + }, + "jump_address" => LineInformation { + title: String::from("Jump Address"), + description: String::from("The concatenation of the upper 36 bits of PC + 4 with the lower 26 bits of the instruction, shifted left by 2. This is used as the new PC value for J-type instructions."), + value: datapath_state.mips.state.jump_address, + bits: 64, + }, + "lower_26" => LineInformation { + title: String::from("Instruction [25-0]"), + description: String::from("The lower 26 bits of instruction. This is used as part of the new PC value for J-type instructions."), + value: datapath_state.mips.state.lower_26 as u64, + bits: 26, + }, + "lower_26_shifted_left_by_2" => LineInformation { + title: String::from("Instruction [25-0] << 2"), + description: String::from("The lower 26 bits of instruction, shifted left by 2. This is used as part of the new PC value for J-type instructions."), + value: datapath_state.mips.state.lower_26_shifted_left_by_2 as u64, + bits: 28, + }, + "mem_mux1_to_mem_mux2" => LineInformation { + title: String::from("Relative PC Address"), + description: String::from("Based on the control signals for branching and jumping, this address may be the next PC value. This is used for general non-branching instructions or branch-type instructions."), + value: datapath_state.mips.state.mem_mux1_to_mem_mux2, + bits: 64, + }, + "memory_data" => LineInformation { + title: String::from("Memory Data"), + description: String::from("The data retrieved from memory, given that the MemRead control signal is set. This may be 32 bits or 64 bits, depending on the RegWidth control signal."), + value: datapath_state.mips.state.memory_data, + bits: 64, + }, + "new_pc" => LineInformation { + title: String::from("New Program Counter"), + description: String::from("The address of the next instruction to execute. In other words, the next value of the program counter (PC) register."), + value: datapath_state.mips.state.new_pc, + bits: 64, + }, + "pc" => LineInformation { + title: String::from("Program Counter"), + description: String::from("The address of the currently-executing instruction."), + value: datapath_state.mips.registers.pc, + bits: 64, + }, + "pc_plus_4" => LineInformation { + title: String::from("PC + 4"), + description: String::from("The address of the currently-executing instruction, plus 4. By default, this will become the next value of the PC register. However, a different address may be used in the case of a branch or jump instruction."), + value: datapath_state.mips.state.pc_plus_4, + bits: 64, + }, + "pc_plus_4_upper" => LineInformation { + title: String::from("PC + 4 [63-28]"), + description: String::from("The upper 36 bits of PC + 4. This is to be concatenated with the lower 26 bits of the instruction to calculate a jump address."), + value: datapath_state.mips.state.pc_plus_4 & 0xffff_ffff_f000_0000 >> 28, + bits: 36, + }, + "ra_id" => LineInformation { + title: String::from("Return Address Register Index"), + description: String::from("The value 31. This represents the thirty-second register, the return address register ($ra)."), + value: 31, + bits: 5, + }, + "rd" => LineInformation { + title: String::from("Instruction [15-11] (rd)"), + description: String::from("The rd field. Depending on the RegDst control signal, this will be the register written to for an instruction. This register is used as the destination for most R-type instructions."), + value: datapath_state.mips.state.rd as u64, + bits: 5, + }, + "read_data_1" => LineInformation { + title: String::from("Read Data 1"), + description: String::from("Data retrieved from the register specified by the rs instruction field. Based on the instruction, this may be used as the first input to the ALU, or the next value of the PC register."), + value: datapath_state.mips.state.read_data_1, + bits: 64, + }, + "read_data_2" => LineInformation { + title: String::from("Read Data 2"), + description: String::from("Data retrieved from the register specified by the rt instruction field. Based on the instruction, this may be used as the second input to the ALU, data written to memory, or data transferred to the floating-point coprocessor."), + value: datapath_state.mips.state.read_data_2, + bits: 64, + }, + "register_write_data" => LineInformation { + title: String::from("Register Write Data"), + description: String::from("Data that will be written to a general-purpose register, given that RegWrite is set."), + value: datapath_state.mips.state.register_write_data, + bits: 64, + }, + "relative_pc_branch" => LineInformation { + title: String::from("Relative PC Branch Address"), + description: String::from("The relative address used in branch instructions. This is the sum of PC + 4 and the sign-extended immediate value, shifted left by 2."), + value: datapath_state.mips.state.relative_pc_branch, + bits: 64, + }, + "rs" => LineInformation { + title: String::from("Instruction [25-21] (rs)"), + description: String::from("The rs field. Contains the first register to be read for an instruction."), + value: datapath_state.mips.state.rs as u64, + bits: 5, + }, + "rt" => LineInformation { + title: String::from("Instruction [20-16] (rt)"), + description: String::from("The rt field. Contains the second register to be read for an instruction."), + value: datapath_state.mips.state.rt as u64, + bits: 5, + }, + "shamt" => LineInformation { + title: String::from("Instruction [10-6] (shamt)"), + description: String::from("The shamt (\"shift amount\") field. Specifies the number of bits to shift for those instructions that perform bit-shifting."), + value: datapath_state.mips.state.shamt as u64, + bits: 5, + }, + "sign_extend" => LineInformation { + title: String::from("Sign-Extended Immediate"), + description: String::from("The immediate field, sign-extended to a 64-bit value."), + value: datapath_state.mips.state.sign_extend, + bits: 64, + }, + "sign_extend_shift_left_by_2" => LineInformation { + title: String::from("Sign-Extended Immediate << 2"), + description: String::from("The immediate field, sign-extended to a 64-bit value, then shifted left by 2."), + value: datapath_state.mips.state.sign_extend_shift_left_by_2, + bits: 64, + }, + "write_data" => LineInformation { + title: String::from("Memory Write Data"), + description: String::from("Given that the MemWrite control signal is set, this data will be written to memory."), + value: datapath_state.mips.state.write_data, + bits: 64, + }, + "write_register" => LineInformation { + title: String::from("Write Register"), + description: String::from("The register that will be written to, assuming RegWrite is set. Depending on the RegDst control signal, this will consist of the rs, rt, or rd register, or 31 (indicating the $ra register)."), + value: datapath_state.mips.state.write_register_destination as u64, + bits: 5, + }, + "zero_extended_immediate" => LineInformation { + title: String::from("Zero-Extended Immediate"), + description: String::from("The immediate field, zero-extended to a 64-bit value."), + value: datapath_state.mips.state.imm as u64, + bits: 64, + }, + _ => LineInformation { + title: String::from("[Title]"), + description: String::from("[Description]"), + value: 0, + bits: 0, + }, + } +} diff --git a/src/emulation_core/riscv/line_info.rs b/src/emulation_core/riscv/line_info.rs index d17a5e319..4f28777c1 100644 --- a/src/emulation_core/riscv/line_info.rs +++ b/src/emulation_core/riscv/line_info.rs @@ -332,3 +332,314 @@ impl VisualDatapath for RiscDatapath { } } } + +pub fn visual_line_to_data(variable: &str, datapath_state: &UseReducerHandle) -> LineInformation { +// match variable { +// "alu_input2" => LineInformation { +// title: String::from("ALU Input 2"), +// description: String::from("The second input to the ALU. This is determined by the ALUSrc control signal to select between register data, a sign-extended and left-shifted immediate value, or a zero-extended immediate value."), +// value: datapath_state.riscv.state.alu_input2, +// bits: 64, +// }, +// "alu_result" => LineInformation { +// title: String::from("ALU Result"), +// description: String::from("The result of the calculation performed by the ALU. This is used either as an address to access memory or as a value that is saved into a register."), +// value: datapath_state.riscv.state.alu_result, +// bits: 64, +// }, +// "data_result" => LineInformation { +// title: String::from("Writeback Data"), +// description: String::from("After finishing processing the instruction, this will either be the ALU result, data from memory, or PC + 4, based on the MemToReg control signal. This data is saved into registers."), +// value: datapath_state.riscv.state.data_result, +// bits: 64, +// }, +// "fpu_alu_result" => LineInformation { +// title: String::from("Floating-Point ALU Result"), +// description: String::from("The result of the calculation performed by the floating-point ALU. This is used as an option to be written to a floating-point register, based on the DataWrite and FpuMemToReg control signals."), +// value: datapath_state.riscv.coprocessor.state.alu_result, +// bits: 64, +// }, +// "fpu_branch_decision" => LineInformation { +// title: String::from("FPU Branch Decision"), +// description: String::from("Based on the true/false branch flag, determines whether to branch. (The FpuBranch control signal must also be set.)"), +// value: datapath_state.riscv.coprocessor.state.condition_code_mux as u64, +// bits: 1, +// }, +// "fpu_branch_flag" => LineInformation { +// title: String::from("Instruction [16] (True/False Branch Flag)"), +// description: String::from("The true/false branch flag of branching coprocessor instructions. This flag specifies whether a floating-point branch instruction is BC1T or BC1F."), +// value: datapath_state.riscv.coprocessor.state.branch_flag as u64, +// bits: 1, +// }, +// "fpu_comparator_result" => LineInformation { +// title: String::from("Floating-Point Comparator Result"), +// description: String::from("The result of the comparison of two floating-point values. This is routed to the \"Condition Code\" (cc) register, and will be written there if the CcWrite control signal is set."), +// value: datapath_state.riscv.coprocessor.state.comparator_result, +// bits: 64, +// }, +// "fpu_condition_code" => LineInformation { +// title: String::from("Condition Code Value"), +// description: String::from("Data retrieved from the \"Condition Code\" (cc) register. This specifies whether a previous conditional instruction was true or false."), +// value: datapath_state.riscv.coprocessor.state.condition_code_bit as u64, +// bits: 1, +// }, +// "fpu_condition_code_inverted" => LineInformation { +// title: String::from("Condition Code Value (Inverted)"), +// description: String::from("Inverted form of the condition code register value."), +// value: datapath_state.riscv.coprocessor.state.condition_code_bit_inverted as u64, +// bits: 1, +// }, +// "fpu_data" => LineInformation { +// title: String::from("Floating-Point Data Register Value"), +// description: String::from("Data retrieved from the \"Data\" register. This register acts as a means to communicate data between the main processor and floating-point coprocessor in MTC1 and MFC1 instructions."), +// value: datapath_state.riscv.coprocessor.state.fmt as u64, +// bits: 64, +// }, +// "fpu_data_writeback" => LineInformation { +// title: String::from("Floating-Point Data Writeback"), +// description: String::from("The value from the floating-point unit's \"Data\" register. Depending on the FpuRegWidth control signal, this will be 64-bit data or sign-extended 32-bit data."), +// value: datapath_state.riscv.coprocessor.state.data_writeback, +// bits: 64, +// }, +// "fpu_destination" => LineInformation { +// title: String::from("Floating-Point Write Register"), +// description: String::from("The register that will be written to, assuming FpuRegWrite is set. Depending on the FpuRegDst control signal, this will consist of the fs, ft, or fd register."), +// value: datapath_state.riscv.coprocessor.state.destination as u64, +// bits: 5, +// }, +// "fpu_fd" => LineInformation { +// title: String::from("Instruction [10-6] (fd)"), +// description: String::from("The fd field. Depending on the FpuRegDst control signal, this will be the register written to in a floating-point operation. This register is used as the destination for most floating-point arithmetic instructions."), +// value: datapath_state.riscv.coprocessor.state.fd as u64, +// bits: 5, +// }, +// "fpu_fmt" => LineInformation { +// title: String::from("Instruction [25-21] (fmt)"), +// description: String::from("The fmt field. This is used to distinguish between single-precision and double-precision floating-point instructions."), +// value: datapath_state.riscv.coprocessor.state.fmt as u64, +// bits: 5, +// }, +// "fpu_fp_register_data_from_main_processor" => LineInformation { +// title: String::from("Writeback Data (To Floating-Point Coprocessor)"), +// description: String::from("This data is written to a floating-point register, given FpuMemToReg is set. This line allows data to load from memory to a floating-point register, specifically in the case of the LWC1 instruction."), +// value: datapath_state.riscv.coprocessor.state.fp_register_data_from_main_processor, +// bits: 64, +// }, +// "fpu_fp_register_to_memory" => LineInformation { +// title: String::from("Memory Write Data (from FPU)"), +// description: String::from("If the MemWriteSrc control signal is set, this data will be written to memory. This is used for the SWC1 instruction."), +// value: datapath_state.riscv.coprocessor.state.fp_register_to_memory, +// bits: 64, +// }, +// "fpu_fs" => LineInformation { +// title: String::from("Instruction [15-11] (fs)"), +// description: String::from("The fs field. Contains the first register to be read for a floating-point instruction."), +// value: datapath_state.riscv.coprocessor.state.fs as u64, +// bits: 5, +// }, +// "fpu_ft" => LineInformation { +// title: String::from("Instruction [20-16] (ft)"), +// description: String::from("The ft field. Contains the second register to be read for a floating-point instruction."), +// value: datapath_state.riscv.coprocessor.state.ft as u64, +// bits: 5, +// }, +// "fpu_new_data" => LineInformation { +// title: String::from("New Floating-Point Data Register Value"), +// description: String::from("Data sent to the \"Data\" register. Depending on the DataSrc control signal, this will either be data from the main processor or the floating-point coprocessor. This register acts as a means to communicate data between the main processor and floating-point coprocessor in MTC1 and MFC1 instructions."), +// value: datapath_state.riscv.coprocessor.state.fmt as u64, +// bits: 64, +// }, +// "fpu_read_data_1" => LineInformation { +// title: String::from("FPU Read Data 1"), +// description: String::from("Data retrieved from the register specified by the fs instruction field. This is used as the first inputs to the floating-point ALU and comparator. This can additionally be written to the \"Data\" register, based on the DataSrc and DataWrite control signals."), +// value: datapath_state.riscv.coprocessor.state.read_data_1, +// bits: 64, +// }, +// "fpu_read_data_2" => LineInformation { +// title: String::from("FPU Read Data 2"), +// description: String::from("Data retrieved from the register specified by the ft instruction field. This is used as the second inputs to the floating-point ALU and comparator. This can additionally be used as data to be written to memory, based on the MemWriteSrc control signal."), +// value: datapath_state.riscv.coprocessor.state.read_data_2, +// bits: 64, +// }, +// "fpu_register_write_data" => LineInformation { +// title: String::from("FPU Register Write Data"), +// description: String::from("Data that will be written to a floating-point register, given that FpuRegWrite is set."), +// value: datapath_state.riscv.coprocessor.state.register_write_data, +// bits: 64, +// }, +// "fpu_register_write_mux_to_mux" => LineInformation { +// title: String::from("FPU Register Write Data (When FpuMemToReg is Unset)"), +// description: String::from("Based on the DataWrite control signal, this will either be the result of the floating-point ALU or the contents of the \"Data\" register. (The \"Data\" register is used for transferring data between the processor and floating-point coprocessor.)"), +// value: datapath_state.riscv.coprocessor.state.register_write_mux_to_mux, +// bits: 64, +// }, +// "fpu_sign_extend_data" => LineInformation { +// title: String::from("Floating-Point Data Register Value (Sign-Extended)"), +// description: String::from("In the case where FpuRegWidth indicates a 32-bit width, this is the bottom 32 bits of the value from the \"Data\" register, then sign-extended to 64 bits."), +// value: datapath_state.riscv.coprocessor.state.sign_extend_data, +// bits: 64, +// }, +// "funct" => LineInformation { +// title: String::from("Instruction [5-0] (funct)"), +// description: String::from("The funct field. Contains the type of operation to execute for R-type instructions."), +// value: datapath_state.riscv.state.funct as u64, +// bits: 6, +// }, +// "imm" => LineInformation { +// title: String::from("Instruction [15-0] (immediate)"), +// description: String::from("The immediate field. Contains the 16-bit constant value used for I-type instructions."), +// value: datapath_state.riscv.state.imm as u64, +// bits: 16, +// }, +// "instruction" => LineInformation { +// title: String::from("Instruction"), +// description: String::from("The currently-loaded instruction. This is broken down into different fields, where each field serves a different purpose in identifying what the instruction does."), +// value: datapath_state.riscv.state.instruction as u64, +// bits: 32, +// }, +// "jump_address" => LineInformation { +// title: String::from("Jump Address"), +// description: String::from("The concatenation of the upper 36 bits of PC + 4 with the lower 26 bits of the instruction, shifted left by 2. This is used as the new PC value for J-type instructions."), +// value: datapath_state.riscv.state.jump_address, +// bits: 64, +// }, +// "lower_26" => LineInformation { +// title: String::from("Instruction [25-0]"), +// description: String::from("The lower 26 bits of instruction. This is used as part of the new PC value for J-type instructions."), +// value: datapath_state.riscv.state.lower_26 as u64, +// bits: 26, +// }, +// "lower_26_shifted_left_by_2" => LineInformation { +// title: String::from("Instruction [25-0] << 2"), +// description: String::from("The lower 26 bits of instruction, shifted left by 2. This is used as part of the new PC value for J-type instructions."), +// value: datapath_state.riscv.state.lower_26_shifted_left_by_2 as u64, +// bits: 28, +// }, +// "mem_mux1_to_mem_mux2" => LineInformation { +// title: String::from("Relative PC Address"), +// description: String::from("Based on the control signals for branching and jumping, this address may be the next PC value. This is used for general non-branching instructions or branch-type instructions."), +// value: datapath_state.riscv.state.mem_mux1_to_mem_mux2, +// bits: 64, +// }, +// "memory_data" => LineInformation { +// title: String::from("Memory Data"), +// description: String::from("The data retrieved from memory, given that the MemRead control signal is set. This may be 32 bits or 64 bits, depending on the RegWidth control signal."), +// value: datapath_state.riscv.state.memory_data, +// bits: 64, +// }, +// "new_pc" => LineInformation { +// title: String::from("New Program Counter"), +// description: String::from("The address of the next instruction to execute. In other words, the next value of the program counter (PC) register."), +// value: datapath_state.riscv.state.new_pc, +// bits: 64, +// }, +// "pc" => LineInformation { +// title: String::from("Program Counter"), +// description: String::from("The address of the currently-executing instruction."), +// value: datapath_state.riscv.registers.pc, +// bits: 64, +// }, +// "pc_plus_4" => LineInformation { +// title: String::from("PC + 4"), +// description: String::from("The address of the currently-executing instruction, plus 4. By default, this will become the next value of the PC register. However, a different address may be used in the case of a branch or jump instruction."), +// value: datapath_state.riscv.state.pc_plus_4, +// bits: 64, +// }, +// "pc_plus_4_upper" => LineInformation { +// title: String::from("PC + 4 [63-28]"), +// description: String::from("The upper 36 bits of PC + 4. This is to be concatenated with the lower 26 bits of the instruction to calculate a jump address."), +// value: datapath_state.riscv.state.pc_plus_4 & 0xffff_ffff_f000_0000 >> 28, +// bits: 36, +// }, +// "ra_id" => LineInformation { +// title: String::from("Return Address Register Index"), +// description: String::from("The value 31. This represents the thirty-second register, the return address register ($ra)."), +// value: 31, +// bits: 5, +// }, +// "rd" => LineInformation { +// title: String::from("Instruction [15-11] (rd)"), +// description: String::from("The rd field. Depending on the RegDst control signal, this will be the register written to for an instruction. This register is used as the destination for most R-type instructions."), +// value: datapath_state.riscv.state.rd as u64, +// bits: 5, +// }, +// "read_data_1" => LineInformation { +// title: String::from("Read Data 1"), +// description: String::from("Data retrieved from the register specified by the rs instruction field. Based on the instruction, this may be used as the first input to the ALU, or the next value of the PC register."), +// value: datapath_state.riscv.state.read_data_1, +// bits: 64, +// }, +// "read_data_2" => LineInformation { +// title: String::from("Read Data 2"), +// description: String::from("Data retrieved from the register specified by the rt instruction field. Based on the instruction, this may be used as the second input to the ALU, data written to memory, or data transferred to the floating-point coprocessor."), +// value: datapath_state.riscv.state.read_data_2, +// bits: 64, +// }, +// "register_write_data" => LineInformation { +// title: String::from("Register Write Data"), +// description: String::from("Data that will be written to a general-purpose register, given that RegWrite is set."), +// value: datapath_state.riscv.state.register_write_data, +// bits: 64, +// }, +// "relative_pc_branch" => LineInformation { +// title: String::from("Relative PC Branch Address"), +// description: String::from("The relative address used in branch instructions. This is the sum of PC + 4 and the sign-extended immediate value, shifted left by 2."), +// value: datapath_state.riscv.state.relative_pc_branch, +// bits: 64, +// }, +// "rs" => LineInformation { +// title: String::from("Instruction [25-21] (rs)"), +// description: String::from("The rs field. Contains the first register to be read for an instruction."), +// value: datapath_state.riscv.state.rs as u64, +// bits: 5, +// }, +// "rt" => LineInformation { +// title: String::from("Instruction [20-16] (rt)"), +// description: String::from("The rt field. Contains the second register to be read for an instruction."), +// value: datapath_state.riscv.state.rt as u64, +// bits: 5, +// }, +// "shamt" => LineInformation { +// title: String::from("Instruction [10-6] (shamt)"), +// description: String::from("The shamt (\"shift amount\") field. Specifies the number of bits to shift for those instructions that perform bit-shifting."), +// value: datapath_state.riscv.state.shamt as u64, +// bits: 5, +// }, +// "sign_extend" => LineInformation { +// title: String::from("Sign-Extended Immediate"), +// description: String::from("The immediate field, sign-extended to a 64-bit value."), +// value: datapath_state.riscv.state.sign_extend, +// bits: 64, +// }, +// "sign_extend_shift_left_by_2" => LineInformation { +// title: String::from("Sign-Extended Immediate << 2"), +// description: String::from("The immediate field, sign-extended to a 64-bit value, then shifted left by 2."), +// value: datapath_state.riscv.state.sign_extend_shift_left_by_2, +// bits: 64, +// }, +// "write_data" => LineInformation { +// title: String::from("Memory Write Data"), +// description: String::from("Given that the MemWrite control signal is set, this data will be written to memory."), +// value: datapath_state.riscv.state.write_data, +// bits: 64, +// }, +// "write_register" => LineInformation { +// title: String::from("Write Register"), +// description: String::from("The register that will be written to, assuming RegWrite is set. Depending on the RegDst control signal, this will consist of the rs, rt, or rd register, or 31 (indicating the $ra register)."), +// value: datapath_state.riscv.state.write_register_destination as u64, +// bits: 5, +// }, +// "zero_extended_immediate" => LineInformation { +// title: String::from("Zero-Extended Immediate"), +// description: String::from("The immediate field, zero-extended to a 64-bit value."), +// value: datapath_state.riscv.state.imm as u64, +// bits: 64, +// }, +// _ => LineInformation { +// title: String::from("[Title]"), +// description: String::from("[Description]"), +// value: 0, +// bits: 0, +// }, +// } +} \ No newline at end of file diff --git a/src/ui/footer/component.rs b/src/ui/footer/component.rs index 11da3beb7..60bcaac17 100644 --- a/src/ui/footer/component.rs +++ b/src/ui/footer/component.rs @@ -1,5 +1,4 @@ use crate::agent::datapath_communicator::DatapathCommunicator; -use crate::emulation_core::mips::datapath::MipsDatapath; use crate::ui::console::component::Console; use crate::ui::hex_editor::component::HexEditor; use crate::ui::visual_datapath::{DatapathSize, VisualDatapath}; @@ -8,11 +7,12 @@ use wasm_bindgen::JsCast; use web_sys::HtmlElement; use yew::prelude::*; use yew_hooks::prelude::*; +use crate::agent::datapath_reducer::DatapathReducer; #[derive(PartialEq, Properties)] pub struct Footerprops { pub communicator: &'static DatapathCommunicator, - pub datapath: MipsDatapath, + pub datapath_state: UseReducerHandle, pub parsermsg: String, pub show_input: UseStateHandle, pub command: UseStateHandle, @@ -93,7 +93,7 @@ pub fn footer(props: &Footerprops) -> Html {
} else if **active_tab == FooterTabState::Datapath {
- +
} else if **active_tab == FooterTabState::HexEditor {
diff --git a/src/ui/visual_datapath/mod.rs b/src/ui/visual_datapath/mod.rs index 3139d8e95..b0922a27d 100644 --- a/src/ui/visual_datapath/mod.rs +++ b/src/ui/visual_datapath/mod.rs @@ -33,13 +33,13 @@ use wasm_bindgen::{JsCast, JsValue}; use web_sys::{Element, Event, HtmlCollection, HtmlElement}; use yew::prelude::*; -use crate::emulation_core::mips::datapath::{MipsDatapath, Stage}; +use crate::{agent::datapath_reducer::DatapathReducer, emulation_core::{architectures::AvailableDatapaths, datapath::Datapath, mips::{coprocessor, datapath::{MipsDatapath, Stage}}}}; use consts::*; use utils::*; #[derive(PartialEq, Properties)] pub struct VisualDatapathProps { - pub datapath: MipsDatapath, + pub datapath_state: UseReducerHandle, /// A path to the location of the datapath SVG file. This path should be /// relative to the project root. @@ -105,7 +105,7 @@ impl Component for VisualDatapath { // there is actual data to view. A better way to see this is "when stage X is // set on the datapath, highlight the lines for stage Y." The datapath stage // tells where it will start the next time "execute" is pressed. - let current_stage = String::from(match ctx.props().datapath.current_stage { + let current_stage = String::from(match ctx.props().datapath_state.mips.current_stage { Stage::InstructionFetch => "writeback", Stage::InstructionDecode => "instruction_fetch", Stage::Execute => "instruction_decode", @@ -115,13 +115,13 @@ impl Component for VisualDatapath { debug!("Current stage: {:?}", current_stage); if first_render || self.should_reinitialize { - self.initialize(current_stage, ctx.props().datapath.clone()); + self.initialize(current_stage, ctx.props().datapath_state.clone()); self.should_reinitialize = false; } else { let result = Self::highlight_stage( &get_g_elements(), current_stage, - ctx.props().datapath.clone(), + &ctx.props().datapath_state.clone(), ); // Capture new event listeners. @@ -181,7 +181,7 @@ impl VisualDatapath { /// circumvented by creating an event listener on the `` element for the /// "load" event, which will guarantee when that virtual DOM is actually ready /// to be manipulated. - pub fn initialize(&mut self, current_stage: String, datapath: MipsDatapath) { + pub fn initialize(&mut self, current_stage: String, datapath_state: UseReducerHandle) { let on_load = Callback::from(move |_| { let nodes = get_g_elements(); @@ -210,7 +210,7 @@ impl VisualDatapath { }); } }); - Self::highlight_stage(&nodes, current_stage.clone(), datapath.clone()) + Self::highlight_stage(&nodes, current_stage.clone(), &datapath_state.clone()) }); let active_listeners = Rc::clone(&self.active_listeners); @@ -253,7 +253,7 @@ impl VisualDatapath { pub fn highlight_stage( nodes: &HtmlCollection, stage: String, - datapath: MipsDatapath, + datapath_state: &UseReducerHandle, ) -> Result, JsValue> { let mut active_listeners: Vec = vec![]; @@ -261,7 +261,7 @@ impl VisualDatapath { if element.has_attribute("data-stage") { let is_in_current_stage = element.get_attribute("data-stage").unwrap() == stage; if let Ok(listeners) = - Self::enable_interactivity(element, datapath.clone(), is_in_current_stage) + Self::enable_interactivity(element, datapath_state, is_in_current_stage) { for l in listeners { active_listeners.push(l); @@ -281,7 +281,7 @@ impl VisualDatapath { /// If successful, returns a [`Vec`] containing the newly created event listeners. pub fn enable_interactivity( element: &Element, - datapath: MipsDatapath, + datapath_state: &UseReducerHandle, is_active: bool, ) -> Result, JsValue> { // Color a line when hovering. @@ -300,39 +300,6 @@ impl VisualDatapath { } }); - // Show the popup when hovering. - let popup_on_mouseover = Callback::from(move |event: web_sys::Event| { - let event = event.unchecked_into::(); - - // Get relevant elements. - let target = event.target().unwrap().unchecked_into::(); - let popup = get_popup_element(); - - // Show popup. - let variable = target - .parent_element() - .unwrap() - .get_attribute("data-variable") - .unwrap_or_default(); - populate_popup_information(&datapath, &variable); - - // Calculate popup position. - let mouse_position = get_datapath_iframe_mouse_position(event); - let popup_size = (popup.offset_width(), popup.offset_height()); - let popup_position = - calculate_popup_position(mouse_position, popup_size, get_window_size()); - - popup - .style() - .set_property("left", &format!("{}px", popup_position.0)) - .ok(); - popup - .style() - .set_property("top", &format!("{}px", popup_position.1)) - .ok(); - popup.style().set_property("display", "block").ok(); - }); - // Move the popup if the mouse moves while still hovering. let popup_on_mousemove = Callback::from(move |event: Event| { let event = event.unchecked_into::(); @@ -396,10 +363,37 @@ impl VisualDatapath { color_on_mouseout.emit(event.clone()) }); - let popup_on_mouseover = popup_on_mouseover.clone(); + let datapath_state_ref = datapath_state.clone(); let popup_on_mouseover_listener = EventListener::new(&path, "mouseover", move |event| { - popup_on_mouseover.emit(event.clone()) + let event = event.clone().unchecked_into::(); + // Get relevant elements. + let target = event.target().unwrap().unchecked_into::(); + let popup = get_popup_element(); + + // Show popup. + let variable = target + .parent_element() + .unwrap() + .get_attribute("data-variable") + .unwrap_or_default(); + populate_popup_information(&datapath_state_ref, &variable); + + // Calculate popup position. + let mouse_position = get_datapath_iframe_mouse_position(event); + let popup_size = (popup.offset_width(), popup.offset_height()); + let popup_position = + calculate_popup_position(mouse_position, popup_size, get_window_size()); + + popup + .style() + .set_property("left", &format!("{}px", popup_position.0)) + .ok(); + popup + .style() + .set_property("top", &format!("{}px", popup_position.1)) + .ok(); + popup.style().set_property("display", "block").ok(); }); let popup_on_mousemove = popup_on_mousemove.clone(); diff --git a/src/ui/visual_datapath/utils.rs b/src/ui/visual_datapath/utils.rs index 38afb0046..3b8797079 100644 --- a/src/ui/visual_datapath/utils.rs +++ b/src/ui/visual_datapath/utils.rs @@ -3,8 +3,9 @@ use gloo::utils::{document, window}; use wasm_bindgen::JsCast; use web_sys::{Element, HtmlCollection, HtmlElement, HtmlObjectElement, MouseEvent}; +use yew::UseReducerHandle; -use crate::emulation_core::{datapath::VisualDatapath, mips::datapath::MipsDatapath}; +use crate::{agent::datapath_reducer::DatapathReducer, emulation_core::{self, architectures::AvailableDatapaths}}; use super::consts::*; @@ -138,7 +139,7 @@ where /// Parameters: /// - `datapath`: A reference to the datapath that information will be pulled from. /// - `variable`: The "variable" attribute of the line in the diagram that will have information. -pub fn populate_popup_information(datapath: &MipsDatapath, variable: &str) { +pub fn populate_popup_information(datapath_state: &UseReducerHandle, variable: &str) { let popup = get_popup_element(); let title = popup.query_selector(".title").unwrap().unwrap(); @@ -146,7 +147,17 @@ pub fn populate_popup_information(datapath: &MipsDatapath, variable: &str) { let bits = popup.query_selector(".data .code").unwrap().unwrap(); let meaning = popup.query_selector(".meaning").unwrap().unwrap(); - let information = datapath.visual_line_to_data(variable); + let information; + match datapath_state.current_architecture { + AvailableDatapaths::MIPS => { + information = emulation_core::mips::line_info::visual_line_to_data(variable, datapath_state); + }, + AvailableDatapaths::RISCV => { + // replace with RISC-V version + // information = emulation_core::riscv::line_info::visual_line_to_data(variable, datapath_state); + information = emulation_core::mips::line_info::visual_line_to_data(variable, datapath_state); + } + }; title.set_text_content(Some(&information.title)); description.set_text_content(Some(&information.description)); @@ -169,4 +180,4 @@ pub fn u64_to_bits(mut value: u64, bits: u64) -> String { output = output.chars().rev().collect::(); output -} +} \ No newline at end of file From 4853e97590b1e20ad64d3803e278180d076de281 Mon Sep 17 00:00:00 2001 From: Cay Date: Sun, 18 Feb 2024 18:53:31 -0500 Subject: [PATCH 098/355] Remove unused imports: --- src/ui/visual_datapath/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ui/visual_datapath/mod.rs b/src/ui/visual_datapath/mod.rs index b0922a27d..6d6ddad40 100644 --- a/src/ui/visual_datapath/mod.rs +++ b/src/ui/visual_datapath/mod.rs @@ -33,10 +33,11 @@ use wasm_bindgen::{JsCast, JsValue}; use web_sys::{Element, Event, HtmlCollection, HtmlElement}; use yew::prelude::*; -use crate::{agent::datapath_reducer::DatapathReducer, emulation_core::{architectures::AvailableDatapaths, datapath::Datapath, mips::{coprocessor, datapath::{MipsDatapath, Stage}}}}; use consts::*; use utils::*; +use crate::{agent::datapath_reducer::DatapathReducer, emulation_core::mips::datapath::Stage}; + #[derive(PartialEq, Properties)] pub struct VisualDatapathProps { pub datapath_state: UseReducerHandle, From f0818a42c342f5ff24f0a81c10b7331006cd3e7d Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Fri, 16 Feb 2024 18:48:57 -0500 Subject: [PATCH 099/355] Add new DatapathUpdateSignal struct for signalling updates to datapath information --- src/agent.rs | 11 ++++++++--- src/agent/datapath_communicator.rs | 3 --- src/emulation_core/datapath.rs | 30 +++++++++++++++++++++++++++-- src/emulation_core/mips/datapath.rs | 14 +++++++++----- 4 files changed, 45 insertions(+), 13 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index a93658f6a..da65042d7 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -2,7 +2,7 @@ use crate::agent::messages::{Command, MipsStateUpdate}; use crate::emulation_core::architectures::{DatapathRef, DatapathUpdate}; -use crate::emulation_core::datapath::Datapath; +use crate::emulation_core::datapath::{Datapath, DatapathUpdateSignal}; use crate::emulation_core::mips::datapath::MipsDatapath; use crate::emulation_core::mips::registers::GpRegisterType; use futures::{FutureExt, SinkExt, StreamExt}; @@ -71,6 +71,10 @@ pub async fn emulation_core_agent(scope: ReactorScope) struct EmulatorCoreAgentState { current_datapath: Box>, + /// The changes to the emulator core's memory/registers/etc. are tracked in this variable. When + /// it's time to send updates back to the main thread, this variable determines which updates + /// get sent. + pub updates: DatapathUpdateSignal, pub scope: ReactorScope, speed: u32, executing: bool, @@ -80,6 +84,7 @@ impl EmulatorCoreAgentState { pub fn new(scope: ReactorScope) -> EmulatorCoreAgentState { EmulatorCoreAgentState { current_datapath: Box::::default(), + updates: DatapathUpdateSignal::default(), scope, speed: 0, executing: false, @@ -107,10 +112,10 @@ impl EmulatorCoreAgentState { self.executing = true; } Command::ExecuteInstruction => { - self.current_datapath.execute_instruction(); + self.updates |= self.current_datapath.execute_instruction(); } Command::ExecuteStage => { - self.current_datapath.execute_stage(); + self.updates |= self.current_datapath.execute_stage(); } Command::Pause => { self.executing = false; diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index e2eb6bfac..ba81ccc5a 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -6,7 +6,6 @@ use futures::stream::{SplitSink, SplitStream}; use futures::FutureExt; use futures::SinkExt; use futures::StreamExt; -use gloo_console::log; use gloo_console::warn; use std::cell::RefCell; use yew::UseReducerDispatcher; @@ -60,9 +59,7 @@ impl DatapathCommunicator { }; loop { - log!("Waiting..."); let update = reader.next().await; - log!(format!("Got update {:?}", update)); match update { None => return, Some(update) => dispatcher_handle.dispatch(update), diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index 0d73035fc..fcc2490f7 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -3,6 +3,7 @@ use crate::emulation_core::architectures::DatapathRef; use crate::emulation_core::mips::line_info::LineInformation; use crate::emulation_core::mips::memory::Memory; +use std::ops::BitOrAssign; /// A generic datapath. /// @@ -31,13 +32,13 @@ pub trait Datapath { /// midway through a stage, the current instruction will be finished /// instead of executing a new instruction. Should the datapath be in /// a "halted" state, behavior is undefined. - fn execute_instruction(&mut self); + fn execute_instruction(&mut self) -> DatapathUpdateSignal; /// Execute a single stage of execution based on the current state of /// the datapath. Should the datapath not support stages, assume the /// same behavior as [`Self::execute_instruction()`]. Should the /// datapath be in a "halted" state, behavior is undefined. - fn execute_stage(&mut self); + fn execute_stage(&mut self) -> DatapathUpdateSignal; /// Retrieve the data in the register indicated by the provided enum. /// It can be assumed valid data will be retrieved since any valid @@ -79,3 +80,28 @@ pub trait VisualDatapath { /// part of the visual datapath diagram. fn visual_line_to_data(&self, variable: &str) -> LineInformation; } + +/// Struct used for signalling the results of execution. This can then be used to determine which +/// additional actions the emulator core thread needs to perform after it executes a cycle/stage. +#[derive(Default, Debug, Copy, Clone, PartialEq)] +pub struct DatapathUpdateSignal { + pub changed_state: bool, + pub changed_registers: bool, + pub changed_coprocessor_state: bool, + pub changed_coprocessor_registers: bool, + pub changed_memory: bool, + pub hit_syscall: bool, + pub hit_breakpoint: bool, +} + +impl BitOrAssign for DatapathUpdateSignal { + fn bitor_assign(&mut self, rhs: Self) { + self.changed_state |= rhs.changed_state; + self.changed_registers |= rhs.changed_registers; + self.changed_coprocessor_state |= rhs.changed_coprocessor_state; + self.changed_coprocessor_registers |= rhs.changed_coprocessor_registers; + self.changed_memory |= rhs.changed_memory; + self.hit_syscall |= rhs.hit_syscall; + self.hit_breakpoint |= rhs.hit_breakpoint; + } +} diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index 7eca803f6..015f3b62b 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -53,6 +53,7 @@ use super::datapath_signals::*; use super::instruction::*; use super::{coprocessor::MipsFpCoprocessor, memory::Memory, registers::GpRegisters}; use crate::emulation_core::architectures::DatapathRef; +use crate::emulation_core::datapath::DatapathUpdateSignal; use serde::{Deserialize, Serialize}; /// An implementation of a datapath for the MIPS64 ISA. @@ -225,14 +226,15 @@ impl Datapath for MipsDatapath { type RegisterData = u64; type RegisterEnum = super::registers::GpRegisterType; - fn execute_instruction(&mut self) { + fn execute_instruction(&mut self) -> DatapathUpdateSignal { + let mut result_signals = DatapathUpdateSignal::default(); loop { // Stop early if the datapath has halted. if self.is_halted { break; } - self.execute_stage(); + result_signals |= self.execute_stage(); // This instruction is finished when the datapath has returned // to the IF stage. @@ -240,12 +242,13 @@ impl Datapath for MipsDatapath { break; } } + result_signals } - fn execute_stage(&mut self) { + fn execute_stage(&mut self) -> DatapathUpdateSignal { // If the datapath is halted, do nothing. if self.is_halted { - return; + return DatapathUpdateSignal::default(); } match self.current_stage { @@ -254,7 +257,7 @@ impl Datapath for MipsDatapath { Stage::Execute => self.stage_execute(), Stage::Memory => self.stage_memory(), Stage::WriteBack => self.stage_writeback(), - } + }; // If the FPU has halted, reflect this in the main unit. if self.coprocessor.is_halted { @@ -262,6 +265,7 @@ impl Datapath for MipsDatapath { } self.current_stage = Stage::get_next_stage(self.current_stage); + DatapathUpdateSignal::default() } fn get_register_by_enum(&self, register: Self::RegisterEnum) -> u64 { From 8052bf1907b1cae19e70c2a119fc489af9f2e4aa Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 22 Feb 2024 14:37:16 -0500 Subject: [PATCH 100/355] Implement update signaling for the MIPS datapath --- src/emulation_core/mips/datapath.rs | 48 ++++++++++++++++++++++++----- src/parser/parser_assembler_main.rs | 6 ++-- 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index 015f3b62b..2fbfdd33a 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -251,7 +251,7 @@ impl Datapath for MipsDatapath { return DatapathUpdateSignal::default(); } - match self.current_stage { + let res = match self.current_stage { Stage::InstructionFetch => self.stage_instruction_fetch(), Stage::InstructionDecode => self.stage_instruction_decode(), Stage::Execute => self.stage_execute(), @@ -265,7 +265,7 @@ impl Datapath for MipsDatapath { } self.current_stage = Stage::get_next_stage(self.current_stage); - DatapathUpdateSignal::default() + res } fn get_register_by_enum(&self, register: Self::RegisterEnum) -> u64 { @@ -338,13 +338,19 @@ impl MipsDatapath { /// /// Fetch the current instruction based on the given PC and load it /// into the datapath. - fn stage_instruction_fetch(&mut self) { + fn stage_instruction_fetch(&mut self) -> DatapathUpdateSignal { self.instruction_fetch(); // Upper part of datapath, PC calculation self.pc_plus_4(); self.coprocessor.set_instruction(self.state.instruction); + + // PC always updates in this function, therefore registers need to be updated on the UI + DatapathUpdateSignal { + changed_registers: true, + ..Default::default() + } } /// Stage 2 of 5: Instruction Decode (ID) @@ -353,7 +359,7 @@ impl MipsDatapath { /// /// If the instruction is determined to be a `syscall`, immediately /// finish the instruction and set the `is_halted` flag. - fn stage_instruction_decode(&mut self) { + fn stage_instruction_decode(&mut self) -> DatapathUpdateSignal { self.instruction_decode(); self.sign_extend(); self.set_control_signals(); @@ -372,22 +378,34 @@ impl MipsDatapath { if let Instruction::SyscallType(_) = self.instruction { self.is_halted = true; } + + // Instruction decode always involves a state update + DatapathUpdateSignal { + changed_state: true, + ..Default::default() + } } /// Stage 3 of 5: Execute (EX) /// /// Execute the current instruction with some arithmetic operation. - fn stage_execute(&mut self) { + fn stage_execute(&mut self) -> DatapathUpdateSignal { self.alu(); self.calc_relative_pc_branch(); self.calc_cpu_branch_signal(); self.coprocessor.stage_execute(); + + DatapathUpdateSignal { + changed_state: true, + changed_coprocessor_state: true, + ..Default::default() + } } /// Stage 4 of 5: Memory (MEM) /// /// Read or write to memory. - fn stage_memory(&mut self) { + fn stage_memory(&mut self) -> DatapathUpdateSignal { if let MemRead::YesRead = self.signals.mem_read { self.memory_read(); } @@ -410,18 +428,34 @@ impl MipsDatapath { self.calc_general_branch_signal(); self.pick_pc_plus_4_or_relative_branch_addr_mux1(); self.set_new_pc_mux2(); + + DatapathUpdateSignal { + changed_state: true, + changed_memory: self.signals.mem_write == MemWrite::YesWrite, + changed_coprocessor_state: true, + ..Default::default() + } } /// Stage 5 of 5: Writeback (WB) /// /// Write the result of the instruction's operation to a register, /// if desired. Additionally, set the PC for the next instruction. - fn stage_writeback(&mut self) { + fn stage_writeback(&mut self) -> DatapathUpdateSignal { self.coprocessor .set_fp_register_data_from_main_processor(self.state.data_result); self.register_write(); self.set_pc(); self.coprocessor.stage_writeback(); + + DatapathUpdateSignal { + changed_state: true, + changed_coprocessor_state: true, + changed_registers: self.signals.reg_write != RegWrite::NoWrite, + changed_coprocessor_registers: self.coprocessor.signals.fpu_reg_write + != FpuRegWrite::NoWrite, + ..Default::default() + } } // ================== Instruction Fetch (IF) ================== diff --git a/src/parser/parser_assembler_main.rs b/src/parser/parser_assembler_main.rs index 4a04a7c81..b345be4ea 100644 --- a/src/parser/parser_assembler_main.rs +++ b/src/parser/parser_assembler_main.rs @@ -56,7 +56,8 @@ pub fn parser(file_string: String) -> (ProgramInfo, Vec) { &mut program_info.monaco_line_info, ); - let (binary, data_starting_point) = create_binary_vec(program_info.instructions.clone(), vec_of_data); + let (binary, data_starting_point) = + create_binary_vec(program_info.instructions.clone(), vec_of_data); for entry in &program_info.monaco_line_info { program_info @@ -115,7 +116,8 @@ pub fn parser(file_string: String) -> (ProgramInfo, Vec) { &mut program_info.monaco_line_info, ); - let (binary, data_starting_point) = create_binary_vec(program_info.instructions.clone(), vec_of_data); + let (binary, data_starting_point) = + create_binary_vec(program_info.instructions.clone(), vec_of_data); for entry in &program_info.monaco_line_info { program_info From 7fdb1822a732e9a365a22371c9fabb0ad0dd7881 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 22 Feb 2024 14:48:46 -0500 Subject: [PATCH 101/355] Use the spread operator to make the reducer code slightly cleaner --- src/agent/datapath_reducer.rs | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/agent/datapath_reducer.rs b/src/agent/datapath_reducer.rs index 63bfc7902..808ec3638 100644 --- a/src/agent/datapath_reducer.rs +++ b/src/agent/datapath_reducer.rs @@ -13,7 +13,7 @@ pub struct DatapathReducer { pub mips: MipsCoreState, } -#[derive(Default, PartialEq)] +#[derive(Default, PartialEq, Clone)] pub struct MipsCoreState { pub state: DatapathState, pub registers: GpRegisters, @@ -40,27 +40,19 @@ impl Reducible for DatapathReducer { mips: match update { MipsStateUpdate::UpdateState(state) => MipsCoreState { state, - registers: self.mips.registers, - memory: self.mips.memory.clone(), - current_stage: self.mips.current_stage, + ..self.mips.clone() }, MipsStateUpdate::UpdateRegisters(registers) => MipsCoreState { - state: self.mips.state.clone(), registers, - memory: self.mips.memory.clone(), - current_stage: self.mips.current_stage, + ..self.mips.clone() }, MipsStateUpdate::UpdateMemory(memory) => MipsCoreState { - state: self.mips.state.clone(), - registers: self.mips.registers, memory, - current_stage: self.mips.current_stage, + ..self.mips.clone() }, MipsStateUpdate::UpdateStage(stage) => MipsCoreState { - state: self.mips.state.clone(), - registers: self.mips.registers, - memory: self.mips.memory.clone(), current_stage: stage, + ..self.mips.clone() }, }, }, From 123d9aae117a064feb970dc8576a8294b60ade4d Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 22 Feb 2024 15:05:05 -0500 Subject: [PATCH 102/355] Add coprocessor state and register updates --- src/agent.rs | 8 ++++++++ src/agent/datapath_reducer.rs | 13 +++++++++++++ src/agent/messages.rs | 3 +++ src/bin/main.rs | 2 +- src/emulation_core/mips/coprocessor.rs | 3 ++- 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index da65042d7..a1058fb9c 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -56,12 +56,20 @@ pub async fn emulation_core_agent(scope: ReactorScope) DatapathUpdate::MIPS(MipsStateUpdate::UpdateState(datapath.state.clone())); let register_update = DatapathUpdate::MIPS(MipsStateUpdate::UpdateRegisters(datapath.registers)); + let coprocessor_state = DatapathUpdate::MIPS( + MipsStateUpdate::UpdateCoprocessorState(datapath.coprocessor.state.clone()), + ); + let coprocessor_registers = DatapathUpdate::MIPS( + MipsStateUpdate::UpdateCoprocessorRegisters(datapath.coprocessor.fpr), + ); let memory_update = DatapathUpdate::MIPS(MipsStateUpdate::UpdateMemory(datapath.memory.clone())); let stage_update = DatapathUpdate::MIPS(MipsStateUpdate::UpdateStage(datapath.current_stage)); state.scope.send(state_update).await.unwrap(); state.scope.send(register_update).await.unwrap(); + state.scope.send(coprocessor_state).await.unwrap(); + state.scope.send(coprocessor_registers).await.unwrap(); state.scope.send(memory_update).await.unwrap(); state.scope.send(stage_update).await.unwrap(); } diff --git a/src/agent/datapath_reducer.rs b/src/agent/datapath_reducer.rs index 808ec3638..1eb4c7c53 100644 --- a/src/agent/datapath_reducer.rs +++ b/src/agent/datapath_reducer.rs @@ -1,6 +1,7 @@ use crate::agent::messages::MipsStateUpdate; use crate::emulation_core::architectures::AvailableDatapaths::MIPS; use crate::emulation_core::architectures::{AvailableDatapaths, DatapathUpdate}; +use crate::emulation_core::mips::coprocessor::FpuState; use crate::emulation_core::mips::datapath::{DatapathState, Stage}; use crate::emulation_core::mips::memory::Memory; use crate::emulation_core::mips::registers::GpRegisters; @@ -17,6 +18,8 @@ pub struct DatapathReducer { pub struct MipsCoreState { pub state: DatapathState, pub registers: GpRegisters, + pub coprocessor_state: FpuState, + pub coprocessor_registers: [u64; 32], pub memory: Memory, pub current_stage: Stage, } @@ -46,6 +49,16 @@ impl Reducible for DatapathReducer { registers, ..self.mips.clone() }, + MipsStateUpdate::UpdateCoprocessorState(coprocessor_state) => MipsCoreState { + coprocessor_state, + ..self.mips.clone() + }, + MipsStateUpdate::UpdateCoprocessorRegisters(coprocessor_registers) => { + MipsCoreState { + coprocessor_registers, + ..self.mips.clone() + } + } MipsStateUpdate::UpdateMemory(memory) => MipsCoreState { memory, ..self.mips.clone() diff --git a/src/agent/messages.rs b/src/agent/messages.rs index 664c2deaa..f2b9db0df 100644 --- a/src/agent/messages.rs +++ b/src/agent/messages.rs @@ -1,3 +1,4 @@ +use crate::emulation_core::mips::coprocessor::FpuState; use crate::emulation_core::mips::datapath::DatapathState; use crate::emulation_core::mips::memory::Memory; use crate::emulation_core::mips::registers::GpRegisters; @@ -24,6 +25,8 @@ pub enum Command { pub enum MipsStateUpdate { UpdateState(DatapathState), UpdateRegisters(GpRegisters), + UpdateCoprocessorState(FpuState), + UpdateCoprocessorRegisters([u64; 32]), UpdateMemory(Memory), UpdateStage(Stage), } diff --git a/src/bin/main.rs b/src/bin/main.rs index 011ea91d2..ad143966f 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -526,7 +526,7 @@ fn app(props: &AppProps) -> Html { // Right column - + } diff --git a/src/emulation_core/mips/coprocessor.rs b/src/emulation_core/mips/coprocessor.rs index c0c40fe85..06ba90991 100644 --- a/src/emulation_core/mips/coprocessor.rs +++ b/src/emulation_core/mips/coprocessor.rs @@ -3,6 +3,7 @@ use super::constants::*; use super::control_signals::floating_point::*; use super::instruction::Instruction; +use serde::{Deserialize, Serialize}; /// An implementation of a floating-point coprocessor for the MIPS64 ISA. /// @@ -20,7 +21,7 @@ pub struct MipsFpCoprocessor { pub data: u64, } -#[derive(Clone, Default, PartialEq)] +#[derive(Clone, Default, PartialEq, Serialize, Deserialize, Debug)] pub struct FpuState { pub instruction: u32, pub op: u32, From 8beca5cfc23896448625cdbd3245c87e38fe0933 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 22 Feb 2024 15:32:35 -0500 Subject: [PATCH 103/355] Only send necessary updates back to the UI thread --- src/agent.rs | 76 ++++++++++++++++++++++++---------- src/emulation_core/datapath.rs | 12 ++++++ 2 files changed, 66 insertions(+), 22 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index a1058fb9c..6b72e919c 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -1,8 +1,9 @@ //! The agent responsible for running the emulator core on the worker thread and communication functionalities. -use crate::agent::messages::{Command, MipsStateUpdate}; +use crate::agent::messages::Command; +use crate::agent::messages::MipsStateUpdate::*; use crate::emulation_core::architectures::{DatapathRef, DatapathUpdate}; -use crate::emulation_core::datapath::{Datapath, DatapathUpdateSignal}; +use crate::emulation_core::datapath::{Datapath, DatapathUpdateSignal, UPDATE_EVERYTHING}; use crate::emulation_core::mips::datapath::MipsDatapath; use crate::emulation_core::mips::registers::GpRegisterType; use futures::{FutureExt, SinkExt, StreamExt}; @@ -52,26 +53,52 @@ pub async fn emulation_core_agent(scope: ReactorScope) // TODO: Add support for the FP coprocessor updates in MIPS match state.current_datapath.as_datapath_ref() { DatapathRef::MIPS(datapath) => { - let state_update = - DatapathUpdate::MIPS(MipsStateUpdate::UpdateState(datapath.state.clone())); - let register_update = - DatapathUpdate::MIPS(MipsStateUpdate::UpdateRegisters(datapath.registers)); - let coprocessor_state = DatapathUpdate::MIPS( - MipsStateUpdate::UpdateCoprocessorState(datapath.coprocessor.state.clone()), - ); - let coprocessor_registers = DatapathUpdate::MIPS( - MipsStateUpdate::UpdateCoprocessorRegisters(datapath.coprocessor.fpr), - ); - let memory_update = - DatapathUpdate::MIPS(MipsStateUpdate::UpdateMemory(datapath.memory.clone())); - let stage_update = - DatapathUpdate::MIPS(MipsStateUpdate::UpdateStage(datapath.current_stage)); - state.scope.send(state_update).await.unwrap(); - state.scope.send(register_update).await.unwrap(); - state.scope.send(coprocessor_state).await.unwrap(); - state.scope.send(coprocessor_registers).await.unwrap(); - state.scope.send(memory_update).await.unwrap(); - state.scope.send(stage_update).await.unwrap(); + // Stage always updates + state + .scope + .send(DatapathUpdate::MIPS(UpdateStage(datapath.current_stage))) + .await + .unwrap(); + + if state.updates.changed_state { + state + .scope + .send(DatapathUpdate::MIPS(UpdateState(datapath.state.clone()))) + .await + .unwrap(); + } + if state.updates.changed_registers { + state + .scope + .send(DatapathUpdate::MIPS(UpdateRegisters(datapath.registers))) + .await + .unwrap(); + } + if state.updates.changed_coprocessor_state { + state + .scope + .send(DatapathUpdate::MIPS(UpdateCoprocessorState( + datapath.coprocessor.state.clone(), + ))) + .await + .unwrap(); + } + if state.updates.changed_coprocessor_registers { + state + .scope + .send(DatapathUpdate::MIPS(UpdateCoprocessorRegisters( + datapath.coprocessor.fpr, + ))) + .await + .unwrap(); + } + if state.updates.changed_memory { + state + .scope + .send(DatapathUpdate::MIPS(UpdateMemory(datapath.memory.clone()))) + .await + .unwrap(); + } } } } @@ -106,15 +133,19 @@ impl EmulatorCoreAgentState { } Command::Initialize(initial_pc, mem) => { self.current_datapath.initialize(initial_pc, mem).unwrap(); + self.updates.changed_memory = true; + self.updates.changed_registers = true; } Command::SetExecuteSpeed(speed) => { self.speed = speed; } Command::SetRegister(register, value) => { self.current_datapath.set_register_by_str(®ister, value); + self.updates.changed_registers = true; } Command::SetMemory(ptr, data) => { self.current_datapath.set_memory(ptr, data); + self.updates.changed_memory = true; } Command::Execute => { self.executing = true; @@ -130,6 +161,7 @@ impl EmulatorCoreAgentState { } Command::Reset => { self.current_datapath.reset(); + self.updates |= UPDATE_EVERYTHING; } } } diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index fcc2490f7..677c18fcb 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -94,6 +94,18 @@ pub struct DatapathUpdateSignal { pub hit_breakpoint: bool, } +/// Constant used to easily trigger an update for everything but to avoid triggering any other +/// execution (i.e. breakpoints or syscalls). +pub const UPDATE_EVERYTHING: DatapathUpdateSignal = DatapathUpdateSignal { + changed_state: true, + changed_registers: true, + changed_coprocessor_state: true, + changed_coprocessor_registers: true, + changed_memory: true, + hit_syscall: false, + hit_breakpoint: false, +}; + impl BitOrAssign for DatapathUpdateSignal { fn bitor_assign(&mut self, rhs: Self) { self.changed_state |= rhs.changed_state; From 3aaa642fab07deb9fe4583f5aafae54a4e5df7f6 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Thu, 22 Feb 2024 16:25:05 -0500 Subject: [PATCH 104/355] Avoid some of the repetition in the updates checking/sending loop --- src/agent.rs | 90 +++++++++++++++++++++++++--------------------------- 1 file changed, 44 insertions(+), 46 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index 6b72e919c..7930a6de9 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -16,6 +16,23 @@ pub mod datapath_communicator; pub mod datapath_reducer; pub mod messages; +macro_rules! send_update { + ($scope:expr, $condition:expr, $value:expr) => { + if $condition { + $scope + .send($value) + .await + .expect("ReactorScope's send() function should not fail.") + } + }; +} + +macro_rules! send_update_mips { + ($scope:expr, $cond:expr, $data:expr) => { + send_update!($scope, $cond, DatapathUpdate::MIPS($data)) + }; +} + /// The main logic for the emulation core agent. All code within this function runs on a worker thread as opposed to /// the UI thread. #[reactor(EmulationCoreAgent)] @@ -49,56 +66,37 @@ pub async fn emulation_core_agent(scope: ReactorScope) state.execute(); // Part 3: Processing State/Sending Updates to UI - // TODO: This is a very naive implementation. Optimization is probably a good idea. - // TODO: Add support for the FP coprocessor updates in MIPS match state.current_datapath.as_datapath_ref() { DatapathRef::MIPS(datapath) => { // Stage always updates - state - .scope - .send(DatapathUpdate::MIPS(UpdateStage(datapath.current_stage))) - .await - .unwrap(); + send_update_mips!(state.scope, true, UpdateStage(datapath.current_stage)); - if state.updates.changed_state { - state - .scope - .send(DatapathUpdate::MIPS(UpdateState(datapath.state.clone()))) - .await - .unwrap(); - } - if state.updates.changed_registers { - state - .scope - .send(DatapathUpdate::MIPS(UpdateRegisters(datapath.registers))) - .await - .unwrap(); - } - if state.updates.changed_coprocessor_state { - state - .scope - .send(DatapathUpdate::MIPS(UpdateCoprocessorState( - datapath.coprocessor.state.clone(), - ))) - .await - .unwrap(); - } - if state.updates.changed_coprocessor_registers { - state - .scope - .send(DatapathUpdate::MIPS(UpdateCoprocessorRegisters( - datapath.coprocessor.fpr, - ))) - .await - .unwrap(); - } - if state.updates.changed_memory { - state - .scope - .send(DatapathUpdate::MIPS(UpdateMemory(datapath.memory.clone()))) - .await - .unwrap(); - } + // Send all other updates based on the state.updates variable. + send_update_mips!( + state.scope, + state.updates.changed_state, + UpdateState(datapath.state.clone()) + ); + send_update_mips!( + state.scope, + state.updates.changed_registers, + UpdateRegisters(datapath.registers) + ); + send_update_mips!( + state.scope, + state.updates.changed_coprocessor_state, + UpdateCoprocessorState(datapath.coprocessor.state.clone()) + ); + send_update_mips!( + state.scope, + state.updates.changed_coprocessor_registers, + UpdateCoprocessorRegisters(datapath.coprocessor.fpr) + ); + send_update_mips!( + state.scope, + state.updates.changed_memory, + UpdateMemory(datapath.memory.clone()) + ); } } } From 800fb938e0358d2a97176b963040355650eeeff2 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Tue, 27 Feb 2024 18:51:37 -0500 Subject: [PATCH 105/355] Fix agent sending updates on every cycle --- src/agent.rs | 2 ++ src/emulation_core/mips/datapath.rs | 10 ++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index 7930a6de9..dc6b4d355 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -68,6 +68,7 @@ pub async fn emulation_core_agent(scope: ReactorScope) // Part 3: Processing State/Sending Updates to UI match state.current_datapath.as_datapath_ref() { DatapathRef::MIPS(datapath) => { + log!(format!("Updates: {:?}", state.updates)); // Stage always updates send_update_mips!(state.scope, true, UpdateStage(datapath.current_stage)); @@ -99,6 +100,7 @@ pub async fn emulation_core_agent(scope: ReactorScope) ); } } + state.updates = Default::default(); } } diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index 2fbfdd33a..4b8d19a7f 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -346,9 +346,10 @@ impl MipsDatapath { self.coprocessor.set_instruction(self.state.instruction); - // PC always updates in this function, therefore registers need to be updated on the UI + // Both state and coprocessor state always update DatapathUpdateSignal { - changed_registers: true, + changed_state: true, + changed_coprocessor_state: true, ..Default::default() } } @@ -382,6 +383,7 @@ impl MipsDatapath { // Instruction decode always involves a state update DatapathUpdateSignal { changed_state: true, + changed_coprocessor_state: true, ..Default::default() } } @@ -451,9 +453,9 @@ impl MipsDatapath { DatapathUpdateSignal { changed_state: true, changed_coprocessor_state: true, - changed_registers: self.signals.reg_write != RegWrite::NoWrite, + changed_registers: true, // Always true because pc always gets updated changed_coprocessor_registers: self.coprocessor.signals.fpu_reg_write - != FpuRegWrite::NoWrite, + == FpuRegWrite::YesWrite, ..Default::default() } } From 99ae4530ecb3c8fde80133f6adad1ab134df0a60 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Tue, 27 Feb 2024 19:23:49 -0500 Subject: [PATCH 106/355] Return the appropriate DatapathStateUpdate when hitting a syscall --- src/emulation_core/mips/datapath.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index 4b8d19a7f..5793de350 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -384,6 +384,7 @@ impl MipsDatapath { DatapathUpdateSignal { changed_state: true, changed_coprocessor_state: true, + hit_syscall: matches!(self.instruction, Instruction::SyscallType(_)), ..Default::default() } } From caa0b8cd70cd929bcc938ad6f60f9b507b22e331 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Tue, 27 Feb 2024 21:54:07 -0500 Subject: [PATCH 107/355] Add functions to Datapath to extract syscall arguments from registers --- src/emulation_core/datapath.rs | 73 +++++++++++++++++++++++++++++ src/emulation_core/mips/datapath.rs | 12 ++++- 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index 677c18fcb..269fb64f2 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -1,6 +1,10 @@ //! Module for the API of a generic datapath. use crate::emulation_core::architectures::DatapathRef; +use crate::emulation_core::datapath::Syscall::{ + Exit, PrintDouble, PrintFloat, PrintInt, PrintString, ReadDouble, ReadFloat, ReadInt, + ReadString, +}; use crate::emulation_core::mips::line_info::LineInformation; use crate::emulation_core::mips::memory::Memory; use std::ops::BitOrAssign; @@ -69,6 +73,10 @@ pub trait Datapath { /// Obtain a reference to the concrete datapath type. Used when datapath-specific logic is /// needed while dealing with a datapath as a trait object. fn as_datapath_ref(&self) -> DatapathRef; + + /// Returns the type of syscall and its arguments (if any exist for that syscall). See the + /// syscall enum for a list of syscalls and what they do. + fn get_syscall_arguments(&self) -> Syscall; } /// A datapath that supports a visual diagram component. @@ -81,6 +89,71 @@ pub trait VisualDatapath { fn visual_line_to_data(&self, variable: &str) -> LineInformation; } +/// Enum describing all syscalls that can be executed. The register used for indicating the syscall +/// (and its argument) is different for each architecture. +pub enum Syscall { + /// Halts the emulator core. This should generally be the default syscall if the syscall number + /// does not match any of the other variants. + /// + /// Call number: 0 + Exit, + /// Prints the integer value of the argument register. + /// + /// Call number: 1 + PrintInt(u64), + /// Prints the float value of the argument register. + /// + /// Call number: 2 + PrintFloat(f32), + /// Prints the double value of the argument register. + /// + /// Call number: 3 + PrintDouble(f64), + /// Prints a string to console, starting at the memory address in the argument and ending at a + /// null byte. + /// + /// Call number: 4 + PrintString(u64), + /// Reads the next int from the console. + /// + /// Call number: 5 + ReadInt, + /// Reads the next double from the console. + /// + /// Call number: 6 + ReadFloat, + /// Reads the next float from the console. + /// + /// Call number 7 + ReadDouble, + /// Reads from the console until a newline character and stores it at the provided memory + /// address with a null terminator. + /// + /// Call number 8 + ReadString(u64), +} + +impl Syscall { + pub fn from_register_data( + syscall: u64, + integer_arg: u64, + float_arg: f32, + double_arg: f64, + ) -> Syscall { + match syscall { + 1 => PrintInt(integer_arg), + 2 => PrintFloat(float_arg), + 3 => PrintDouble(double_arg), + 4 => PrintString(integer_arg), + 5 => ReadInt, + 6 => ReadFloat, + 7 => ReadDouble, + 8 => ReadString(integer_arg), + _ => Exit, + } + } +} + /// Struct used for signalling the results of execution. This can then be used to determine which /// additional actions the emulator core thread needs to perform after it executes a cycle/stage. #[derive(Default, Debug, Copy, Clone, PartialEq)] diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index 5793de350..1f3b09b92 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -53,7 +53,8 @@ use super::datapath_signals::*; use super::instruction::*; use super::{coprocessor::MipsFpCoprocessor, memory::Memory, registers::GpRegisters}; use crate::emulation_core::architectures::DatapathRef; -use crate::emulation_core::datapath::DatapathUpdateSignal; +use crate::emulation_core::datapath::{DatapathUpdateSignal, Syscall}; +use crate::emulation_core::mips::registers::GpRegisterType::{V0, V1}; use serde::{Deserialize, Serialize}; /// An implementation of a datapath for the MIPS64 ISA. @@ -305,6 +306,15 @@ impl Datapath for MipsDatapath { fn as_datapath_ref(&self) -> DatapathRef { DatapathRef::MIPS(self) } + + fn get_syscall_arguments(&self) -> Syscall { + Syscall::from_register_data( + self.get_register_by_enum(V0), + self.get_register_by_enum(V1), + f32::from_bits(self.coprocessor.fpr[0] as u32), + f64::from_bits(self.coprocessor.fpr[0]), + ) + } } impl MipsDatapath { From b3b7a94362720ee04d8625e0166bd129c5fb53cb Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Tue, 27 Feb 2024 22:05:49 -0500 Subject: [PATCH 108/355] Add functions to Datapath to place syscall results in registers --- src/emulation_core/datapath.rs | 8 ++++++++ src/emulation_core/mips/datapath.rs | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index 269fb64f2..1a7d67625 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -77,6 +77,14 @@ pub trait Datapath { /// Returns the type of syscall and its arguments (if any exist for that syscall). See the /// syscall enum for a list of syscalls and what they do. fn get_syscall_arguments(&self) -> Syscall; + + /// Places the provided results from a syscall into the appropriate registers. + fn return_syscall_results( + &mut self, + integer_return: Option, + float_return: Option, + double_return: Option, + ); } /// A datapath that supports a visual diagram component. diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index 1f3b09b92..b626805d0 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -315,6 +315,23 @@ impl Datapath for MipsDatapath { f64::from_bits(self.coprocessor.fpr[0]), ) } + + fn return_syscall_results( + &mut self, + integer_return: Option, + float_return: Option, + double_return: Option, + ) { + if let Some(val) = integer_return { + self.registers[V1] = val; + } + if let Some(val) = float_return { + self.coprocessor.fpr[1] = val.to_bits() as u64; + } + if let Some(val) = double_return { + self.coprocessor.fpr[1] = val.to_bits(); + } + } } impl MipsDatapath { From a6a51d6b8982b75b187a2dd716bcc36d3af089a8 Mon Sep 17 00:00:00 2001 From: Brooks McKinley <31021010+brooksmckinley@users.noreply.github.com> Date: Wed, 28 Feb 2024 16:09:31 -0500 Subject: [PATCH 109/355] Add function to Datapath for halting the emulation core --- src/emulation_core/datapath.rs | 3 +++ src/emulation_core/mips/datapath.rs | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index 1a7d67625..9593e0c5a 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -67,6 +67,9 @@ pub trait Datapath { /// be true in the case where an error had occurred previously. fn is_halted(&self) -> bool; + /// Halts the datapath. In order to un-halt the datapath, either call reset() or initialize(). + fn halt(&mut self); + /// Restore the datapath to its default state. fn reset(&mut self); diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index b626805d0..7d34ca2d9 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -299,6 +299,10 @@ impl Datapath for MipsDatapath { self.is_halted } + fn halt(&mut self) { + self.is_halted = true; + } + fn reset(&mut self) { std::mem::take(self); } From 73230de10aa449ecae822d8abb7a1947fa646b6a Mon Sep 17 00:00:00 2001 From: Cay Date: Fri, 1 Mar 2024 14:45:03 -0500 Subject: [PATCH 110/355] Add zoom slider --- src/ui/footer/component.rs | 21 +-------- src/ui/visual_datapath/mod.rs | 50 +++++++++++++++------ static/styles/main.css | 16 +++++++ static/styles/visual_datapath.css | 75 +++++++++++++++++++++++++++++++ 4 files changed, 130 insertions(+), 32 deletions(-) diff --git a/src/ui/footer/component.rs b/src/ui/footer/component.rs index 60bcaac17..70a03086b 100644 --- a/src/ui/footer/component.rs +++ b/src/ui/footer/component.rs @@ -1,7 +1,7 @@ use crate::agent::datapath_communicator::DatapathCommunicator; use crate::ui::console::component::Console; use crate::ui::hex_editor::component::HexEditor; -use crate::ui::visual_datapath::{DatapathSize, VisualDatapath}; +use crate::ui::visual_datapath::VisualDatapath; use monaco::api::TextModel; use wasm_bindgen::JsCast; use web_sys::HtmlElement; @@ -32,7 +32,6 @@ pub enum FooterTabState { #[function_component(Footer)] pub fn footer(props: &Footerprops) -> Html { let active_tab = &props.active_tab; - let zoom_datapath = use_bool_toggle(false); let switch_datapath = use_bool_toggle(false); let change_tab = { let active_tab = active_tab.clone(); @@ -53,19 +52,6 @@ pub fn footer(props: &Footerprops) -> Html { }) }; - let toggle_zoom = { - let zoom_datapath = zoom_datapath.clone(); - - Callback::from(move |_| { - zoom_datapath.toggle(); - }) - }; - - let datapath_size = match *zoom_datapath { - true => DatapathSize::Big, - false => DatapathSize::Small, - }; - let switch_datapath_type = { let switch_datapath = switch_datapath.clone(); @@ -92,9 +78,7 @@ pub fn footer(props: &Footerprops) -> Html { } else if **active_tab == FooterTabState::Datapath { -
- -
+ } else if **active_tab == FooterTabState::HexEditor {
@@ -123,7 +107,6 @@ pub fn footer(props: &Footerprops) -> Html { if **active_tab == FooterTabState::Datapath {
-
} diff --git a/src/ui/visual_datapath/mod.rs b/src/ui/visual_datapath/mod.rs index 6d6ddad40..7bb01ef1f 100644 --- a/src/ui/visual_datapath/mod.rs +++ b/src/ui/visual_datapath/mod.rs @@ -30,7 +30,7 @@ use std::{cell::RefCell, rc::Rc}; use gloo_events::EventListener; use log::debug; use wasm_bindgen::{JsCast, JsValue}; -use web_sys::{Element, Event, HtmlCollection, HtmlElement}; +use web_sys::{Element, Event, HtmlCollection, HtmlElement, HtmlInputElement}; use yew::prelude::*; use consts::*; @@ -47,8 +47,6 @@ pub struct VisualDatapathProps { /// /// For example, "`static/datapath_full.svg`". pub svg_path: String, - - pub size: Option, } pub struct VisualDatapath { @@ -57,6 +55,7 @@ pub struct VisualDatapath { /// /// This can occur if the `svg_path` property of the component changes. should_reinitialize: bool, + size: Rc>, } #[derive(Clone, Copy, Default, PartialEq)] @@ -74,20 +73,20 @@ impl Component for VisualDatapath { VisualDatapath { active_listeners: Rc::new(RefCell::new(vec![])), should_reinitialize: false, + size: Rc::new(RefCell::new(50)), } } fn view(&self, ctx: &Context) -> Html { - // Set the size of the datapath based on props. - let size = ctx.props().size.unwrap_or_default(); - let size_class = match size { - DatapathSize::Big => "big-datapath", - DatapathSize::Small => "small-datapath", - }; - + let zoom_in_size = Rc::clone(&self.size); + let zoom_range_size = Rc::clone(&self.size); + let zoom_value_size = Rc::clone(&self.size); + let zoom_out_size = Rc::clone(&self.size); html! { - <> - +
+
+ +
- +
+ + (); + let value = target.value().parse::().unwrap(); + log::debug!("Value: {:?}", value); + let mut size = zoom_range_size.borrow_mut(); + *size = value; + })}/> + +
+
} } diff --git a/static/styles/main.css b/static/styles/main.css index f98a1660d..41858ebdc 100644 --- a/static/styles/main.css +++ b/static/styles/main.css @@ -41,6 +41,16 @@ body { background-color: #2e2b2b; } +/****** Icons ******/ +.icon { + display: inline-block; + width: 1em; + height: 1em; + stroke-width: 0; + stroke: currentColor; + fill: currentColor; +} + /****** Editor ******/ .code { display: flex; @@ -221,13 +231,19 @@ body { } .datapath-wrapper { + max-height: 50%; +} + +.datapath-object-wrapper { flex-grow: 1.4; /* border: 2px solid black; */ overflow: auto; width: 100%; + height: 100%; flex-basis: 50%; background-color: #FFF; z-index: 1; + position: relative; } .button-bar { diff --git a/static/styles/visual_datapath.css b/static/styles/visual_datapath.css index d36c624e5..77941e453 100644 --- a/static/styles/visual_datapath.css +++ b/static/styles/visual_datapath.css @@ -6,6 +6,81 @@ width: auto; } +#datapath-zoom-controls { + position: absolute; + left: 27px; + bottom: 66px; + z-index: 1000; + display: flex; + align-items: center; + gap: 10px; +} + +/** Zoom Levels **/ +.datapath.size-0 { + width: 100%; +} +.datapath.size-10 { + width: 110%; +} +.datapath.size-20 { + width: 120%; +} +.datapath.size-30 { + width: 130%; +} +.datapath.size-40 { + width: 140%; +} +.datapath.size-50 { + width: 150%; +} +.datapath.size-60 { + width: 160%; +} +.datapath.size-70 { + width: 170%; +} +.datapath.size-80 { + width: 180%; +} +.datapath.size-90 { + width: 190%; +} +.datapath.size-100 { + width: 200%; +} +.datapath.size-110 { + width: 210%; +} +.datapath.size-120 { + width: 220%; +} +.datapath.size-130 { + width: 230%; +} +.datapath.size-140 { + width: 240%; +} +.datapath.size-150 { + width: 250%; +} +.datapath.size-160 { + width: 260%; +} +.datapath.size-170 { + width: 270%; +} +.datapath.size-180 { + width: 280%; +} +.datapath.size-190 { + width: 290%; +} +.datapath.size-200 { + width: 300%; +} + #popup { display: none; position: absolute; From 49fac6209095c38db3ce540e071eb3a047066b5b Mon Sep 17 00:00:00 2001 From: rharding8 Date: Fri, 1 Mar 2024 16:07:44 -0500 Subject: [PATCH 111/355] Added RV64I instructions for loading and storing doubles and addition with truncated words. --- src/emulation_core/riscv/constants.rs | 23 +---------- src/emulation_core/riscv/control_signals.rs | 3 ++ src/emulation_core/riscv/datapath.rs | 41 +++++++++++++++++--- src/emulation_core/riscv/datapath_signals.rs | 8 ++++ src/emulation_core/riscv/instruction.rs | 4 +- 5 files changed, 50 insertions(+), 29 deletions(-) diff --git a/src/emulation_core/riscv/constants.rs b/src/emulation_core/riscv/constants.rs index 29c107f4a..3a54838cb 100644 --- a/src/emulation_core/riscv/constants.rs +++ b/src/emulation_core/riscv/constants.rs @@ -1,5 +1,3 @@ -use super::control_signals::RegWidth; - pub const FUNCT_SYSCALL: u8 = 0b001100; pub const FUNCT_SLL: u8 = 0b000000; @@ -45,9 +43,11 @@ pub const FUNCT_SOP37: u8 = 0b011111; /// Used for R-type instructions. pub const OPCODE_OP: u8 = 0b0110011; +pub const OPCODE_OP_32: u8 = 0b0111011; /// Used for I-type instructions. pub const OPCODE_IMM: u8 = 0b0010011; +pub const OPCODE_IMM_32: u8 = 0b0011011; // JALR pub const OPCODE_JALR: u8 = 0b1100111; // LOAD @@ -119,22 +119,3 @@ pub const SUB_DMT: u8 = 0b00101; pub const FMT_SINGLE: u8 = 16; pub const FMT_DOUBLE: u8 = 17; -/// Return the register width associated to an instruction -/// with the given `funct` code. -/// -/// Returns [`None`] if the `funct` code is not supported. -pub fn reg_width_by_funct(funct: u8) -> Option { - match funct { - // `syscall` does not have a register width associated with it, - // but is set for the purposes of a default signal value. - FUNCT_SYSCALL => Some(RegWidth::DoubleWord), - FUNCT_ADD | FUNCT_ADDU | FUNCT_SUB | FUNCT_SLL => Some(RegWidth::Word), - FUNCT_AND | FUNCT_OR | FUNCT_SLT | FUNCT_SLTU => Some(RegWidth::DoubleWord), - FUNCT_DADD | FUNCT_DSUB => Some(RegWidth::DoubleWord), - FUNCT_DADDU | FUNCT_DSUBU => Some(RegWidth::DoubleWord), - FUNCT_JALR => Some(RegWidth::DoubleWord), - FUNCT_SOP30 | FUNCT_SOP31 | FUNCT_SOP32 | FUNCT_SOP33 => Some(RegWidth::Word), - FUNCT_SOP34 | FUNCT_SOP35 | FUNCT_SOP36 | FUNCT_SOP37 => Some(RegWidth::DoubleWord), - _ => None, - } -} diff --git a/src/emulation_core/riscv/control_signals.rs b/src/emulation_core/riscv/control_signals.rs index 1c2dcd6f6..dc7257943 100644 --- a/src/emulation_core/riscv/control_signals.rs +++ b/src/emulation_core/riscv/control_signals.rs @@ -119,11 +119,14 @@ pub enum ReadWrite { LoadByte, LoadHalf, LoadWord, + LoadDouble, LoadByteUnsigned, LoadHalfUnsigned, + LoadWordUnsigned, StoreByte, StoreHalf, StoreWord, + StoreDouble, } diff --git a/src/emulation_core/riscv/datapath.rs b/src/emulation_core/riscv/datapath.rs index 586b39c18..8b94a27df 100644 --- a/src/emulation_core/riscv/datapath.rs +++ b/src/emulation_core/riscv/datapath.rs @@ -354,10 +354,13 @@ impl RiscDatapath { ReadWrite::LoadHalf => self.memory_read(), ReadWrite::LoadHalfUnsigned => self.memory_read(), ReadWrite::LoadWord => self.memory_read(), + ReadWrite::LoadWordUnsigned => self.memory_read(), + ReadWrite::LoadDouble => self.memory_read(), ReadWrite::NoLoadStore => (), ReadWrite::StoreByte => self.memory_write(), ReadWrite::StoreHalf => self.memory_write(), ReadWrite::StoreWord => self.memory_write(), + ReadWrite::StoreDouble => self.memory_write(), } // Determine what data will be sent to the registers: either @@ -427,7 +430,7 @@ impl RiscDatapath { Instruction::IType(i) => { self.state.rs1 = i.rs1 as u32; self.state.funct3 = i.funct3 as u32; - self.state.rd = 0; // Placeholder + self.state.rd = i.rd as u32; self.state.imm = i.imm as u32; self.state.shamt = (i.imm & 0x001f) as u32; } @@ -463,7 +466,7 @@ impl RiscDatapath { /// 64-bit value. fn sign_extend(&mut self) { // self.state.sign_extend = ((self.state.imm as i16) as i64) as u64; - self.state.sign_extend = self.state.imm as i32 as i64 as u64; + self.state.sign_extend = self.state.imm as i64 as u64; } fn set_immediate(&mut self) { @@ -541,6 +544,10 @@ impl RiscDatapath { reg_write_en: RegWriteEn::YesWrite, ..Default::default() }; + + if r.op == OPCODE_OP_32 { + self.datapath_signals.reg_width = RegisterWidth::HalfWidth; + } match r.funct3 { 0 => match r.funct7 { @@ -568,9 +575,13 @@ impl RiscDatapath { reg_write_en: RegWriteEn::YesWrite, ..Default::default() }; + + if i.op == OPCODE_IMM_32 { + self.datapath_signals.reg_width = RegisterWidth::HalfWidth; + } match i.op { - OPCODE_IMM => match i.funct3 { + OPCODE_IMM | OPCODE_IMM_32 => match i.funct3 { 0 => self.signals.alu_op = AluOp::Addition, 1 => self.signals.alu_op = AluOp::ShiftLeftLogical(self.state.shamt), @@ -597,8 +608,10 @@ impl RiscDatapath { 0 => self.signals.read_write = ReadWrite::LoadByte, 1 => self.signals.read_write = ReadWrite::LoadHalf, 2 => self.signals.read_write = ReadWrite::LoadWord, + 3 => self.signals.read_write = ReadWrite::LoadDouble, 4 => self.signals.read_write = ReadWrite::LoadByteUnsigned, 5 => self.signals.read_write = ReadWrite::LoadHalfUnsigned, + 6 => self.signals.read_write = ReadWrite::LoadWordUnsigned, } } } @@ -617,6 +630,7 @@ impl RiscDatapath { 0 => self.signals.read_write = ReadWrite::StoreByte, 1 => self.signals.read_write = ReadWrite::StoreHalf, 2 => self.signals.read_write = ReadWrite::StoreWord, + 3 => self.signals.read_write = ReadWrite::StoreDouble, } } @@ -671,6 +685,7 @@ impl RiscDatapath { fn read_registers(&mut self) { self.state.read_data_1 = self.registers.gpr[self.state.rs1 as usize]; self.state.read_data_2 = self.registers.gpr[self.state.rs2 as usize]; + } // ======================= Execute (EX) ======================= @@ -689,9 +704,14 @@ impl RiscDatapath { self.state.alu_input1 = self.state.read_data_1; self.state.alu_input2 = match self.signals.op2_select { OP2Select::DATA2 => self.state.read_data_2, - OP2Select::IMM => self.state.imm as u64, + OP2Select::IMM => self.state.imm as i64 as u64, }; + if self.datapath_signals.reg_width == RegisterWidth::HalfWidth { + self.state.alu_input1 = self.state.alu_input1 as u32 as u64; + self.state.alu_input2 = self.state.alu_input2 as u32 as u64; + } + // Set the result. self.state.alu_result = match self.signals.alu_op { AluOp::Addition => self.state.alu_input1.wrapping_add(self.state.alu_input2), @@ -709,7 +729,7 @@ impl RiscDatapath { AluOp::Xor => self.state.alu_input1 ^ self.state.alu_input2, AluOp::ShiftLeftLogical(shamt) => self.state.alu_input2 << shamt, AluOp::ShiftRightLogical(shamt) => self.state.alu_input2 >> shamt, - AluOp::ShiftRightArithmetic(shamt) => (self.state.alu_input2 as i32 >> shamt) as u64, + AluOp::ShiftRightArithmetic(shamt) => (self.state.alu_input2 as i64 >> shamt) as u64, AluOp::MultiplicationSigned => { ((self.state.alu_input1 as i128) * (self.state.alu_input2 as i128)) as u64 } @@ -733,6 +753,10 @@ impl RiscDatapath { _ => 0, }; + if self.datapath_signals.reg_width == RegisterWidth::HalfWidth { + self.state.alu_result = self.state.alu_result as u32 as i64 as u64; + } + if self.signals.branch_jump == BranchJump::J { self.construct_jump_address(); } @@ -800,7 +824,9 @@ impl RiscDatapath { ReadWrite::LoadByteUnsigned => self.memory.load_byte(address).unwrap_or(0) as u64, ReadWrite::LoadHalf => self.memory.load_half(address).unwrap_or(0) as i64 as u64, ReadWrite::LoadHalfUnsigned => self.memory.load_half(address).unwrap_or(0) as u64, - ReadWrite::LoadWord => self.memory.load_word(address).unwrap_or(0) as u64, + ReadWrite::LoadWord => self.memory.load_word(address).unwrap_or(0) as i64 as u64, + ReadWrite::LoadWordUnsigned => self.memory.load_word(address).unwrap_or(0) as u64, + ReadWrite::LoadDouble => self.memory.load_double_word(address).unwrap_or(0), _ => 0, }; } @@ -825,6 +851,9 @@ impl RiscDatapath { ReadWrite::StoreWord => { self.memory.store_word(address, self.state.write_data as u32).ok(); } + ReadWrite::StoreDouble => { + self.memory.store_double_word(address, self.state.write_data).ok(); + } _ => (), }; } diff --git a/src/emulation_core/riscv/datapath_signals.rs b/src/emulation_core/riscv/datapath_signals.rs index a382522e8..159ae5889 100644 --- a/src/emulation_core/riscv/datapath_signals.rs +++ b/src/emulation_core/riscv/datapath_signals.rs @@ -5,6 +5,7 @@ pub struct DatapathSignals { pub alu_z: AluZ, pub cpu_branch: CpuBranch, pub general_branch: GeneralBranch, + pub reg_width: RegisterWidth, } /// The "Zero" line that comes out of the ALU. @@ -53,3 +54,10 @@ pub enum GeneralBranch { NoBranch = 0, YesBranch = 1, } + +#[derive(Clone, Default, PartialEq)] +pub enum RegisterWidth { + #[default] + DoubleWidth = 0, + HalfWidth = 1, +} \ No newline at end of file diff --git a/src/emulation_core/riscv/instruction.rs b/src/emulation_core/riscv/instruction.rs index 2d29bbf32..ed989ef37 100644 --- a/src/emulation_core/riscv/instruction.rs +++ b/src/emulation_core/riscv/instruction.rs @@ -109,7 +109,7 @@ impl TryFrom for Instruction { let op = (value & 0x7f) as u8; match op { // R-type instructions: - OPCODE_OP => Ok(Instruction::RType(RType { + OPCODE_OP | OPCODE_OP_32 => Ok(Instruction::RType(RType { funct7: (value >> 25) as u8, rs2: ((value >> 20) & 0x1f) as u8, rs1: ((value >> 15) & 0x1f) as u8, @@ -119,7 +119,7 @@ impl TryFrom for Instruction { })), // I-type instructions: - OPCODE_IMM | OPCODE_JALR | OPCODE_LOAD | OPCODE_SYSTEM => Ok(Instruction::IType(IType { + OPCODE_IMM | OPCODE_IMM_32 | OPCODE_JALR | OPCODE_LOAD | OPCODE_SYSTEM => Ok(Instruction::IType(IType { imm: (value >> 20) as u16, rs1: ((value >> 15) & 0x1f) as u8, funct3: ((value >> 12) & 0x07) as u8, From 8064326c85fbb1e510464e6ba7fc938723de8115 Mon Sep 17 00:00:00 2001 From: Cay Date: Fri, 1 Mar 2024 16:16:00 -0500 Subject: [PATCH 112/355] Make FP registers their own type and merge reg_view functions into one --- src/agent.rs | 5 +- src/agent/datapath_communicator.rs | 5 + src/agent/datapath_reducer.rs | 2 +- src/agent/messages.rs | 3 +- src/bin/main.rs | 2 +- src/emulation_core/datapath.rs | 5 +- src/emulation_core/mips.rs | 3 +- src/emulation_core/mips/coprocessor.rs | 58 ++++- src/emulation_core/mips/datapath.rs | 9 +- src/emulation_core/mips/fp_registers.rs | 227 ++++++++++++++++++ .../mips/{registers.rs => gp_registers.rs} | 0 src/tests/emulation_core/mips.rs | 178 +++++++------- src/tests/emulation_core/registers.rs | 2 +- .../core_parser/coprocessor_move.rs | 12 +- .../integration/core_parser/fibonacci.rs | 14 +- .../core_parser/floating_point_arithmetic.rs | 12 +- .../core_parser/floating_point_branch.rs | 4 +- .../core_parser/floating_point_comparison.rs | 8 +- .../core_parser/store_load_word.rs | 2 +- src/ui/regview/component.rs | 186 ++++++++------ 20 files changed, 524 insertions(+), 213 deletions(-) create mode 100644 src/emulation_core/mips/fp_registers.rs rename src/emulation_core/mips/{registers.rs => gp_registers.rs} (100%) diff --git a/src/agent.rs b/src/agent.rs index a93658f6a..5de3c20cd 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -4,7 +4,7 @@ use crate::agent::messages::{Command, MipsStateUpdate}; use crate::emulation_core::architectures::{DatapathRef, DatapathUpdate}; use crate::emulation_core::datapath::Datapath; use crate::emulation_core::mips::datapath::MipsDatapath; -use crate::emulation_core::mips::registers::GpRegisterType; +use crate::emulation_core::mips::gp_registers::GpRegisterType; use futures::{FutureExt, SinkExt, StreamExt}; use gloo_console::log; use std::time::Duration; @@ -100,6 +100,9 @@ impl EmulatorCoreAgentState { Command::SetRegister(register, value) => { self.current_datapath.set_register_by_str(®ister, value); } + Command::SetFPRegister(register, value) => { + self.current_datapath.set_fp_register_by_str(®ister, value); + } Command::SetMemory(ptr, data) => { self.current_datapath.set_memory(ptr, data); } diff --git a/src/agent/datapath_communicator.rs b/src/agent/datapath_communicator.rs index e2eb6bfac..6db35d05c 100644 --- a/src/agent/datapath_communicator.rs +++ b/src/agent/datapath_communicator.rs @@ -107,6 +107,11 @@ impl DatapathCommunicator { self.send_message(Command::SetRegister(register, data)); } + // Sets the FP register with the provided name to the provided value. + pub fn set_fp_register(&self, register: String, data: u64) { + self.send_message(Command::SetFPRegister(register, data)); + } + /// Copies the contents of `data` to the emulator core's memory at `ptr`. Copies until either the end of `data` or /// the end of the emulaot core's memory. pub fn set_memory(&self, ptr: u64, data: u32) { diff --git a/src/agent/datapath_reducer.rs b/src/agent/datapath_reducer.rs index 63bfc7902..cd36db8e4 100644 --- a/src/agent/datapath_reducer.rs +++ b/src/agent/datapath_reducer.rs @@ -3,7 +3,7 @@ use crate::emulation_core::architectures::AvailableDatapaths::MIPS; use crate::emulation_core::architectures::{AvailableDatapaths, DatapathUpdate}; use crate::emulation_core::mips::datapath::{DatapathState, Stage}; use crate::emulation_core::mips::memory::Memory; -use crate::emulation_core::mips::registers::GpRegisters; +use crate::emulation_core::mips::gp_registers::GpRegisters; use std::rc::Rc; use yew::Reducible; diff --git a/src/agent/messages.rs b/src/agent/messages.rs index 664c2deaa..edafef076 100644 --- a/src/agent/messages.rs +++ b/src/agent/messages.rs @@ -1,6 +1,6 @@ use crate::emulation_core::mips::datapath::DatapathState; use crate::emulation_core::mips::memory::Memory; -use crate::emulation_core::mips::registers::GpRegisters; +use crate::emulation_core::mips::gp_registers::GpRegisters; use crate::emulation_core::{architectures::AvailableDatapaths, mips::datapath::Stage}; use serde::{Deserialize, Serialize}; @@ -11,6 +11,7 @@ pub enum Command { Initialize(usize, Vec), SetExecuteSpeed(u32), SetRegister(String, u64), + SetFPRegister(String, u64), SetMemory(u64, u32), Execute, ExecuteInstruction, diff --git a/src/bin/main.rs b/src/bin/main.rs index 011ea91d2..41c3d7249 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -526,7 +526,7 @@ fn app(props: &AppProps) -> Html { // Right column - + } diff --git a/src/emulation_core/datapath.rs b/src/emulation_core/datapath.rs index 0d73035fc..f6ed88bee 100644 --- a/src/emulation_core/datapath.rs +++ b/src/emulation_core/datapath.rs @@ -44,10 +44,13 @@ pub trait Datapath { /// registers should be listed within [`Self::RegisterEnum`]. fn get_register_by_enum(&self, register: Self::RegisterEnum) -> Self::RegisterData; - /// Sets the data in the register indicated by the provided string. If it doesn't exist, + /// Sets the data in the GP register indicated by the provided string. If it doesn't exist, /// this function returns Err. fn set_register_by_str(&mut self, register: &str, data: Self::RegisterData); + // Set the data in the FP register indicated by the provided string + fn set_fp_register_by_str(&mut self, register: &str, data: Self::RegisterData); + /// Reset the datapath, load instructions into memory, and un-sets the `is_halted` /// flag. If the process fails, an [`Err`] is returned. fn initialize(&mut self, initial_pc: usize, instructions: Vec) -> Result<(), String>; diff --git a/src/emulation_core/mips.rs b/src/emulation_core/mips.rs index 9eef52183..ad461e62d 100644 --- a/src/emulation_core/mips.rs +++ b/src/emulation_core/mips.rs @@ -9,4 +9,5 @@ pub mod datapath_signals; pub mod instruction; pub mod line_info; pub mod memory; -pub mod registers; +pub mod gp_registers; +pub mod fp_registers; diff --git a/src/emulation_core/mips/coprocessor.rs b/src/emulation_core/mips/coprocessor.rs index c0c40fe85..0410cb401 100644 --- a/src/emulation_core/mips/coprocessor.rs +++ b/src/emulation_core/mips/coprocessor.rs @@ -2,20 +2,20 @@ use super::constants::*; use super::control_signals::floating_point::*; +use super::fp_registers::FpRegisters; use super::instruction::Instruction; /// An implementation of a floating-point coprocessor for the MIPS64 ISA. /// /// Different from the main processor, much of the functionality of the coprocessor /// is controlled remotely using its available API calls. -#[derive(Clone, Default, PartialEq)] +#[derive(Clone, PartialEq)] pub struct MipsFpCoprocessor { instruction: Instruction, pub signals: FpuControlSignals, pub state: FpuState, pub is_halted: bool, - - pub fpr: [u64; 32], + pub registers: FpRegisters, pub condition_code: u64, pub data: u64, } @@ -58,6 +58,22 @@ pub struct FpuState { pub comparator_result: u64, } +impl Default for MipsFpCoprocessor { + fn default() -> Self { + let coprocessor: MipsFpCoprocessor = MipsFpCoprocessor { + instruction: Instruction::default(), + signals: FpuControlSignals::default(), + state: FpuState::default(), + is_halted: false, + registers: FpRegisters::default(), + condition_code: 0, + data: 0, + }; + + coprocessor + } +} + impl MipsFpCoprocessor { // ========================== Stages ========================== pub fn stage_instruction_decode(&mut self) { @@ -127,6 +143,30 @@ impl MipsFpCoprocessor { self.state.fp_register_to_memory } + pub fn set_register(&mut self, _register: usize, _data: u64) -> Result<(), String> { + if _register >= 32 { + return Err(format!("Register index out of bounds: {}", _register)) + } + + let register = &mut self.registers.fpr[_register]; + *register = _data; + + Ok(()) + } + + pub fn register_from_str(&self, _register: &str) -> Option { + // Check if register matches a register between f0 and f31 + if _register.len() >= 2 && &_register[0..1] == "f" && _register.len() <= 3 { + let register = &_register[1..]; + if let Ok(register) = register.parse::() { + if register < 32 { + return Some(register); + } + } + } + return None; + } + // ================== Instruction Decode (ID) ================== /// Decode an instruction into its individual fields. fn instruction_decode(&mut self) { @@ -398,13 +438,13 @@ impl MipsFpCoprocessor { let reg1 = self.state.fs as usize; let reg2 = self.state.ft as usize; - self.state.read_data_1 = self.fpr[reg1]; - self.state.read_data_2 = self.fpr[reg2]; + self.state.read_data_1 = self.registers.fpr[reg1]; + self.state.read_data_2 = self.registers.fpr[reg2]; // Truncate the variable data if a 32-bit word is requested. if let FpuRegWidth::Word = self.signals.fpu_reg_width { - self.state.read_data_1 = self.fpr[reg1] as u32 as u64; - self.state.read_data_2 = self.fpr[reg2] as u32 as u64; + self.state.read_data_1 = self.registers.fpr[reg1] as u32 as u64; + self.state.read_data_2 = self.registers.fpr[reg2] as u32 as u64; } } @@ -613,7 +653,7 @@ impl MipsFpCoprocessor { FpuMemToReg::UseDataWrite => self.state.register_write_mux_to_mux, FpuMemToReg::UseMemory => self.state.fp_register_data_from_main_processor, }; - - self.fpr[self.state.destination] = self.state.register_write_data; + log::debug!("Writing to register f{}: {}", self.state.destination, self.state.register_write_data); + self.registers.fpr[self.state.destination] = self.state.register_write_data; } } diff --git a/src/emulation_core/mips/datapath.rs b/src/emulation_core/mips/datapath.rs index 7eca803f6..44654db80 100644 --- a/src/emulation_core/mips/datapath.rs +++ b/src/emulation_core/mips/datapath.rs @@ -51,7 +51,7 @@ use super::constants::*; use super::control_signals::{floating_point::*, *}; use super::datapath_signals::*; use super::instruction::*; -use super::{coprocessor::MipsFpCoprocessor, memory::Memory, registers::GpRegisters}; +use super::{coprocessor::MipsFpCoprocessor, memory::Memory, gp_registers::GpRegisters}; use crate::emulation_core::architectures::DatapathRef; use serde::{Deserialize, Serialize}; @@ -223,7 +223,7 @@ impl Default for MipsDatapath { impl Datapath for MipsDatapath { type RegisterData = u64; - type RegisterEnum = super::registers::GpRegisterType; + type RegisterEnum = super::gp_registers::GpRegisterType; fn execute_instruction(&mut self) { loop { @@ -273,6 +273,11 @@ impl Datapath for MipsDatapath { *register = _data; } + fn set_fp_register_by_str(&mut self, _register: &str, _data: Self::RegisterData) { + let register = &mut self.coprocessor.registers[_register]; + *register = _data; + } + fn initialize(&mut self, initial_pc: usize, instructions: Vec) -> Result<(), String> { self.reset(); self.load_instructions(instructions)?; diff --git a/src/emulation_core/mips/fp_registers.rs b/src/emulation_core/mips/fp_registers.rs new file mode 100644 index 000000000..b9a67fc44 --- /dev/null +++ b/src/emulation_core/mips/fp_registers.rs @@ -0,0 +1,227 @@ +//! Register structure and API. + +use serde::{Deserialize, Serialize}; +use std::ops::{Index, IndexMut}; +use std::str::FromStr; +use strum::IntoEnumIterator; +use strum_macros::{Display, EnumIter, EnumString}; + +/// Collection of general-purpose registers used by the datapath. +#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)] +pub struct FpRegisters { + pub fpr: [u64; 32], +} + +/// Specifies all of the valid registers accessible in an instance +/// of [`FpRegisters`]. +#[derive(Clone, Copy, Debug, Display, EnumIter, EnumString, Eq, PartialEq)] +#[strum(ascii_case_insensitive)] +#[strum(serialize_all = "lowercase")] +pub enum FpRegisterType { + F0 = 0, + F1 = 1, + F2 = 2, + F3 = 3, + F4 = 4, + F5 = 5, + F6 = 6, + F7 = 7, + F8 = 8, + F9 = 9, + F10 = 10, + F11 = 11, + F12 = 12, + F13 = 13, + F14 = 14, + F15 = 15, + F16 = 16, + F17 = 17, + F18 = 18, + F19 = 19, + F20 = 20, + F21 = 21, + F22 = 22, + F23 = 23, + F24 = 24, + F25 = 25, + F26 = 26, + F27 = 27, + F28 = 28, + F29 = 29, + F30 = 30, + F31 = 31, +} + +impl FpRegisterType { + pub fn get_fpr_name(&self) -> String { + match self { + _ => format!("f{}", *self as u32), + } + } + pub fn is_valid_register_value(&self, value: u64) -> bool { + true + } +} + +impl ToString for FpRegisters { + fn to_string(&self) -> String { + let mut output = String::new(); + + let fpr_registers = self + .fpr + .iter() + .enumerate() + .map(|(i, inst)| format!("fpr[{i}] = {inst}")) + .collect::>() + .join("\n"); + output.push_str(&fpr_registers); + + output + } +} + +impl Index<&str> for FpRegisters { + type Output = u64; + + // Convert string to the corresponding RegistersEnum value and use this to index. + // If this is an invalid string, no enum will be returned, causing a panic as desired. + fn index(&self, index: &str) -> &Self::Output { + match FpRegisterType::from_str(index) { + Ok(register) => &self[register], + _ => panic!("{index} is not a valid register"), + } + } +} + +impl IndexMut<&str> for FpRegisters { + // Convert string to the corresponding RegistersEnum value and use this to index. + // If this is an invalid string, no enum will be returned, causing a panic as desired. + fn index_mut(&mut self, index: &str) -> &mut Self::Output { + match FpRegisterType::from_str(index) { + Ok(register) => &mut self[register], + _ => panic!("{index} is not a valid register"), + } + } +} + +impl Index for FpRegisters { + type Output = u64; + + fn index(&self, index: FpRegisterType) -> &Self::Output { + match index { + FpRegisterType::F0 => &self.fpr[0], + FpRegisterType::F1 => &self.fpr[1], + FpRegisterType::F2 => &self.fpr[2], + FpRegisterType::F3 => &self.fpr[3], + FpRegisterType::F4 => &self.fpr[4], + FpRegisterType::F5 => &self.fpr[5], + FpRegisterType::F6 => &self.fpr[6], + FpRegisterType::F7 => &self.fpr[7], + FpRegisterType::F8 => &self.fpr[8], + FpRegisterType::F9 => &self.fpr[9], + FpRegisterType::F10 => &self.fpr[10], + FpRegisterType::F11 => &self.fpr[11], + FpRegisterType::F12 => &self.fpr[12], + FpRegisterType::F13 => &self.fpr[13], + FpRegisterType::F14 => &self.fpr[14], + FpRegisterType::F15 => &self.fpr[15], + FpRegisterType::F16 => &self.fpr[16], + FpRegisterType::F17 => &self.fpr[17], + FpRegisterType::F18 => &self.fpr[18], + FpRegisterType::F19 => &self.fpr[19], + FpRegisterType::F20 => &self.fpr[20], + FpRegisterType::F21 => &self.fpr[21], + FpRegisterType::F22 => &self.fpr[22], + FpRegisterType::F23 => &self.fpr[23], + FpRegisterType::F24 => &self.fpr[24], + FpRegisterType::F25 => &self.fpr[25], + FpRegisterType::F26 => &self.fpr[26], + FpRegisterType::F27 => &self.fpr[27], + FpRegisterType::F28 => &self.fpr[28], + FpRegisterType::F29 => &self.fpr[29], + FpRegisterType::F30 => &self.fpr[30], + FpRegisterType::F31 => &self.fpr[31], + } + } +} + +impl IndexMut for FpRegisters { + fn index_mut(&mut self, index: FpRegisterType) -> &mut Self::Output { + match index { + FpRegisterType::F0 => &mut self.fpr[0], + FpRegisterType::F1 => &mut self.fpr[1], + FpRegisterType::F2 => &mut self.fpr[2], + FpRegisterType::F3 => &mut self.fpr[3], + FpRegisterType::F4 => &mut self.fpr[4], + FpRegisterType::F5 => &mut self.fpr[5], + FpRegisterType::F6 => &mut self.fpr[6], + FpRegisterType::F7 => &mut self.fpr[7], + FpRegisterType::F8 => &mut self.fpr[8], + FpRegisterType::F9 => &mut self.fpr[9], + FpRegisterType::F10 => &mut self.fpr[10], + FpRegisterType::F11 => &mut self.fpr[11], + FpRegisterType::F12 => &mut self.fpr[12], + FpRegisterType::F13 => &mut self.fpr[13], + FpRegisterType::F14 => &mut self.fpr[14], + FpRegisterType::F15 => &mut self.fpr[15], + FpRegisterType::F16 => &mut self.fpr[16], + FpRegisterType::F17 => &mut self.fpr[17], + FpRegisterType::F18 => &mut self.fpr[18], + FpRegisterType::F19 => &mut self.fpr[19], + FpRegisterType::F20 => &mut self.fpr[20], + FpRegisterType::F21 => &mut self.fpr[21], + FpRegisterType::F22 => &mut self.fpr[22], + FpRegisterType::F23 => &mut self.fpr[23], + FpRegisterType::F24 => &mut self.fpr[24], + FpRegisterType::F25 => &mut self.fpr[25], + FpRegisterType::F26 => &mut self.fpr[26], + FpRegisterType::F27 => &mut self.fpr[27], + FpRegisterType::F28 => &mut self.fpr[28], + FpRegisterType::F29 => &mut self.fpr[29], + FpRegisterType::F30 => &mut self.fpr[30], + FpRegisterType::F31 => &mut self.fpr[31], + } + } +} + +/// Iterator that is used to view each register in the register file. +/// +/// This contains a copy of all the registers and their values, and a [`FpRegisterTypeIter`], +/// as generated by [`strum::IntoEnumIterator`]. In other iterator implementations, +/// the internal state might be data like a [`FpRegisterType`]. However, since we can't +/// normally just "add 1" to get to the next register, we use an internal iterator +/// that can track the progression of one [`FpRegisterType`] to the next. +pub struct FpRegistersIter { + registers: FpRegisters, + register_iter: FpRegisterTypeIter, +} + +/// This implementation of the [`Iterator`] trait essentially wraps the existing +/// [`FpRegisterTypeIter`] so that the register type can be paired with register data. +impl Iterator for FpRegistersIter { + type Item = (FpRegisterType, u64); + + fn next(&mut self) -> Option { + match self.register_iter.next() { + Some(register_type) => Some((register_type, self.registers[register_type])), + None => None, + } + } +} + +/// [`IntoIterator`] is a standard library trait that can convert any type into +/// an [`Iterator`]. In this case, this is an instance of [`FpRegistersIter`] with all the +/// data in the registers and a new [`FpRegisterTypeIter`]. +impl IntoIterator for FpRegisters { + type Item = (FpRegisterType, u64); + type IntoIter = FpRegistersIter; + + /// Consumes the [`FpRegisters`] struct to create a new [`FpRegistersIter`] that can + /// be iterated over. + fn into_iter(self) -> Self::IntoIter { + FpRegistersIter { + registers: self, + register_iter: FpRegisterType::iter(), + } + } +} diff --git a/src/emulation_core/mips/registers.rs b/src/emulation_core/mips/gp_registers.rs similarity index 100% rename from src/emulation_core/mips/registers.rs rename to src/emulation_core/mips/gp_registers.rs diff --git a/src/tests/emulation_core/mips.rs b/src/tests/emulation_core/mips.rs index 9483e3260..e603c9ffd 100644 --- a/src/tests/emulation_core/mips.rs +++ b/src/tests/emulation_core/mips.rs @@ -2,7 +2,7 @@ use crate::emulation_core::datapath::Datapath; use crate::emulation_core::mips::datapath::MipsDatapath; -use crate::emulation_core::mips::registers::GpRegisterType; +use crate::emulation_core::mips::gp_registers::GpRegisterType; pub mod api { use super::*; @@ -1721,14 +1721,14 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10000_00000_00001_00010_000000]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[0] = f32::to_bits(0.25f32) as u64; - datapath.coprocessor.fpr[1] = f32::to_bits(0.5f32) as u64; + datapath.coprocessor.registers.fpr[0] = f32::to_bits(0.25f32) as u64; + datapath.coprocessor.registers.fpr[1] = f32::to_bits(0.5f32) as u64; datapath.execute_instruction(); // The result should be 0.75, represented in a 32-bit value as per the // IEEE 754 single-precision floating-point specification. - assert_eq!(f32::from_bits(datapath.coprocessor.fpr[2] as u32), 0.75); + assert_eq!(f32::from_bits(datapath.coprocessor.registers.fpr[2] as u32), 0.75); Ok(()) } @@ -1744,14 +1744,14 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10001_00000_00001_00010_000000]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[0] = f64::to_bits(123.125); - datapath.coprocessor.fpr[1] = f64::to_bits(0.5); + datapath.coprocessor.registers.fpr[0] = f64::to_bits(123.125); + datapath.coprocessor.registers.fpr[1] = f64::to_bits(0.5); datapath.execute_instruction(); // The result should be 123.625, represented in a 64-bit value as per the // IEEE 754 double-precision floating-point specification. - assert_eq!(f64::from_bits(datapath.coprocessor.fpr[2]), 123.625); + assert_eq!(f64::from_bits(datapath.coprocessor.registers.fpr[2]), 123.625); Ok(()) } @@ -1768,12 +1768,12 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10000_00000_00001_00010_000001]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[0] = f32::to_bits(5.625f32) as u64; - datapath.coprocessor.fpr[1] = f32::to_bits(3.125f32) as u64; + datapath.coprocessor.registers.fpr[0] = f32::to_bits(5.625f32) as u64; + datapath.coprocessor.registers.fpr[1] = f32::to_bits(3.125f32) as u64; datapath.execute_instruction(); - assert_eq!(f32::from_bits(datapath.coprocessor.fpr[2] as u32), -2.5); + assert_eq!(f32::from_bits(datapath.coprocessor.registers.fpr[2] as u32), -2.5); Ok(()) } @@ -1790,12 +1790,12 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10001_00000_00001_00010_000001]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[0] = f64::to_bits(438.125); - datapath.coprocessor.fpr[1] = f64::to_bits(98765.5); + datapath.coprocessor.registers.fpr[0] = f64::to_bits(438.125); + datapath.coprocessor.registers.fpr[1] = f64::to_bits(98765.5); datapath.execute_instruction(); - assert_eq!(f64::from_bits(datapath.coprocessor.fpr[2]), 98327.375); + assert_eq!(f64::from_bits(datapath.coprocessor.registers.fpr[2]), 98327.375); Ok(()) } @@ -1812,12 +1812,12 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10000_00100_00101_01001_000010]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[5] = f32::to_bits(24.5f32) as u64; - datapath.coprocessor.fpr[4] = f32::to_bits(0.5f32) as u64; + datapath.coprocessor.registers.fpr[5] = f32::to_bits(24.5f32) as u64; + datapath.coprocessor.registers.fpr[4] = f32::to_bits(0.5f32) as u64; datapath.execute_instruction(); - assert_eq!(f32::from_bits(datapath.coprocessor.fpr[9] as u32), 12.25f32); + assert_eq!(f32::from_bits(datapath.coprocessor.registers.fpr[9] as u32), 12.25f32); Ok(()) } @@ -1834,12 +1834,12 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10001_01001_00110_00100_000010]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[6] = f64::to_bits(-150.0625); - datapath.coprocessor.fpr[9] = f64::to_bits(9.5); + datapath.coprocessor.registers.fpr[6] = f64::to_bits(-150.0625); + datapath.coprocessor.registers.fpr[9] = f64::to_bits(9.5); datapath.execute_instruction(); - assert_eq!(f64::from_bits(datapath.coprocessor.fpr[4]), -1425.59375); + assert_eq!(f64::from_bits(datapath.coprocessor.registers.fpr[4]), -1425.59375); Ok(()) } @@ -1856,13 +1856,13 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10000_10001_10000_01111_000011]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[16] = f32::to_bits(901f32) as u64; - datapath.coprocessor.fpr[17] = f32::to_bits(2f32) as u64; + datapath.coprocessor.registers.fpr[16] = f32::to_bits(901f32) as u64; + datapath.coprocessor.registers.fpr[17] = f32::to_bits(2f32) as u64; datapath.execute_instruction(); assert_eq!( - f32::from_bits(datapath.coprocessor.fpr[15] as u32), + f32::from_bits(datapath.coprocessor.registers.fpr[15] as u32), 450.5f32 ); Ok(()) @@ -1881,12 +1881,12 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10001_10100_01010_00001_000011]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[10] = f64::to_bits(95405.375); - datapath.coprocessor.fpr[20] = f64::to_bits(2.0); + datapath.coprocessor.registers.fpr[10] = f64::to_bits(95405.375); + datapath.coprocessor.registers.fpr[20] = f64::to_bits(2.0); datapath.execute_instruction(); - assert_eq!(f64::from_bits(datapath.coprocessor.fpr[1]), 47702.6875); + assert_eq!(f64::from_bits(datapath.coprocessor.registers.fpr[1]), 47702.6875); Ok(()) } @@ -1904,7 +1904,7 @@ pub mod coprocessor { datapath.initialize_legacy(instructions)?; datapath.registers.gpr[17] = 1028; // $s1 - datapath.coprocessor.fpr[3] = f32::to_bits(1.0625f32) as u64; + datapath.coprocessor.registers.fpr[3] = f32::to_bits(1.0625f32) as u64; datapath.execute_instruction(); @@ -1930,7 +1930,7 @@ pub mod coprocessor { datapath.initialize_legacy(instructions)?; datapath.registers.gpr[16] = 2000; // $s0 - datapath.coprocessor.fpr[5] = f32::to_bits(3.5f32) as u64; + datapath.coprocessor.registers.fpr[5] = f32::to_bits(3.5f32) as u64; datapath.execute_instruction(); @@ -1960,7 +1960,7 @@ pub mod coprocessor { datapath.initialize_legacy(instructions)?; datapath.registers.gpr[18] = 1000; // $s2 - datapath.coprocessor.fpr[0] = f64::to_bits(9853114.625); + datapath.coprocessor.registers.fpr[0] = f64::to_bits(9853114.625); datapath.execute_instruction(); @@ -1996,7 +1996,7 @@ pub mod coprocessor { datapath.execute_instruction(); assert_eq!( - f32::from_bits(datapath.coprocessor.fpr[10] as u32), + f32::from_bits(datapath.coprocessor.registers.fpr[10] as u32), 413.125f32 ); Ok(()) @@ -2027,7 +2027,7 @@ pub mod coprocessor { datapath.execute_instruction(); assert_eq!( - f32::from_bits(datapath.coprocessor.fpr[11] as u32), + f32::from_bits(datapath.coprocessor.registers.fpr[11] as u32), 6.1875f32 ); Ok(()) @@ -2046,8 +2046,8 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10000_00010_00001_000_00_110010]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[1] = f32::to_bits(15.5f32) as u64; - datapath.coprocessor.fpr[2] = f32::to_bits(15.5f32) as u64; + datapath.coprocessor.registers.fpr[1] = f32::to_bits(15.5f32) as u64; + datapath.coprocessor.registers.fpr[2] = f32::to_bits(15.5f32) as u64; datapath.execute_instruction(); @@ -2069,8 +2069,8 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10000_00011_01110_000_00_110010]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[14] = f32::to_bits(20.125f32) as u64; - datapath.coprocessor.fpr[3] = f32::to_bits(100f32) as u64; + datapath.coprocessor.registers.fpr[14] = f32::to_bits(20.125f32) as u64; + datapath.coprocessor.registers.fpr[3] = f32::to_bits(100f32) as u64; datapath.execute_instruction(); @@ -2092,8 +2092,8 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10001_01001_00101_000_00_110010]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[5] = f64::to_bits(12951.625); - datapath.coprocessor.fpr[9] = f64::to_bits(12951.625); + datapath.coprocessor.registers.fpr[5] = f64::to_bits(12951.625); + datapath.coprocessor.registers.fpr[9] = f64::to_bits(12951.625); datapath.execute_instruction(); @@ -2115,8 +2115,8 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10001_10011_01111_000_00_110010]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[15] = f64::to_bits(6016.25); - datapath.coprocessor.fpr[19] = f64::to_bits(820.43); + datapath.coprocessor.registers.fpr[15] = f64::to_bits(6016.25); + datapath.coprocessor.registers.fpr[19] = f64::to_bits(820.43); datapath.execute_instruction(); @@ -2138,8 +2138,8 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10000_00000_10011_000_00_111100]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[19] = f32::to_bits(2.875f32) as u64; - datapath.coprocessor.fpr[0] = f32::to_bits(70.6f32) as u64; + datapath.coprocessor.registers.fpr[19] = f32::to_bits(2.875f32) as u64; + datapath.coprocessor.registers.fpr[0] = f32::to_bits(70.6f32) as u64; datapath.execute_instruction(); @@ -2161,8 +2161,8 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10000_11111_11110_000_00_111100]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[30] = f32::to_bits(90.7f32) as u64; - datapath.coprocessor.fpr[31] = f32::to_bits(-87.44f32) as u64; + datapath.coprocessor.registers.fpr[30] = f32::to_bits(90.7f32) as u64; + datapath.coprocessor.registers.fpr[31] = f32::to_bits(-87.44f32) as u64; datapath.execute_instruction(); @@ -2184,8 +2184,8 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10001_11101_01100_000_00_111100]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[12] = f64::to_bits(4.0); - datapath.coprocessor.fpr[29] = f64::to_bits(30000.6); + datapath.coprocessor.registers.fpr[12] = f64::to_bits(4.0); + datapath.coprocessor.registers.fpr[29] = f64::to_bits(30000.6); datapath.execute_instruction(); @@ -2207,8 +2207,8 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10001_00101_00100_000_00_111100]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[4] = f64::to_bits(413.420); - datapath.coprocessor.fpr[5] = f64::to_bits(-6600.9); + datapath.coprocessor.registers.fpr[4] = f64::to_bits(413.420); + datapath.coprocessor.registers.fpr[5] = f64::to_bits(-6600.9); datapath.execute_instruction(); @@ -2230,8 +2230,8 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10000_00001_00000_000_00_111110]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[0] = f32::to_bits(171.937f32) as u64; - datapath.coprocessor.fpr[1] = f32::to_bits(9930.829f32) as u64; + datapath.coprocessor.registers.fpr[0] = f32::to_bits(171.937f32) as u64; + datapath.coprocessor.registers.fpr[1] = f32::to_bits(9930.829f32) as u64; datapath.execute_instruction(); @@ -2253,8 +2253,8 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10000_00011_00010_000_00_111110]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[2] = f32::to_bits(6.5f32) as u64; - datapath.coprocessor.fpr[3] = f32::to_bits(6.5f32) as u64; + datapath.coprocessor.registers.fpr[2] = f32::to_bits(6.5f32) as u64; + datapath.coprocessor.registers.fpr[3] = f32::to_bits(6.5f32) as u64; datapath.execute_instruction(); @@ -2276,8 +2276,8 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10000_00101_00100_000_00_111110]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[4] = f32::to_bits(5742.006f32) as u64; - datapath.coprocessor.fpr[5] = f32::to_bits(1336.568f32) as u64; + datapath.coprocessor.registers.fpr[4] = f32::to_bits(5742.006f32) as u64; + datapath.coprocessor.registers.fpr[5] = f32::to_bits(1336.568f32) as u64; datapath.execute_instruction(); @@ -2299,8 +2299,8 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10001_00111_00110_000_00_111110]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[6] = f64::to_bits(3483.70216); - datapath.coprocessor.fpr[7] = f64::to_bits(7201.56625); + datapath.coprocessor.registers.fpr[6] = f64::to_bits(3483.70216); + datapath.coprocessor.registers.fpr[7] = f64::to_bits(7201.56625); datapath.execute_instruction(); @@ -2322,8 +2322,8 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10001_01001_01000_000_00_111110]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[8] = f64::to_bits(77.4009); - datapath.coprocessor.fpr[9] = f64::to_bits(77.4009); + datapath.coprocessor.registers.fpr[8] = f64::to_bits(77.4009); + datapath.coprocessor.registers.fpr[9] = f64::to_bits(77.4009); datapath.execute_instruction(); @@ -2345,8 +2345,8 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10001_01011_01010_000_00_111110]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[10] = f64::to_bits(9190.43309); - datapath.coprocessor.fpr[11] = f64::to_bits(2869.57622); + datapath.coprocessor.registers.fpr[10] = f64::to_bits(9190.43309); + datapath.coprocessor.registers.fpr[11] = f64::to_bits(2869.57622); datapath.execute_instruction(); @@ -2368,8 +2368,8 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10000_01101_01100_000_00_111111]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[12] = f32::to_bits(2469.465f32) as u64; - datapath.coprocessor.fpr[13] = f32::to_bits(3505.57f32) as u64; + datapath.coprocessor.registers.fpr[12] = f32::to_bits(2469.465f32) as u64; + datapath.coprocessor.registers.fpr[13] = f32::to_bits(3505.57f32) as u64; datapath.execute_instruction(); @@ -2391,8 +2391,8 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10000_01111_01110_000_00_111111]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[14] = f32::to_bits(7099.472f32) as u64; - datapath.coprocessor.fpr[15] = f32::to_bits(87.198f32) as u64; + datapath.coprocessor.registers.fpr[14] = f32::to_bits(7099.472f32) as u64; + datapath.coprocessor.registers.fpr[15] = f32::to_bits(87.198f32) as u64; datapath.execute_instruction(); @@ -2414,8 +2414,8 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10001_10001_10000_000_00_111111]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[16] = f64::to_bits(7726.4794015); - datapath.coprocessor.fpr[17] = f64::to_bits(9345.7753943); + datapath.coprocessor.registers.fpr[16] = f64::to_bits(7726.4794015); + datapath.coprocessor.registers.fpr[17] = f64::to_bits(9345.7753943); datapath.execute_instruction(); @@ -2437,8 +2437,8 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10001_10011_10010_000_00_111111]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[18] = f64::to_bits(4688.2854359); - datapath.coprocessor.fpr[19] = f64::to_bits(819.7956308); + datapath.coprocessor.registers.fpr[18] = f64::to_bits(4688.2854359); + datapath.coprocessor.registers.fpr[19] = f64::to_bits(819.7956308); datapath.execute_instruction(); @@ -2460,8 +2460,8 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10000_10101_10100_000_00_111101]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[20] = f32::to_bits(3090.244f32) as u64; - datapath.coprocessor.fpr[21] = f32::to_bits(7396.444f32) as u64; + datapath.coprocessor.registers.fpr[20] = f32::to_bits(3090.244f32) as u64; + datapath.coprocessor.registers.fpr[21] = f32::to_bits(7396.444f32) as u64; datapath.execute_instruction(); @@ -2483,8 +2483,8 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10000_10111_10110_000_00_111101]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[22] = f32::to_bits(6269.823f32) as u64; - datapath.coprocessor.fpr[23] = f32::to_bits(3089.393f32) as u64; + datapath.coprocessor.registers.fpr[22] = f32::to_bits(6269.823f32) as u64; + datapath.coprocessor.registers.fpr[23] = f32::to_bits(3089.393f32) as u64; datapath.execute_instruction(); @@ -2506,8 +2506,8 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10001_11001_11000_000_00_111101]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[24] = f64::to_bits(819.7956308); - datapath.coprocessor.fpr[25] = f64::to_bits(4688.2854359); + datapath.coprocessor.registers.fpr[24] = f64::to_bits(819.7956308); + datapath.coprocessor.registers.fpr[25] = f64::to_bits(4688.2854359); datapath.execute_instruction(); @@ -2529,8 +2529,8 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_10001_11011_11010_000_00_111101]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[26] = f64::to_bits(9776.3465875); - datapath.coprocessor.fpr[27] = f64::to_bits(1549.8268716); + datapath.coprocessor.registers.fpr[26] = f64::to_bits(9776.3465875); + datapath.coprocessor.registers.fpr[27] = f64::to_bits(1549.8268716); datapath.execute_instruction(); @@ -2559,8 +2559,8 @@ pub mod coprocessor { ]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[5] = f64::to_bits(12951.625); - datapath.coprocessor.fpr[9] = f64::to_bits(12951.625); + datapath.coprocessor.registers.fpr[5] = f64::to_bits(12951.625); + datapath.coprocessor.registers.fpr[9] = f64::to_bits(12951.625); datapath.execute_instruction(); datapath.execute_instruction(); @@ -2590,8 +2590,8 @@ pub mod coprocessor { ]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[5] = f64::to_bits(12952.625); - datapath.coprocessor.fpr[9] = f64::to_bits(12951.625); + datapath.coprocessor.registers.fpr[5] = f64::to_bits(12952.625); + datapath.coprocessor.registers.fpr[9] = f64::to_bits(12951.625); datapath.execute_instruction(); datapath.execute_instruction(); @@ -2621,8 +2621,8 @@ pub mod coprocessor { ]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[4] = f32::to_bits(5742.006f32) as u64; - datapath.coprocessor.fpr[5] = f32::to_bits(1336.568f32) as u64; + datapath.coprocessor.registers.fpr[4] = f32::to_bits(5742.006f32) as u64; + datapath.coprocessor.registers.fpr[5] = f32::to_bits(1336.568f32) as u64; datapath.execute_instruction(); datapath.execute_instruction(); @@ -2652,8 +2652,8 @@ pub mod coprocessor { ]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[4] = f32::to_bits(742.006f32) as u64; - datapath.coprocessor.fpr[5] = f32::to_bits(1336.568f32) as u64; + datapath.coprocessor.registers.fpr[4] = f32::to_bits(742.006f32) as u64; + datapath.coprocessor.registers.fpr[5] = f32::to_bits(1336.568f32) as u64; datapath.execute_instruction(); datapath.execute_instruction(); @@ -2680,7 +2680,7 @@ pub mod coprocessor { datapath.execute_instruction(); - assert_eq!(datapath.coprocessor.fpr[0], 25); + assert_eq!(datapath.coprocessor.registers.fpr[0], 25); Ok(()) } @@ -2702,7 +2702,7 @@ pub mod coprocessor { datapath.execute_instruction(); - assert_eq!(datapath.coprocessor.fpr[1], 0xABCD_BEEF); + assert_eq!(datapath.coprocessor.registers.fpr[1], 0xABCD_BEEF); Ok(()) } @@ -2724,7 +2724,7 @@ pub mod coprocessor { datapath.execute_instruction(); - assert_eq!(datapath.coprocessor.fpr[30], 0xDEAD_BEEF_FEED_DEED); + assert_eq!(datapath.coprocessor.registers.fpr[30], 0xDEAD_BEEF_FEED_DEED); Ok(()) } @@ -2742,7 +2742,7 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_00000_10101_10010_00000000000]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[18] = 123; + datapath.coprocessor.registers.fpr[18] = 123; datapath.execute_instruction(); @@ -2764,7 +2764,7 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_00000_10110_10011_00000000000]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[19] = 0xABBA_BABB_3ABA_4444; + datapath.coprocessor.registers.fpr[19] = 0xABBA_BABB_3ABA_4444; datapath.execute_instruction(); @@ -2786,7 +2786,7 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_00000_10111_10100_00000000000]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[20] = 0xBADA_BEEF_BADA_B00E; + datapath.coprocessor.registers.fpr[20] = 0xBADA_BEEF_BADA_B00E; datapath.execute_instruction(); @@ -2808,7 +2808,7 @@ pub mod coprocessor { let instructions: Vec = vec![0b010001_00001_11000_10101_00000000000]; datapath.initialize_legacy(instructions)?; - datapath.coprocessor.fpr[21] = 0xADDA_DADD_1BAA_CAFE; + datapath.coprocessor.registers.fpr[21] = 0xADDA_DADD_1BAA_CAFE; datapath.execute_instruction(); diff --git a/src/tests/emulation_core/registers.rs b/src/tests/emulation_core/registers.rs index c912ffd66..26539a345 100644 --- a/src/tests/emulation_core/registers.rs +++ b/src/tests/emulation_core/registers.rs @@ -1,4 +1,4 @@ -use crate::emulation_core::mips::registers::{GpRegisterType, GpRegisters}; +use crate::emulation_core::mips::gp_registers::{GpRegisterType, GpRegisters}; #[test] #[allow(clippy::field_reassign_with_default)] diff --git a/src/tests/integration/core_parser/coprocessor_move.rs b/src/tests/integration/core_parser/coprocessor_move.rs index bcff12b7f..56f403101 100644 --- a/src/tests/integration/core_parser/coprocessor_move.rs +++ b/src/tests/integration/core_parser/coprocessor_move.rs @@ -16,7 +16,7 @@ fn basic_mtc1() -> Result<(), String> { datapath.execute_instruction(); } - assert_eq!(datapath.coprocessor.fpr[5], 658461658); + assert_eq!(datapath.coprocessor.registers.fpr[5], 658461658); Ok(()) } @@ -34,7 +34,7 @@ fn truncate_32_bit_mtc1() -> Result<(), String> { datapath.execute_instruction(); } - assert_eq!(datapath.coprocessor.fpr[6], 0xAC71_AC41); + assert_eq!(datapath.coprocessor.registers.fpr[6], 0xAC71_AC41); Ok(()) } @@ -46,7 +46,7 @@ fn basic_mfc1() -> Result<(), String> { let (_, instruction_bits) = parser(instructions); datapath.initialize_legacy(instruction_bits)?; - datapath.coprocessor.fpr[5] = 657861659; + datapath.coprocessor.registers.fpr[5] = 657861659; while !datapath.is_halted() { datapath.execute_instruction(); @@ -64,7 +64,7 @@ fn truncate_32_bit_mfc1() -> Result<(), String> { let (_, instruction_bits) = parser(instructions); datapath.initialize_legacy(instruction_bits)?; - datapath.coprocessor.fpr[6] = 0x0003_7F80_E5E7_D785; + datapath.coprocessor.registers.fpr[6] = 0x0003_7F80_E5E7_D785; while !datapath.is_halted() { datapath.execute_instruction(); @@ -88,7 +88,7 @@ fn basic_dmtc1() -> Result<(), String> { datapath.execute_instruction(); } - assert_eq!(datapath.coprocessor.fpr[6], 0x0120_02F2_AC71_AC41); + assert_eq!(datapath.coprocessor.registers.fpr[6], 0x0120_02F2_AC71_AC41); Ok(()) } @@ -100,7 +100,7 @@ fn basic_dmfc1() -> Result<(), String> { let (_, instruction_bits) = parser(instructions); datapath.initialize_legacy(instruction_bits)?; - datapath.coprocessor.fpr[6] = 0x0003_7F90_E5E7_D785; + datapath.coprocessor.registers.fpr[6] = 0x0003_7F90_E5E7_D785; while !datapath.is_halted() { datapath.execute_instruction(); diff --git a/src/tests/integration/core_parser/fibonacci.rs b/src/tests/integration/core_parser/fibonacci.rs index f380aeaee..e4c5c9cd2 100644 --- a/src/tests/integration/core_parser/fibonacci.rs +++ b/src/tests/integration/core_parser/fibonacci.rs @@ -1,4 +1,4 @@ -use crate::emulation_core::mips::registers::GpRegisterType; +use crate::emulation_core::mips::gp_registers::GpRegisterType; use super::*; @@ -22,11 +22,11 @@ fn recursive_fibonacci() -> Result<(), String> { slt $v0,$v0,$s1 beq $v0,$zero,L2 nop - + lw $v0,40($fp) b L3 nop - + L2: lw $v0,40($fp) nop @@ -34,7 +34,7 @@ fn recursive_fibonacci() -> Result<(), String> { move $a0,$v0 jal fib(int) nop - + move $s0,$v0 lw $v0,40($fp) nop @@ -42,7 +42,7 @@ fn recursive_fibonacci() -> Result<(), String> { move $a0,$v0 jal fib(int) nop - + addu $v0,$s0,$v0 L3: move $sp,$fp @@ -52,7 +52,7 @@ fn recursive_fibonacci() -> Result<(), String> { addiu $sp,$sp,40 jr $ra nop - + main: addiu $sp,$sp,-40 sw $ra,36($sp) @@ -63,7 +63,7 @@ fn recursive_fibonacci() -> Result<(), String> { lw $a0,24($fp) jal fib(int) nop - + sw $v0,28($fp) lw $v0,28($fp) # This is where the final answer gets loaded off the stack move $sp,$fp diff --git a/src/tests/integration/core_parser/floating_point_arithmetic.rs b/src/tests/integration/core_parser/floating_point_arithmetic.rs index 7f3466d48..f8e1b4352 100644 --- a/src/tests/integration/core_parser/floating_point_arithmetic.rs +++ b/src/tests/integration/core_parser/floating_point_arithmetic.rs @@ -21,14 +21,14 @@ akin! { let (_, instruction_bits) = parser(instructions); datapath.initialize_legacy(instruction_bits)?; - datapath.coprocessor.fpr[15] = *value1; - datapath.coprocessor.fpr[16] = *value2; + datapath.coprocessor.registers.fpr[15] = *value1; + datapath.coprocessor.registers.fpr[16] = *value2; while !datapath.is_halted() { datapath.execute_instruction(); } - assert_eq!(datapath.coprocessor.fpr[*result_register], *expected_result); + assert_eq!(datapath.coprocessor.registers.fpr[*result_register], *expected_result); Ok(()) } } @@ -52,14 +52,14 @@ akin! { let (_, instruction_bits) = parser(instructions); datapath.initialize_legacy(instruction_bits)?; - datapath.coprocessor.fpr[15] = *value1; - datapath.coprocessor.fpr[16] = *value2; + datapath.coprocessor.registers.fpr[15] = *value1; + datapath.coprocessor.registers.fpr[16] = *value2; while !datapath.is_halted() { datapath.execute_instruction(); } - assert_eq!(datapath.coprocessor.fpr[*result_register], *expected_result); + assert_eq!(datapath.coprocessor.registers.fpr[*result_register], *expected_result); Ok(()) } } diff --git a/src/tests/integration/core_parser/floating_point_branch.rs b/src/tests/integration/core_parser/floating_point_branch.rs index fb74fd44f..cffae414a 100644 --- a/src/tests/integration/core_parser/floating_point_branch.rs +++ b/src/tests/integration/core_parser/floating_point_branch.rs @@ -40,7 +40,7 @@ bc1t loop"#, // This should end when the loop has iterated 5 times. // Thus, $s2 should be 35 and $f0 should be 5.0. assert_eq!(datapath.registers.gpr[18], 35); // $s2 - assert_eq!(f32::from_bits(datapath.coprocessor.fpr[0] as u32), 5.0); // $f0 + assert_eq!(f32::from_bits(datapath.coprocessor.registers.fpr[0] as u32), 5.0); // $f0 Ok(()) } @@ -83,7 +83,7 @@ bc1f loop"#, // This should end when the loop has iterated 6 times. // Thus, $s2 should be 42 and $f0 should be 6.0. assert_eq!(datapath.registers.gpr[18], 42); // $s2 - assert_eq!(f32::from_bits(datapath.coprocessor.fpr[0] as u32), 6.0); // $f0 + assert_eq!(f32::from_bits(datapath.coprocessor.registers.fpr[0] as u32), 6.0); // $f0 Ok(()) } diff --git a/src/tests/integration/core_parser/floating_point_comparison.rs b/src/tests/integration/core_parser/floating_point_comparison.rs index 45e9ed632..b00b51506 100644 --- a/src/tests/integration/core_parser/floating_point_comparison.rs +++ b/src/tests/integration/core_parser/floating_point_comparison.rs @@ -19,8 +19,8 @@ akin! { let (_, instruction_bits) = parser(instructions); datapath.initialize_legacy(instruction_bits)?; - datapath.coprocessor.fpr[15] = *value1; - datapath.coprocessor.fpr[16] = *value2; + datapath.coprocessor.registers.fpr[15] = *value1; + datapath.coprocessor.registers.fpr[16] = *value2; while !datapath.is_halted() { datapath.execute_instruction(); @@ -48,8 +48,8 @@ akin! { let (_, instruction_bits) = parser(instructions); datapath.initialize_legacy(instruction_bits)?; - datapath.coprocessor.fpr[15] = *value1; - datapath.coprocessor.fpr[16] = *value2; + datapath.coprocessor.registers.fpr[15] = *value1; + datapath.coprocessor.registers.fpr[16] = *value2; while !datapath.is_halted() { datapath.execute_instruction(); diff --git a/src/tests/integration/core_parser/store_load_word.rs b/src/tests/integration/core_parser/store_load_word.rs index 00e7811ec..7c52f83a6 100644 --- a/src/tests/integration/core_parser/store_load_word.rs +++ b/src/tests/integration/core_parser/store_load_word.rs @@ -118,7 +118,7 @@ lwc1 $f12, 0($t4)"#, datapath.execute_instruction(); } - assert_eq!(datapath.coprocessor.fpr[12], 36); + assert_eq!(datapath.coprocessor.registers.fpr[12], 36); Ok(()) } diff --git a/src/ui/regview/component.rs b/src/ui/regview/component.rs index be351b855..a5e8664b6 100644 --- a/src/ui/regview/component.rs +++ b/src/ui/regview/component.rs @@ -1,5 +1,6 @@ use crate::agent::datapath_communicator::DatapathCommunicator; -use crate::emulation_core::mips::registers::GpRegisters; +use crate::emulation_core::mips::fp_registers::FpRegisters; +use crate::emulation_core::mips::gp_registers::GpRegisters; use wasm_bindgen::JsCast; use web_sys::{HtmlInputElement, InputEvent}; use yew::prelude::*; @@ -8,7 +9,7 @@ use yew::{html, Html}; #[derive(PartialEq, Properties)] pub struct Regviewprops { pub gp: GpRegisters, - pub fp: [u64; 32], + pub fp: FpRegisters, pub pc_limit: usize, pub communicator: &'static DatapathCommunicator, } @@ -17,8 +18,8 @@ pub struct Viewswitch { pub switch_view: bool, } -#[derive(Default, PartialEq)] -enum UnitState { +#[derive(Default, PartialEq, Clone, Copy, Debug)] +pub enum UnitState { #[default] Dec, Hex, @@ -32,7 +33,7 @@ pub struct InputData { } //Convert register to html through iterator -pub fn generate_gpr_rows(props: &Regviewprops) -> Html { +pub fn generate_gpr_rows(props: &Regviewprops, radix: u32) -> Html { let communicator = props.communicator; let pc_limit = props.pc_limit; @@ -40,6 +41,11 @@ pub fn generate_gpr_rows(props: &Regviewprops) -> Html { .gp .into_iter() .map(|(register, data)| { + let format_string = match radix { + 16 => format!("{:#04x?}", data), + 2 => format!("{:#b}", data), + _ => data.to_string(), + }; html! { {register.get_gpr_name()} @@ -48,7 +54,8 @@ pub fn generate_gpr_rows(props: &Regviewprops) -> Html { oninput={move |e: InputEvent| { let target = e.target(); let input = target.unwrap().unchecked_into::(); - let val: u64 = match input.value().parse() { + let input_string = input.value(); + let val = match u64::from_str_radix(&input_string[2..], radix) { Ok(value) => { input.set_class_name("valid"); value @@ -65,7 +72,7 @@ pub fn generate_gpr_rows(props: &Regviewprops) -> Html { input.set_class_name("invalid"); } }} - value={(data as i64).to_string()}/> + value={format_string}/> } @@ -156,14 +163,12 @@ pub fn generate_gpr_rows_bin(props: &Regviewprops) -> Html { } // ============= Coprocessor Registers ============= -pub fn generate_fpr_rows(props: &Regviewprops) -> Html { - // let communicator = props.communicator; +pub fn generate_fpr_rows(props: &Regviewprops, unit_type: UnitState) -> Html { + let communicator = props.communicator; - props - .fp - .iter() - .enumerate() + props.fp.into_iter() .map(|(register, data)| { + let unit_type = unit_type.clone(); html! { {format!("f{register}")} @@ -173,25 +178,60 @@ pub fn generate_fpr_rows(props: &Regviewprops) -> Html { let target = e.target(); let input = target.unwrap().unchecked_into::(); let input_string = input.value(); - let val = match input_string.parse::() { - Ok(value) => { - input.set_class_name("valid"); - value + let value = match unit_type { + UnitState::Float => { + match input_string.parse::() { + Ok(value) => { + input.set_class_name("valid"); + value as u64 + }, + Err(_err) => { + input.set_class_name("invalid"); + return + } + } }, - Err(_err) => { - input.set_class_name("invalid"); - return + UnitState::Double => { + match input_string.parse::() { + Ok(value) => { + input.set_class_name("valid"); + value as u64 + }, + Err(_err) => { + input.set_class_name("invalid"); + return + } + } + }, + _ => { + match u64::from_str_radix(&input_string[2..], 16) { + Ok(value) => { + input.set_class_name("valid"); + value as u64 + }, + Err(_err) => { + input.set_class_name("invalid"); + return + } + } } }; - log::debug!("{}", val as i64); - // communicator.set_register(register.to_string(), val); - // if register.is_valid_register_value(val, pc_limit) { - // input.set_class_name("valid"); - // } else { - // input.set_class_name("invalid"); - // } + communicator.set_register(register.to_string(), value); + if register.is_valid_register_value(value) { + input.set_class_name("valid"); + } else { + input.set_class_name("invalid"); + } }} - value={(*data as i64).to_string()}/> + value={ + match unit_type { + UnitState::Float => format!("{:e}", data).to_string(), + UnitState::Double => format!("{:e}", data).to_string(), + UnitState::Hex => format!("{:#04x?}", data).to_string(), + UnitState::Bin => format!("{:#b}", data).to_string(), + _ => format!("{:?}", data).to_string(), + } + }/> } @@ -199,12 +239,11 @@ pub fn generate_fpr_rows(props: &Regviewprops) -> Html { .collect::() } pub fn generate_fpr_rows_hex(props: &Regviewprops) -> Html { - // let communicator = props.communicator; + let communicator = props.communicator; props .fp - .iter() - .enumerate() + .into_iter() .map(|(register, data)| { html! { @@ -226,12 +265,12 @@ pub fn generate_fpr_rows_hex(props: &Regviewprops) -> Html { } }; log::debug!("{val:#04x?}"); - // communicator.set_register(register.to_string(), val); - // if register.is_valid_register_value(val, pc_limit) { - // input.set_class_name("valid"); - // } else { - // input.set_class_name("invalid"); - // } + communicator.set_register(register.to_string(), val); + if register.is_valid_register_value(val) { + input.set_class_name("valid"); + } else { + input.set_class_name("invalid"); + } }} value={format!("{data:#04x?}").to_string()}/> @@ -241,12 +280,11 @@ pub fn generate_fpr_rows_hex(props: &Regviewprops) -> Html { .collect::() } pub fn generate_fpr_rows_bin(props: &Regviewprops) -> Html { - // let communicator = props.communicator; + let communicator = props.communicator; props .fp - .iter() - .enumerate() + .into_iter() .map(|(register, data)| { html! { @@ -268,12 +306,12 @@ pub fn generate_fpr_rows_bin(props: &Regviewprops) -> Html { } }; log::debug!("{val:#b}"); - // communicator.set_register(register.to_string(), val); - // if register.is_valid_register_value(val, pc_limit) { - // input.set_class_name("valid"); - // } else { - // input.set_class_name("invalid"); - // } + communicator.set_register(register.to_string(), val); + if register.is_valid_register_value(val) { + input.set_class_name("valid"); + } else { + input.set_class_name("invalid"); + } }} value={format!("{data:#b}").to_string()}/> @@ -284,10 +322,9 @@ pub fn generate_fpr_rows_bin(props: &Regviewprops) -> Html { } pub fn generate_fpr_rows_float(props: &Regviewprops) -> Html { - // let communicator = props.communicator; + let communicator = props.communicator; - props.fp.iter() - .enumerate() + props.fp.into_iter() .map(|(register, data)| { html! { @@ -309,14 +346,14 @@ pub fn generate_fpr_rows_float(props: &Regviewprops) -> Html { } }; log::debug!("{:e}", value); - // communicator.set_register(register.to_string(), val); - // if register.is_valid_register_value(val, pc_limit) { - // input.set_class_name("valid"); - // } else { - // input.set_class_name("invalid"); - // } + communicator.set_register(register.to_string(), value as u64); + if register.is_valid_register_value(value as u64) { + input.set_class_name("valid"); + } else { + input.set_class_name("invalid"); + } }} - value={format!("{:e}",f32::from_bits((*data).try_into().unwrap())).to_string()}/> + value={format!("{:e}",f32::from_bits((data).try_into().unwrap())).to_string()}/> } @@ -325,12 +362,11 @@ pub fn generate_fpr_rows_float(props: &Regviewprops) -> Html { } pub fn generate_fpr_rows_double(props: &Regviewprops) -> Html { - // let communicator = props.communicator; + let communicator = props.communicator; props .fp - .iter() - .enumerate() + .into_iter() .map(|(register, data)| { html! { @@ -352,14 +388,14 @@ pub fn generate_fpr_rows_double(props: &Regviewprops) -> Html { } }; log::debug!("{:e}", value); - // communicator.set_register(register.to_string(), val); - // if register.is_valid_register_value(val, pc_limit) { - // input.set_class_name("valid"); - // } else { - // input.set_class_name("invalid"); - // } + communicator.set_register(register.to_string(), value as u64); + if register.is_valid_register_value(value as u64) { + input.set_class_name("valid"); + } else { + input.set_class_name("invalid"); + } }} - value={format!("{:e}", f64::from_bits(*data)).to_string()}/> + value={format!("{:e}", f64::from_bits(data)).to_string()}/> } @@ -457,25 +493,15 @@ pub fn regview(props: &Regviewprops) -> Html { if *switch_flag{ if *active_view == UnitState::Bin { - {generate_gpr_rows_bin(props)} + {generate_gpr_rows(props, 2)} } else if *active_view == UnitState::Hex { - {generate_gpr_rows_hex(props)} + {generate_gpr_rows(props, 16)} } else { - {generate_gpr_rows(props)} + {generate_gpr_rows(props, 10)} } } else { - if *active_view == UnitState::Bin { - {generate_fpr_rows_bin(props)} - } else if *active_view == UnitState::Hex{ - {generate_fpr_rows_hex(props)} - } else if *active_view == UnitState::Float{ - {generate_fpr_rows_float(props)} - } else if *active_view == UnitState::Double{ - {generate_fpr_rows_double(props)} - } else if *active_view == UnitState::Dec { - {generate_fpr_rows(props)} - } + {generate_fpr_rows(props, *active_view.clone())} } From b32f589eec17b06646fcc88435a7ed583ce67cbe Mon Sep 17 00:00:00 2001 From: Cay Date: Fri, 1 Mar 2024 16:24:45 -0500 Subject: [PATCH 113/355] Adds a single visual_line_to_data func in utils --- src/emulation_core/riscv/line_info.rs | 311 ------------- src/ui/visual_datapath/utils.rs | 646 +++++++++++++++++++++++++- 2 files changed, 634 insertions(+), 323 deletions(-) diff --git a/src/emulation_core/riscv/line_info.rs b/src/emulation_core/riscv/line_info.rs index 4f28777c1..fa606e590 100644 --- a/src/emulation_core/riscv/line_info.rs +++ b/src/emulation_core/riscv/line_info.rs @@ -331,315 +331,4 @@ impl VisualDatapath for RiscDatapath { }, } } -} - -pub fn visual_line_to_data(variable: &str, datapath_state: &UseReducerHandle) -> LineInformation { -// match variable { -// "alu_input2" => LineInformation { -// title: String::from("ALU Input 2"), -// description: String::from("The second input to the ALU. This is determined by the ALUSrc control signal to select between register data, a sign-extended and left-shifted immediate value, or a zero-extended immediate value."), -// value: datapath_state.riscv.state.alu_input2, -// bits: 64, -// }, -// "alu_result" => LineInformation { -// title: String::from("ALU Result"), -// description: String::from("The result of the calculation performed by the ALU. This is used either as an address to access memory or as a value that is saved into a register."), -// value: datapath_state.riscv.state.alu_result, -// bits: 64, -// }, -// "data_result" => LineInformation { -// title: String::from("Writeback Data"), -// description: String::from("After finishing processing the instruction, this will either be the ALU result, data from memory, or PC + 4, based on the MemToReg control signal. This data is saved into registers."), -// value: datapath_state.riscv.state.data_result, -// bits: 64, -// }, -// "fpu_alu_result" => LineInformation { -// title: String::from("Floating-Point ALU Result"), -// description: String::from("The result of the calculation performed by the floating-point ALU. This is used as an option to be written to a floating-point register, based on the DataWrite and FpuMemToReg control signals."), -// value: datapath_state.riscv.coprocessor.state.alu_result, -// bits: 64, -// }, -// "fpu_branch_decision" => LineInformation { -// title: String::from("FPU Branch Decision"), -// description: String::from("Based on the true/false branch flag, determines whether to branch. (The FpuBranch control signal must also be set.)"), -// value: datapath_state.riscv.coprocessor.state.condition_code_mux as u64, -// bits: 1, -// }, -// "fpu_branch_flag" => LineInformation { -// title: String::from("Instruction [16] (True/False Branch Flag)"), -// description: String::from("The true/false branch flag of branching coprocessor instructions. This flag specifies whether a floating-point branch instruction is BC1T or BC1F."), -// value: datapath_state.riscv.coprocessor.state.branch_flag as u64, -// bits: 1, -// }, -// "fpu_comparator_result" => LineInformation { -// title: String::from("Floating-Point Comparator Result"), -// description: String::from("The result of the comparison of two floating-point values. This is routed to the \"Condition Code\" (cc) register, and will be written there if the CcWrite control signal is set."), -// value: datapath_state.riscv.coprocessor.state.comparator_result, -// bits: 64, -// }, -// "fpu_condition_code" => LineInformation { -// title: String::from("Condition Code Value"), -// description: String::from("Data retrieved from the \"Condition Code\" (cc) register. This specifies whether a previous conditional instruction was true or false."), -// value: datapath_state.riscv.coprocessor.state.condition_code_bit as u64, -// bits: 1, -// }, -// "fpu_condition_code_inverted" => LineInformation { -// title: String::from("Condition Code Value (Inverted)"), -// description: String::from("Inverted form of the condition code register value."), -// value: datapath_state.riscv.coprocessor.state.condition_code_bit_inverted as u64, -// bits: 1, -// }, -// "fpu_data" => LineInformation { -// title: String::from("Floating-Point Data Register Value"), -// description: String::from("Data retrieved from the \"Data\" register. This register acts as a means to communicate data between the main processor and floating-point coprocessor in MTC1 and MFC1 instructions."), -// value: datapath_state.riscv.coprocessor.state.fmt as u64, -// bits: 64, -// }, -// "fpu_data_writeback" => LineInformation { -// title: String::from("Floating-Point Data Writeback"), -// description: String::from("The value from the floating-point unit's \"Data\" register. Depending on the FpuRegWidth control signal, this will be 64-bit data or sign-extended 32-bit data."), -// value: datapath_state.riscv.coprocessor.state.data_writeback, -// bits: 64, -// }, -// "fpu_destination" => LineInformation { -// title: String::from("Floating-Point Write Register"), -// description: String::from("The register that will be written to, assuming FpuRegWrite is set. Depending on the FpuRegDst control signal, this will consist of the fs, ft, or fd register."), -// value: datapath_state.riscv.coprocessor.state.destination as u64, -// bits: 5, -// }, -// "fpu_fd" => LineInformation { -// title: String::from("Instruction [10-6] (fd)"), -// description: String::from("The fd field. Depending on the FpuRegDst control signal, this will be the register written to in a floating-point operation. This register is used as the destination for most floating-point arithmetic instructions."), -// value: datapath_state.riscv.coprocessor.state.fd as u64, -// bits: 5, -// }, -// "fpu_fmt" => LineInformation { -// title: String::from("Instruction [25-21] (fmt)"), -// description: String::from("The fmt field. This is used to distinguish between single-precision and double-precision floating-point instructions."), -// value: datapath_state.riscv.coprocessor.state.fmt as u64, -// bits: 5, -// }, -// "fpu_fp_register_data_from_main_processor" => LineInformation { -// title: String::from("Writeback Data (To Floating-Point Coprocessor)"), -// description: String::from("This data is written to a floating-point register, given FpuMemToReg is set. This line allows data to load from memory to a floating-point register, specifically in the case of the LWC1 instruction."), -// value: datapath_state.riscv.coprocessor.state.fp_register_data_from_main_processor, -// bits: 64, -// }, -// "fpu_fp_register_to_memory" => LineInformation { -// title: String::from("Memory Write Data (from FPU)"), -// description: String::from("If the MemWriteSrc control signal is set, this data will be written to memory. This is used for the SWC1 instruction."), -// value: datapath_state.riscv.coprocessor.state.fp_register_to_memory, -// bits: 64, -// }, -// "fpu_fs" => LineInformation { -// title: String::from("Instruction [15-11] (fs)"), -// description: String::from("The fs field. Contains the first register to be read for a floating-point instruction."), -// value: datapath_state.riscv.coprocessor.state.fs as u64, -// bits: 5, -// }, -// "fpu_ft" => LineInformation { -// title: String::from("Instruction [20-16] (ft)"), -// description: String::from("The ft field. Contains the second register to be read for a floating-point instruction."), -// value: datapath_state.riscv.coprocessor.state.ft as u64, -// bits: 5, -// }, -// "fpu_new_data" => LineInformation { -// title: String::from("New Floating-Point Data Register Value"), -// description: String::from("Data sent to the \"Data\" register. Depending on the DataSrc control signal, this will either be data from the main processor or the floating-point coprocessor. This register acts as a means to communicate data between the main processor and floating-point coprocessor in MTC1 and MFC1 instructions."), -// value: datapath_state.riscv.coprocessor.state.fmt as u64, -// bits: 64, -// }, -// "fpu_read_data_1" => LineInformation { -// title: String::from("FPU Read Data 1"), -// description: String::from("Data retrieved from the register specified by the fs instruction field. This is used as the first inputs to the floating-point ALU and comparator. This can additionally be written to the \"Data\" register, based on the DataSrc and DataWrite control signals."), -// value: datapath_state.riscv.coprocessor.state.read_data_1, -// bits: 64, -// }, -// "fpu_read_data_2" => LineInformation { -// title: String::from("FPU Read Data 2"), -// description: String::from("Data retrieved from the register specified by the ft instruction field. This is used as the second inputs to the floating-point ALU and comparator. This can additionally be used as data to be written to memory, based on the MemWriteSrc control signal."), -// value: datapath_state.riscv.coprocessor.state.read_data_2, -// bits: 64, -// }, -// "fpu_register_write_data" => LineInformation { -// title: String::from("FPU Register Write Data"), -// description: String::from("Data that will be written to a floating-point register, given that FpuRegWrite is set."), -// value: datapath_state.riscv.coprocessor.state.register_write_data, -// bits: 64, -// }, -// "fpu_register_write_mux_to_mux" => LineInformation { -// title: String::from("FPU Register Write Data (When FpuMemToReg is Unset)"), -// description: String::from("Based on the DataWrite control signal, this will either be the result of the floating-point ALU or the contents of the \"Data\" register. (The \"Data\" register is used for transferring data between the processor and floating-point coprocessor.)"), -// value: datapath_state.riscv.coprocessor.state.register_write_mux_to_mux, -// bits: 64, -// }, -// "fpu_sign_extend_data" => LineInformation { -// title: String::from("Floating-Point Data Register Value (Sign-Extended)"), -// description: String::from("In the case where FpuRegWidth indicates a 32-bit width, this is the bottom 32 bits of the value from the \"Data\" register, then sign-extended to 64 bits."), -// value: datapath_state.riscv.coprocessor.state.sign_extend_data, -// bits: 64, -// }, -// "funct" => LineInformation { -// title: String::from("Instruction [5-0] (funct)"), -// description: String::from("The funct field. Contains the type of operation to execute for R-type instructions."), -// value: datapath_state.riscv.state.funct as u64, -// bits: 6, -// }, -// "imm" => LineInformation { -// title: String::from("Instruction [15-0] (immediate)"), -// description: String::from("The immediate field. Contains the 16-bit constant value used for I-type instructions."), -// value: datapath_state.riscv.state.imm as u64, -// bits: 16, -// }, -// "instruction" => LineInformation { -// title: String::from("Instruction"), -// description: String::from("The currently-loaded instruction. This is broken down into different fields, where each field serves a different purpose in identifying what the instruction does."), -// value: datapath_state.riscv.state.instruction as u64, -// bits: 32, -// }, -// "jump_address" => LineInformation { -// title: String::from("Jump Address"), -// description: String::from("The concatenation of the upper 36 bits of PC + 4 with the lower 26 bits of the instruction, shifted left by 2. This is used as the new PC value for J-type instructions."), -// value: datapath_state.riscv.state.jump_address, -// bits: 64, -// }, -// "lower_26" => LineInformation { -// title: String::from("Instruction [25-0]"), -// description: String::from("The lower 26 bits of instruction. This is used as part of the new PC value for J-type instructions."), -// value: datapath_state.riscv.state.lower_26 as u64, -// bits: 26, -// }, -// "lower_26_shifted_left_by_2" => LineInformation { -// title: String::from("Instruction [25-0] << 2"), -// description: String::from("The lower 26 bits of instruction, shifted left by 2. This is used as part of the new PC value for J-type instructions."), -// value: datapath_state.riscv.state.lower_26_shifted_left_by_2 as u64, -// bits: 28, -// }, -// "mem_mux1_to_mem_mux2" => LineInformation { -// title: String::from("Relative PC Address"), -// description: String::from("Based on the control signals for branching and jumping, this address may be the next PC value. This is used for general non-branching instructions or branch-type instructions."), -// value: datapath_state.riscv.state.mem_mux1_to_mem_mux2, -// bits: 64, -// }, -// "memory_data" => LineInformation { -// title: String::from("Memory Data"), -// description: String::from("The data retrieved from memory, given that the MemRead control signal is set. This may be 32 bits or 64 bits, depending on the RegWidth control signal."), -// value: datapath_state.riscv.state.memory_data, -// bits: 64, -// }, -// "new_pc" => LineInformation { -// title: String::from("New Program Counter"), -// description: String::from("The address of the next instruction to execute. In other words, the next value of the program counter (PC) register."), -// value: datapath_state.riscv.state.new_pc, -// bits: 64, -// }, -// "pc" => LineInformation { -// title: String::from("Program Counter"), -// description: String::from("The address of the currently-executing instruction."), -// value: datapath_state.riscv.registers.pc, -// bits: 64, -// }, -// "pc_plus_4" => LineInformation { -// title: String::from("PC + 4"), -// description: String::from("The address of the currently-executing instruction, plus 4. By default, this will become the next value of the PC register. However, a different address may be used in the case of a branch or jump instruction."), -// value: datapath_state.riscv.state.pc_plus_4, -// bits: 64, -// }, -// "pc_plus_4_upper" => LineInformation { -// title: String::from("PC + 4 [63-28]"), -// description: String::from("The upper 36 bits of PC + 4. This is to be concatenated with the lower 26 bits of the instruction to calculate a jump address."), -// value: datapath_state.riscv.state.pc_plus_4 & 0xffff_ffff_f000_0000 >> 28, -// bits: 36, -// }, -// "ra_id" => LineInformation { -// title: String::from("Return Address Register Index"), -// description: String::from("The value 31. This represents the thirty-second register, the return address register ($ra)."), -// value: 31, -// bits: 5, -// }, -// "rd" => LineInformation { -// title: String::from("Instruction [15-11] (rd)"), -// description: String::from("The rd field. Depending on the RegDst control signal, this will be the register written to for an instruction. This register is used as the destination for most R-type instructions."), -// value: datapath_state.riscv.state.rd as u64, -// bits: 5, -// }, -// "read_data_1" => LineInformation { -// title: String::from("Read Data 1"), -// description: String::from("Data retrieved from the register specified by the rs instruction field. Based on the instruction, this may be used as the first input to the ALU, or the next value of the PC register."), -// value: datapath_state.riscv.state.read_data_1, -// bits: 64, -// }, -// "read_data_2" => LineInformation { -// title: String::from("Read Data 2"), -// description: String::from("Data retrieved from the register specified by the rt instruction field. Based on the instruction, this may be used as the second input to the ALU, data written to memory, or data transferred to the floating-point coprocessor."), -// value: datapath_state.riscv.state.read_data_2, -// bits: 64, -// }, -// "register_write_data" => LineInformation { -// title: String::from("Register Write Data"), -// description: String::from("Data that will be written to a general-purpose register, given that RegWrite is set."), -// value: datapath_state.riscv.state.register_write_data, -// bits: 64, -// }, -// "relative_pc_branch" => LineInformation { -// title: String::from("Relative PC Branch Address"), -// description: String::from("The relative address used in branch instructions. This is the sum of PC + 4 and the sign-extended immediate value, shifted left by 2."), -// value: datapath_state.riscv.state.relative_pc_branch, -// bits: 64, -// }, -// "rs" => LineInformation { -// title: String::from("Instruction [25-21] (rs)"), -// description: String::from("The rs field. Contains the first register to be read for an instruction."), -// value: datapath_state.riscv.state.rs as u64, -// bits: 5, -// }, -// "rt" => LineInformation { -// title: String::from("Instruction [20-16] (rt)"), -// description: String::from("The rt field. Contains the second register to be read for an instruction."), -// value: datapath_state.riscv.state.rt as u64, -// bits: 5, -// }, -// "shamt" => LineInformation { -// title: String::from("Instruction [10-6] (shamt)"), -// description: String::from("The shamt (\"shift amount\") field. Specifies the number of bits to shift for those instructions that perform bit-shifting."), -// value: datapath_state.riscv.state.shamt as u64, -// bits: 5, -// }, -// "sign_extend" => LineInformation { -// title: String::from("Sign-Extended Immediate"), -// description: String::from("The immediate field, sign-extended to a 64-bit value."), -// value: datapath_state.riscv.state.sign_extend, -// bits: 64, -// }, -// "sign_extend_shift_left_by_2" => LineInformation { -// title: String::from("Sign-Extended Immediate << 2"), -// description: String::from("The immediate field, sign-extended to a 64-bit value, then shifted left by 2."), -// value: datapath_state.riscv.state.sign_extend_shift_left_by_2, -// bits: 64, -// }, -// "write_data" => LineInformation { -// title: String::from("Memory Write Data"), -// description: String::from("Given that the MemWrite control signal is set, this data will be written to memory."), -// value: datapath_state.riscv.state.write_data, -// bits: 64, -// }, -// "write_register" => LineInformation { -// title: String::from("Write Register"), -// description: String::from("The register that will be written to, assuming RegWrite is set. Depending on the RegDst control signal, this will consist of the rs, rt, or rd register, or 31 (indicating the $ra register)."), -// value: datapath_state.riscv.state.write_register_destination as u64, -// bits: 5, -// }, -// "zero_extended_immediate" => LineInformation { -// title: String::from("Zero-Extended Immediate"), -// description: String::from("The immediate field, zero-extended to a 64-bit value."), -// value: datapath_state.riscv.state.imm as u64, -// bits: 64, -// }, -// _ => LineInformation { -// title: String::from("[Title]"), -// description: String::from("[Description]"), -// value: 0, -// bits: 0, -// }, -// } } \ No newline at end of file diff --git a/src/ui/visual_datapath/utils.rs b/src/ui/visual_datapath/utils.rs index 3b8797079..aaa43107c 100644 --- a/src/ui/visual_datapath/utils.rs +++ b/src/ui/visual_datapath/utils.rs @@ -5,7 +5,7 @@ use wasm_bindgen::JsCast; use web_sys::{Element, HtmlCollection, HtmlElement, HtmlObjectElement, MouseEvent}; use yew::UseReducerHandle; -use crate::{agent::datapath_reducer::DatapathReducer, emulation_core::{self, architectures::AvailableDatapaths}}; +use crate::{agent::datapath_reducer::DatapathReducer, emulation_core::{architectures::AvailableDatapaths, mips::line_info::LineInformation}}; use super::consts::*; @@ -147,17 +147,7 @@ pub fn populate_popup_information(datapath_state: &UseReducerHandle { - information = emulation_core::mips::line_info::visual_line_to_data(variable, datapath_state); - }, - AvailableDatapaths::RISCV => { - // replace with RISC-V version - // information = emulation_core::riscv::line_info::visual_line_to_data(variable, datapath_state); - information = emulation_core::mips::line_info::visual_line_to_data(variable, datapath_state); - } - }; + let information = visual_line_to_data(variable, datapath_state); title.set_text_content(Some(&information.title)); description.set_text_content(Some(&information.description)); @@ -180,4 +170,636 @@ pub fn u64_to_bits(mut value: u64, bits: u64) -> String { output = output.chars().rev().collect::(); output +} + +pub fn visual_line_to_data(variable: &str, datapath_state: &UseReducerHandle) -> LineInformation { + match datapath_state.current_architecture { + AvailableDatapaths::MIPS => { + match variable { + "alu_input2" => LineInformation { + title: String::from("ALU Input 2"), + description: String::from("The second input to the ALU. This is determined by the ALUSrc control signal to select between register data, a sign-extended and left-shifted immediate value, or a zero-extended immediate value."), + value: datapath_state.mips.state.alu_input2, + bits: 64, + }, + "alu_result" => LineInformation { + title: String::from("ALU Result"), + description: String::from("The result of the calculation performed by the ALU. This is used either as an address to access memory or as a value that is saved into a register."), + value: datapath_state.mips.state.alu_result, + bits: 64, + }, + "data_result" => LineInformation { + title: String::from("Writeback Data"), + description: String::from("After finishing processing the instruction, this will either be the ALU result, data from memory, or PC + 4, based on the MemToReg control signal. This data is saved into registers."), + value: datapath_state.mips.state.data_result, + bits: 64, + }, + "fpu_alu_result" => LineInformation { + title: String::from("Floating-Point ALU Result"), + description: String::from("The result of the calculation performed by the floating-point ALU. This is used as an option to be written to a floating-point register, based on the DataWrite and FpuMemToReg control signals."), + value: datapath_state.mips.coprocessor.state.alu_result, + bits: 64, + }, + "fpu_branch_decision" => LineInformation { + title: String::from("FPU Branch Decision"), + description: String::from("Based on the true/false branch flag, determines whether to branch. (The FpuBranch control signal must also be set.)"), + value: datapath_state.mips.coprocessor.state.condition_code_mux as u64, + bits: 1, + }, + "fpu_branch_flag" => LineInformation { + title: String::from("Instruction [16] (True/False Branch Flag)"), + description: String::from("The true/false branch flag of branching datapath_state.mips.coprocessor instructions. This flag specifies whether a floating-point branch instruction is BC1T or BC1F."), + value: datapath_state.mips.coprocessor.state.branch_flag as u64, + bits: 1, + }, + "fpu_comparator_result" => LineInformation { + title: String::from("Floating-Point Comparator Result"), + description: String::from("The result of the comparison of two floating-point values. This is routed to the \"Condition Code\" (cc) register, and will be written there if the CcWrite control signal is set."), + value: datapath_state.mips.coprocessor.state.comparator_result, + bits: 64, + }, + "fpu_condition_code" => LineInformation { + title: String::from("Condition Code Value"), + description: String::from("Data retrieved from the \"Condition Code\" (cc) register. This specifies whether a previous conditional instruction was true or false."), + value: datapath_state.mips.coprocessor.state.condition_code_bit as u64, + bits: 1, + }, + "fpu_condition_code_inverted" => LineInformation { + title: String::from("Condition Code Value (Inverted)"), + description: String::from("Inverted form of the condition code register value."), + value: datapath_state.mips.coprocessor.state.condition_code_bit_inverted as u64, + bits: 1, + }, + "fpu_data" => LineInformation { + title: String::from("Floating-Point Data Register Value"), + description: String::from("Data retrieved from the \"Data\" register. This register acts as a means to communicate data between the main processor and floating-point datapath_state.mips.coprocessor in MTC1 and MFC1 instructions."), + value: datapath_state.mips.coprocessor.state.fmt as u64, + bits: 64, + }, + "fpu_data_writeback" => LineInformation { + title: String::from("Floating-Point Data Writeback"), + description: String::from("The value from the floating-point unit's \"Data\" register. Depending on the FpuRegWidth control signal, this will be 64-bit data or sign-extended 32-bit data."), + value: datapath_state.mips.coprocessor.state.data_writeback, + bits: 64, + }, + "fpu_destination" => LineInformation { + title: String::from("Floating-Point Write Register"), + description: String::from("The register that will be written to, assuming FpuRegWrite is set. Depending on the FpuRegDst control signal, this will consist of the fs, ft, or fd register."), + value: datapath_state.mips.coprocessor.state.destination as u64, + bits: 5, + }, + "fpu_fd" => LineInformation { + title: String::from("Instruction [10-6] (fd)"), + description: String::from("The fd field. Depending on the FpuRegDst control signal, this will be the register written to in a floating-point operation. This register is used as the destination for most floating-point arithmetic instructions."), + value: datapath_state.mips.coprocessor.state.fd as u64, + bits: 5, + }, + "fpu_fmt" => LineInformation { + title: String::from("Instruction [25-21] (fmt)"), + description: String::from("The fmt field. This is used to distinguish between single-precision and double-precision floating-point instructions."), + value: datapath_state.mips.coprocessor.state.fmt as u64, + bits: 5, + }, + "fpu_fp_register_data_from_main_processor" => LineInformation { + title: String::from("Writeback Data (To Floating-Point Coprocessor)"), + description: String::from("This data is written to a floating-point register, given FpuMemToReg is set. This line allows data to load from memory to a floating-point register, specifically in the case of the LWC1 instruction."), + value: datapath_state.mips.coprocessor.state.fp_register_data_from_main_processor, + bits: 64, + }, + "fpu_fp_register_to_memory" => LineInformation { + title: String::from("Memory Write Data (from FPU)"), + description: String::from("If the MemWriteSrc control signal is set, this data will be written to memory. This is used for the SWC1 instruction."), + value: datapath_state.mips.coprocessor.state.fp_register_to_memory, + bits: 64, + }, + "fpu_fs" => LineInformation { + title: String::from("Instruction [15-11] (fs)"), + description: String::from("The fs field. Contains the first register to be read for a floating-point instruction."), + value: datapath_state.mips.coprocessor.state.fs as u64, + bits: 5, + }, + "fpu_ft" => LineInformation { + title: String::from("Instruction [20-16] (ft)"), + description: String::from("The ft field. Contains the second register to be read for a floating-point instruction."), + value: datapath_state.mips.coprocessor.state.ft as u64, + bits: 5, + }, + "fpu_new_data" => LineInformation { + title: String::from("New Floating-Point Data Register Value"), + description: String::from("Data sent to the \"Data\" register. Depending on the DataSrc control signal, this will either be data from the main processor or the floating-point datapath_state.mips.coprocessor. This register acts as a means to communicate data between the main processor and floating-point datapath_state.mips.coprocessor in MTC1 and MFC1 instructions."), + value: datapath_state.mips.coprocessor.state.fmt as u64, + bits: 64, + }, + "fpu_read_data_1" => LineInformation { + title: String::from("FPU Read Data 1"), + description: String::from("Data retrieved from the register specified by the fs instruction field. This is used as the first inputs to the floating-point ALU and comparator. This can additionally be written to the \"Data\" register, based on the DataSrc and DataWrite control signals."), + value: datapath_state.mips.coprocessor.state.read_data_1, + bits: 64, + }, + "fpu_read_data_2" => LineInformation { + title: String::from("FPU Read Data 2"), + description: String::from("Data retrieved from the register specified by the ft instruction field. This is used as the second inputs to the floating-point ALU and comparator. This can additionally be used as data to be written to memory, based on the MemWriteSrc control signal."), + value: datapath_state.mips.coprocessor.state.read_data_2, + bits: 64, + }, + "fpu_register_write_data" => LineInformation { + title: String::from("FPU Register Write Data"), + description: String::from("Data that will be written to a floating-point register, given that FpuRegWrite is set."), + value: datapath_state.mips.coprocessor.state.register_write_data, + bits: 64, + }, + "fpu_register_write_mux_to_mux" => LineInformation { + title: String::from("FPU Register Write Data (When FpuMemToReg is Unset)"), + description: String::from("Based on the DataWrite control signal, this will either be the result of the floating-point ALU or the contents of the \"Data\" register. (The \"Data\" register is used for transferring data between the processor and floating-point datapath_state.mips.coprocessor.)"), + value: datapath_state.mips.coprocessor.state.register_write_mux_to_mux, + bits: 64, + }, + "fpu_sign_extend_data" => LineInformation { + title: String::from("Floating-Point Data Register Value (Sign-Extended)"), + description: String::from("In the case where FpuRegWidth indicates a 32-bit width, this is the bottom 32 bits of the value from the \"Data\" register, then sign-extended to 64 bits."), + value: datapath_state.mips.coprocessor.state.sign_extend_data, + bits: 64, + }, + "funct" => LineInformation { + title: String::from("Instruction [5-0] (funct)"), + description: String::from("The funct field. Contains the type of operation to execute for R-type instructions."), + value: datapath_state.mips.state.funct as u64, + bits: 6, + }, + "imm" => LineInformation { + title: String::from("Instruction [15-0] (immediate)"), + description: String::from("The immediate field. Contains the 16-bit constant value used for I-type instructions."), + value: datapath_state.mips.state.imm as u64, + bits: 16, + }, + "instruction" => LineInformation { + title: String::from("Instruction"), + description: String::from("The currently-loaded instruction. This is broken down into different fields, where each field serves a different purpose in identifying what the instruction does."), + value: datapath_state.mips.state.instruction as u64, + bits: 32, + }, + "jump_address" => LineInformation { + title: String::from("Jump Address"), + description: String::from("The concatenation of the upper 36 bits of PC + 4 with the lower 26 bits of the instruction, shifted left by 2. This is used as the new PC value for J-type instructions."), + value: datapath_state.mips.state.jump_address, + bits: 64, + }, + "lower_26" => LineInformation { + title: String::from("Instruction [25-0]"), + description: String::from("The lower 26 bits of instruction. This is used as part of the new PC value for J-type instructions."), + value: datapath_state.mips.state.lower_26 as u64, + bits: 26, + }, + "lower_26_shifted_left_by_2" => LineInformation { + title: String::from("Instruction [25-0] << 2"), + description: String::from("The lower 26 bits of instruction, shifted left by 2. This is used as part of the new PC value for J-type instructions."), + value: datapath_state.mips.state.lower_26_shifted_left_by_2 as u64, + bits: 28, + }, + "mem_mux1_to_mem_mux2" => LineInformation { + title: String::from("Relative PC Address"), + description: String::from("Based on the control signals for branching and jumping, this address may be the next PC value. This is used for general non-branching instructions or branch-type instructions."), + value: datapath_state.mips.state.mem_mux1_to_mem_mux2, + bits: 64, + }, + "memory_data" => LineInformation { + title: String::from("Memory Data"), + description: String::from("The data retrieved from memory, given that the MemRead control signal is set. This may be 32 bits or 64 bits, depending on the RegWidth control signal."), + value: datapath_state.mips.state.memory_data, + bits: 64, + }, + "new_pc" => LineInformation { + title: String::from("New Program Counter"), + description: String::from("The address of the next instruction to execute. In other words, the next value of the program counter (PC) register."), + value: datapath_state.mips.state.new_pc, + bits: 64, + }, + "pc" => LineInformation { + title: String::from("Program Counter"), + description: String::from("The address of the currently-executing instruction."), + value: datapath_state.mips.registers.pc, + bits: 64, + }, + "pc_plus_4" => LineInformation { + title: String::from("PC + 4"), + description: String::from("The address of the currently-executing instruction, plus 4. By default, this will become the next value of the PC register. However, a different address may be used in the case of a branch or jump instruction."), + value: datapath_state.mips.state.pc_plus_4, + bits: 64, + }, + "pc_plus_4_upper" => LineInformation { + title: String::from("PC + 4 [63-28]"), + description: String::from("The upper 36 bits of PC + 4. This is to be concatenated with the lower 26 bits of the instruction to calculate a jump address."), + value: datapath_state.mips.state.pc_plus_4 & 0xffff_ffff_f000_0000 >> 28, + bits: 36, + }, + "ra_id" => LineInformation { + title: String::from("Return Address Register Index"), + description: String::from("The value 31. This represents the thirty-second register, the return address register ($ra)."), + value: 31, + bits: 5, + }, + "rd" => LineInformation { + title: String::from("Instruction [15-11] (rd)"), + description: String::from("The rd field. Depending on the RegDst control signal, this will be the register written to for an instruction. This register is used as the destination for most R-type instructions."), + value: datapath_state.mips.state.rd as u64, + bits: 5, + }, + "read_data_1" => LineInformation { + title: String::from("Read Data 1"), + description: String::from("Data retrieved from the register specified by the rs instruction field. Based on the instruction, this may be used as the first input to the ALU, or the next value of the PC register."), + value: datapath_state.mips.state.read_data_1, + bits: 64, + }, + "read_data_2" => LineInformation { + title: String::from("Read Data 2"), + description: String::from("Data retrieved from the register specified by the rt instruction field. Based on the instruction, this may be used as the second input to the ALU, data written to memory, or data transferred to the floating-point coprocessor."), + value: datapath_state.mips.state.read_data_2, + bits: 64, + }, + "register_write_data" => LineInformation { + title: String::from("Register Write Data"), + description: String::from("Data that will be written to a general-purpose register, given that RegWrite is set."), + value: datapath_state.mips.state.register_write_data, + bits: 64, + }, + "relative_pc_branch" => LineInformation { + title: String::from("Relative PC Branch Address"), + description: String::from("The relative address used in branch instructions. This is the sum of PC + 4 and the sign-extended immediate value, shifted left by 2."), + value: datapath_state.mips.state.relative_pc_branch, + bits: 64, + }, + "rs" => LineInformation { + title: String::from("Instruction [25-21] (rs)"), + description: String::from("The rs field. Contains the first register to be read for an instruction."), + value: datapath_state.mips.state.rs as u64, + bits: 5, + }, + "rt" => LineInformation { + title: String::from("Instruction [20-16] (rt)"), + description: String::from("The rt field. Contains the second register to be read for an instruction."), + value: datapath_state.mips.state.rt as u64, + bits: 5, + }, + "shamt" => LineInformation { + title: String::from("Instruction [10-6] (shamt)"), + description: String::from("The shamt (\"shift amount\") field. Specifies the number of bits to shift for those instructions that perform bit-shifting."), + value: datapath_state.mips.state.shamt as u64, + bits: 5, + }, + "sign_extend" => LineInformation { + title: String::from("Sign-Extended Immediate"), + description: String::from("The immediate field, sign-extended to a 64-bit value."), + value: datapath_state.mips.state.sign_extend, + bits: 64, + }, + "sign_extend_shift_left_by_2" => LineInformation { + title: String::from("Sign-Extended Immediate << 2"), + description: String::from("The immediate field, sign-extended to a 64-bit value, then shifted left by 2."), + value: datapath_state.mips.state.sign_extend_shift_left_by_2, + bits: 64, + }, + "write_data" => LineInformation { + title: String::from("Memory Write Data"), + description: String::from("Given that the MemWrite control signal is set, this data will be written to memory."), + value: datapath_state.mips.state.write_data, + bits: 64, + }, + "write_register" => LineInformation { + title: String::from("Write Register"), + description: String::from("The register that will be written to, assuming RegWrite is set. Depending on the RegDst control signal, this will consist of the rs, rt, or rd register, or 31 (indicating the $ra register)."), + value: datapath_state.mips.state.write_register_destination as u64, + bits: 5, + }, + "zero_extended_immediate" => LineInformation { + title: String::from("Zero-Extended Immediate"), + description: String::from("The immediate field, zero-extended to a 64-bit value."), + value: datapath_state.mips.state.imm as u64, + bits: 64, + }, + _ => LineInformation { + title: String::from("[Title]"), + description: String::from("[Description]"), + value: 0, + bits: 0, + }, + } + }, + AvailableDatapaths::RISCV => { + // just a stand in + LineInformation { + title: String::from("ALU Input 2"), + description: String::from("The second input to the ALU. This is determined by the ALUSrc control signal to select between register data, a sign-extended and left-shifted immediate value, or a zero-extended immediate value."), + value: datapath_state.mips.state.alu_input2, + bits: 64 + } + // match variable { + // "alu_input2" => LineInformation { + // title: String::from("ALU Input 2"), + // description: String::from("The second input to the ALU. This is determined by the ALUSrc control signal to select between register data, a sign-extended and left-shifted immediate value, or a zero-extended immediate value."), + // value: datapath_state.riscv.state.alu_input2, + // bits: 64, + // }, + // "alu_result" => LineInformation { + // title: String::from("ALU Result"), + // description: String::from("The result of the calculation performed by the ALU. This is used either as an address to access memory or as a value that is saved into a register."), + // value: datapath_state.riscv.state.alu_result, + // bits: 64, + // }, + // "data_result" => LineInformation { + // title: String::from("Writeback Data"), + // description: String::from("After finishing processing the instruction, this will either be the ALU result, data from memory, or PC + 4, based on the MemToReg control signal. This data is saved into registers."), + // value: datapath_state.riscv.state.data_result, + // bits: 64, + // }, + // "fpu_alu_result" => LineInformation { + // title: String::from("Floating-Point ALU Result"), + // description: String::from("The result of the calculation performed by the floating-point ALU. This is used as an option to be written to a floating-point register, based on the DataWrite and FpuMemToReg control signals."), + // value: datapath_state.riscv.coprocessor.state.alu_result, + // bits: 64, + // }, + // "fpu_branch_decision" => LineInformation { + // title: String::from("FPU Branch Decision"), + // description: String::from("Based on the true/false branch flag, determines whether to branch. (The FpuBranch control signal must also be set.)"), + // value: datapath_state.riscv.coprocessor.state.condition_code_mux as u64, + // bits: 1, + // }, + // "fpu_branch_flag" => LineInformation { + // title: String::from("Instruction [16] (True/False Branch Flag)"), + // description: String::from("The true/false branch flag of branching coprocessor instructions. This flag specifies whether a floating-point branch instruction is BC1T or BC1F."), + // value: datapath_state.riscv.coprocessor.state.branch_flag as u64, + // bits: 1, + // }, + // "fpu_comparator_result" => LineInformation { + // title: String::from("Floating-Point Comparator Result"), + // description: String::from("The result of the comparison of two floating-point values. This is routed to the \"Condition Code\" (cc) register, and will be written there if the CcWrite control signal is set."), + // value: datapath_state.riscv.coprocessor.state.comparator_result, + // bits: 64, + // }, + // "fpu_condition_code" => LineInformation { + // title: String::from("Condition Code Value"), + // description: String::from("Data retrieved from the \"Condition Code\" (cc) register. This specifies whether a previous conditional instruction was true or false."), + // value: datapath_state.riscv.coprocessor.state.condition_code_bit as u64, + // bits: 1, + // }, + // "fpu_condition_code_inverted" => LineInformation { + // title: String::from("Condition Code Value (Inverted)"), + // description: String::from("Inverted form of the condition code register value."), + // value: datapath_state.riscv.coprocessor.state.condition_code_bit_inverted as u64, + // bits: 1, + // }, + // "fpu_data" => LineInformation { + // title: String::from("Floating-Point Data Register Value"), + // description: String::from("Data retrieved from the \"Data\" register. This register acts as a means to communicate data between the main processor and floating-point coprocessor in MTC1 and MFC1 instructions."), + // value: datapath_state.riscv.coprocessor.state.fmt as u64, + // bits: 64, + // }, + // "fpu_data_writeback" => LineInformation { + // title: String::from("Floating-Point Data Writeback"), + // description: String::from("The value from the floating-point unit's \"Data\" register. Depending on the FpuRegWidth control signal, this will be 64-bit data or sign-extended 32-bit data."), + // value: datapath_state.riscv.coprocessor.state.data_writeback, + // bits: 64, + // }, + // "fpu_destination" => LineInformation { + // title: String::from("Floating-Point Write Register"), + // description: String::from("The register that will be written to, assuming FpuRegWrite is set. Depending on the FpuRegDst control signal, this will consist of the fs, ft, or fd register."), + // value: datapath_state.riscv.coprocessor.state.destination as u64, + // bits: 5, + // }, + // "fpu_fd" => LineInformation { + // title: String::from("Instruction [10-6] (fd)"), + // description: String::from("The fd field. Depending on the FpuRegDst control signal, this will be the register written to in a floating-point operation. This register is used as the destination for most floating-point arithmetic instructions."), + // value: datapath_state.riscv.coprocessor.state.fd as u64, + // bits: 5, + // }, + // "fpu_fmt" => LineInformation { + // title: String::from("Instruction [25-21] (fmt)"), + // description: String::from("The fmt field. This is used to distinguish between single-precision and double-precision floating-point instructions."), + // value: datapath_state.riscv.coprocessor.state.fmt as u64, + // bits: 5, + // }, + // "fpu_fp_register_data_from_main_processor" => LineInformation { + // title: String::from("Writeback Data (To Floating-Point Coprocessor)"), + // description: String::from("This data is written to a floating-point register, given FpuMemToReg is set. This line allows data to load from memory to a floating-point register, specifically in the case of the LWC1 instruction."), + // value: datapath_state.riscv.coprocessor.state.fp_register_data_from_main_processor, + // bits: 64, + // }, + // "fpu_fp_register_to_memory" => LineInformation { + // title: String::from("Memory Write Data (from FPU)"), + // description: String::from("If the MemWriteSrc control signal is set, this data will be written to memory. This is used for the SWC1 instruction."), + // value: datapath_state.riscv.coprocessor.state.fp_register_to_memory, + // bits: 64, + // }, + // "fpu_fs" => LineInformation { + // title: String::from("Instruction [15-11] (fs)"), + // description: String::from("The fs field. Contains the first register to be read for a floating-point instruction."), + // value: datapath_state.riscv.coprocessor.state.fs as u64, + // bits: 5, + // }, + // "fpu_ft" => LineInformation { + // title: String::from("Instruction [20-16] (ft)"), + // description: String::from("The ft field. Contains the second register to be read for a floating-point instruction."), + // value: datapath_state.riscv.coprocessor.state.ft as u64, + // bits: 5, + // }, + // "fpu_new_data" => LineInformation { + // title: String::from("New Floating-Point Data Register Value"), + // description: String::from("Data sent to the \"Data\" register. Depending on the DataSrc control signal, this will either be data from the main processor or the floating-point coprocessor. This register acts as a means to communicate data between the main processor and floating-point coprocessor in MTC1 and MFC1 instructions."), + // value: datapath_state.riscv.coprocessor.state.fmt as u64, + // bits: 64, + // }, + // "fpu_read_data_1" => LineInformation { + // title: String::from("FPU Read Data 1"), + // description: String::from("Data retrieved from the register specified by the fs instruction field. This is used as the first inputs to the floating-point ALU and comparator. This can additionally be written to the \"Data\" register, based on the DataSrc and DataWrite control signals."), + // value: datapath_state.riscv.coprocessor.state.read_data_1, + // bits: 64, + // }, + // "fpu_read_data_2" => LineInformation { + // title: String::from("FPU Read Data 2"), + // description: String::from("Data retrieved from the register specified by the ft instruction field. This is used as the second inputs to the floating-point ALU and comparator. This can additionally be used as data to be written to memory, based on the MemWriteSrc control signal."), + // value: datapath_state.riscv.coprocessor.state.read_data_2, + // bits: 64, + // }, + // "fpu_register_write_data" => LineInformation { + // title: String::from("FPU Register Write Data"), + // description: String::from("Data that will be written to a floating-point register, given that FpuRegWrite is set."), + // value: datapath_state.riscv.coprocessor.state.register_write_data, + // bits: 64, + // }, + // "fpu_register_write_mux_to_mux" => LineInformation { + // title: String::from("FPU Register Write Data (When FpuMemToReg is Unset)"), + // description: String::from("Based on the DataWrite control signal, this will either be the result of the floating-point ALU or the contents of the \"Data\" register. (The \"Data\" register is used for transferring data between the processor and floating-point coprocessor.)"), + // value: datapath_state.riscv.coprocessor.state.register_write_mux_to_mux, + // bits: 64, + // }, + // "fpu_sign_extend_data" => LineInformation { + // title: String::from("Floating-Point Data Register Value (Sign-Extended)"), + // description: String::from("In the case where FpuRegWidth indicates a 32-bit width, this is the bottom 32 bits of the value from the \"Data\" register, then sign-extended to 64 bits."), + // value: datapath_state.riscv.coprocessor.state.sign_extend_data, + // bits: 64, + // }, + // "funct" => LineInformation { + // title: String::from("Instruction [5-0] (funct)"), + // description: String::from("The funct field. Contains the type of operation to execute for R-type instructions."), + // value: datapath_state.riscv.state.funct as u64, + // bits: 6, + // }, + // "imm" => LineInformation { + // title: String::from("Instruction [15-0] (immediate)"), + // description: String::from("The immediate field. Contains the 16-bit constant value used for I-type instructions."), + // value: datapath_state.riscv.state.imm as u64, + // bits: 16, + // }, + // "instruction" => LineInformation { + // title: String::from("Instruction"), + // description: String::from("The currently-loaded instruction. This is broken down into different fields, where each field serves a different purpose in identifying what the instruction does."), + // value: datapath_state.riscv.state.instruction as u64, + // bits: 32, + // }, + // "jump_address" => LineInformation { + // title: String::from("Jump Address"), + // description: String::from("The concatenation of the upper 36 bits of PC + 4 with the lower 26 bits of the instruction, shifted left by 2. This is used as the new PC value for J-type instructions."), + // value: datapath_state.riscv.state.jump_address, + // bits: 64, + // }, + // "lower_26" => LineInformation { + // title: String::from("Instruction [25-0]"), + // description: String::from("The lower 26 bits of instruction. This is used as part of the new PC value for J-type instructions."), + // value: datapath_state.riscv.state.lower_26 as u64, + // bits: 26, + // }, + // "lower_26_shifted_left_by_2" => LineInformation { + // title: String::from("Instruction [25-0] << 2"), + // description: String::from("The lower 26 bits of instruction, shifted left by 2. This is used as part of the new PC value for J-type instructions."), + // value: datapath_state.riscv.state.lower_26_shifted_left_by_2 as u64, + // bits: 28, + // }, + // "mem_mux1_to_mem_mux2" => LineInformation { + // title: String::from("Relative PC Address"), + // description: String::from("Based on the control signals for branching and jumping, this address may be the next PC value. This is used for general non-branching instructions or branch-type instructions."), + // value: datapath_state.riscv.state.mem_mux1_to_mem_mux2, + // bits: 64, + // }, + // "memory_data" => LineInformation { + // title: String::from("Memory Data"), + // description: String::from("The data retrieved from memory, given that the MemRead control signal is set. This may be 32 bits or 64 bits, depending on the RegWidth control signal."), + // value: datapath_state.riscv.state.memory_data, + // bits: 64, + // }, + // "new_pc" => LineInformation { + // title: String::from("New Program Counter"), + // description: String::from("The address of the next instruction to execute. In other words, the next value of the program counter (PC) register."), + // value: datapath_state.riscv.state.new_pc, + // bits: 64, + // }, + // "pc" => LineInformation { + // title: String::from("Program Counter"), + // description: String::from("The address of the currently-executing instruction."), + // value: datapath_state.riscv.registers.pc, + // bits: 64, + // }, + // "pc_plus_4" => LineInformation { + // title: String::from("PC + 4"), + // description: String::from("The address of the currently-executing instruction, plus 4. By default, this will become the next value of the PC register. However, a different address may be used in the case of a branch or jump instruction."), + // value: datapath_state.riscv.state.pc_plus_4, + // bits: 64, + // }, + // "pc_plus_4_upper" => LineInformation { + // title: String::from("PC + 4 [63-28]"), + // description: String::from("The upper 36 bits of PC + 4. This is to be concatenated with the lower 26 bits of the instruction to calculate a jump address."), + // value: datapath_state.riscv.state.pc_plus_4 & 0xffff_ffff_f000_0000 >> 28, + // bits: 36, + // }, + // "ra_id" => LineInformation { + // title: String::from("Return Address Register Index"), + // description: String::from("The value 31. This represents the thirty-second register, the return address register ($ra)."), + // value: 31, + // bits: 5, + // }, + // "rd" => LineInformation { + // title: String::from("Instruction [15-11] (rd)"), + // description: String::from("The rd field. Depending on the RegDst control signal, this will be the register written to for an instruction. This register is used as the destination for most R-type instructions."), + // value: datapath_state.riscv.state.rd as u64, + // bits: 5, + // }, + // "read_data_1" => LineInformation { + // title: String::from("Read Data 1"), + // description: String::from("Data retrieved from the register specified by the rs instruction field. Based on the instruction, this may be used as the first input to the ALU, or the next value of the PC register."), + // value: datapath_state.riscv.state.read_data_1, + // bits: 64, + // }, + // "read_data_2" => LineInformation { + // title: String::from("Read Data 2"), + // description: String::from("Data retrieved from the register specified by the rt instruction field. Based on the instruction, this may be used as the second input to the ALU, data written to memory, or data transferred to the floating-point coprocessor."), + // value: datapath_state.riscv.state.read_data_2, + // bits: 64, + // }, + // "register_write_data" => LineInformation { + // title: String::from("Register Write Data"), + // description: String::from("Data that will be written to a general-purpose register, given that RegWrite is set."), + // value: datapath_state.riscv.state.register_write_data, + // bits: 64, + // }, + // "relative_pc_branch" => LineInformation { + // title: String::from("Relative PC Branch Address"), + // description: String::from("The relative address used in branch instructions. This is the sum of PC + 4 and the sign-extended immediate value, shifted left by 2."), + // value: datapath_state.riscv.state.relative_pc_branch, + // bits: 64, + // }, + // "rs" => LineInformation { + // title: String::from("Instruction [25-21] (rs)"), + // description: String::from("The rs field. Contains the first register to be read for an instruction."), + // value: datapath_state.riscv.state.rs as u64, + // bits: 5, + // }, + // "rt" => LineInformation { + // title: String::from("Instruction [20-16] (rt)"), + // description: String::from("The rt field. Contains the second register to be read for an instruction."), + // value: datapath_state.riscv.state.rt as u64, + // bits: 5, + // }, + // "shamt" => LineInformation { + // title: String::from("Instruction [10-6] (shamt)"), + // description: String::from("The shamt (\"shift amount\") field. Specifies the number of bits to shift for those instructions that perform bit-shifting."), + // value: datapath_state.riscv.state.shamt as u64, + // bits: 5, + // }, + // "sign_extend" => LineInformation { + // title: String::from("Sign-Extended Immediate"), + // description: String::from("The immediate field, sign-extended to a 64-bit value."), + // value: datapath_state.riscv.state.sign_extend, + // bits: 64, + // }, + // "sign_extend_shift_left_by_2" => LineInformation { + // title: String::from("Sign-Extended Immediate << 2"), + // description: String::from("The immediate field, sign-extended to a 64-bit value, then shifted left by 2."), + // value: datapath_state.riscv.state.sign_extend_shift_left_by_2, + // bits: 64, + // }, + // "write_data" => LineInformation { + // title: String::from("Memory Write Data"), + // description: String::from("Given that the MemWrite control signal is set, this data will be written to memory."), + // value: datapath_state.riscv.state.write_data, + // bits: 64, + // }, + // "write_register" => LineInformation { + // title: String::from("Write Register"), + // description: String::from("The register that will be written to, assuming RegWrite is set. Depending on the RegDst control signal, this will consist of the rs, rt, or rd register, or 31 (indicating the $ra register)."), + // value: datapath_state.riscv.state.write_register_destination as u64, + // bits: 5, + // }, + // "zero_extended_immediate" => LineInformation { + // title: String::from("Zero-Extended Immediate"), + // description: String::from("The immediate field, zero-extended to a 64-bit value."), + // value: datapath_state.riscv.state.imm as u64, + // bits: 64, + // }, + // _ => LineInformation { + // title: String::from("[Title]"), + // description: String::from("[Description]"), + // value: 0, + // bits: 0, + // }, + // } + } + } } \ No newline at end of file From b8b2cfe0f9f50a861e2cf681d96a9b4acf469fba Mon Sep 17 00:00:00 2001 From: Cay Date: Fri, 1 Mar 2024 17:47:39 -0500 Subject: [PATCH 114/355] Switch to using datapath_state and remove logs/unused code --- src/agent/datapath_reducer.rs | 2 +- src/bin/main.rs | 2 +- src/ui/regview/component.rs | 275 ++++------------------------------ 3 files changed, 29 insertions(+), 250 deletions(-) diff --git a/src/agent/datapath_reducer.rs b/src/agent/datapath_reducer.rs index c6edea99e..ea843b464 100644 --- a/src/agent/datapath_reducer.rs +++ b/src/agent/datapath_reducer.rs @@ -74,7 +74,7 @@ impl Reducible for DatapathReducer { memory: self.mips.memory.clone(), current_stage: self.mips.current_stage.clone(), coprocessor - }, + } }, }, }) diff --git a/src/bin/main.rs b/src/bin/main.rs index 02a46ef31..f7e9bc400 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -526,7 +526,7 @@ fn app(props: &AppProps) -> Html { // Right column - + } diff --git a/src/ui/regview/component.rs b/src/ui/regview/component.rs index 156bf5c6d..e7736bdbb 100644 --- a/src/ui/regview/component.rs +++ b/src/ui/regview/component.rs @@ -33,6 +33,7 @@ pub struct InputData { } //Convert register to html through iterator +// ============= General Purpose Registers ============= pub fn generate_gpr_rows(props: &Regviewprops, radix: u32) -> Html { let communicator = props.communicator; let pc_limit = props.pc_limit; @@ -79,88 +80,6 @@ pub fn generate_gpr_rows(props: &Regviewprops, radix: u32) -> Html { }) .collect::() } -pub fn generate_gpr_rows_hex(props: &Regviewprops) -> Html { - let communicator = props.communicator; - let pc_limit = props.pc_limit; - - props - .gp - .into_iter() - .map(|(register, data)| { - html! { - - {register.get_gpr_name()} - - (); - let input_string = input.value(); - let val = match u64::from_str_radix(&input_string[2..], 16) { - Ok(value) => { - input.set_class_name("valid"); - value - }, - Err(_err) => { - input.set_class_name("invalid"); - return - } - }; - if register.is_valid_register_value(val, pc_limit) { - communicator.set_register(register.to_string(), val); - input.set_class_name("valid"); - } else { - input.set_class_name("invalid"); - } - }} - value={format!("{data:#04x?}").to_string()}/> - - - } - }) - .collect::() -} -pub fn generate_gpr_rows_bin(props: &Regviewprops) -> Html { - let communicator = props.communicator; - let pc_limit = props.pc_limit; - - props - .gp - .into_iter() - .map(|(register, data)| { - html! { - - {register.get_gpr_name()} - - (); - let input_string = input.value(); - let val = match u64::from_str_radix(&input_string[2..], 2) { - Ok(value) => { - input.set_class_name("valid"); - value - }, - Err(_err) => { - input.set_class_name("invalid"); - return - } - }; - if register.is_valid_register_value(val, pc_limit) { - communicator.set_register(register.to_string(), val); - input.set_class_name("valid"); - } else { - input.set_class_name("invalid"); - } - }} - value={format!("{data:#b}").to_string()}/> - - - } - }) - .collect::() -} // ============= Coprocessor Registers ============= pub fn generate_fpr_rows(props: &Regviewprops, unit_type: UnitState) -> Html { @@ -203,7 +122,7 @@ pub fn generate_fpr_rows(props: &Regviewprops, unit_type: UnitState) -> Html { } } }, - _ => { + UnitState::Hex => { match u64::from_str_radix(&input_string[2..], 16) { Ok(value) => { input.set_class_name("valid"); @@ -214,9 +133,33 @@ pub fn generate_fpr_rows(props: &Regviewprops, unit_type: UnitState) -> Html { return } } + }, + UnitState::Bin => { + match u64::from_str_radix(&input_string[2..], 2) { + Ok(value) => { + input.set_class_name("valid"); + value as u64 + }, + Err(_err) => { + input.set_class_name("invalid"); + return + } + } + }, + _ => { + match input_string.parse::() { + Ok(value) => { + input.set_class_name("valid"); + value + }, + Err(_err) => { + input.set_class_name("invalid"); + return + } + } } }; - communicator.set_register(register.to_string(), value); + communicator.set_fp_register(register.to_string(), value); if register.is_valid_register_value(value) { input.set_class_name("valid"); } else { @@ -238,170 +181,6 @@ pub fn generate_fpr_rows(props: &Regviewprops, unit_type: UnitState) -> Html { }) .collect::() } -pub fn generate_fpr_rows_hex(props: &Regviewprops) -> Html { - let communicator = props.communicator; - - props - .fp - .into_iter() - .map(|(register, data)| { - html! { - - {format!("f{register}")} - - (); - let input_string = input.value(); - let val = match u64::from_str_radix(&input_string[2..], 16) { - Ok(value) => { - input.set_class_name("valid"); - value - }, - Err(_err) => { - input.set_class_name("invalid"); - return - } - }; - log::debug!("{val:#04x?}"); - communicator.set_register(register.to_string(), val); - if register.is_valid_register_value(val) { - input.set_class_name("valid"); - } else { - input.set_class_name("invalid"); - } - }} - value={format!("{data:#04x?}").to_string()}/> - - - } - }) - .collect::() -} -pub fn generate_fpr_rows_bin(props: &Regviewprops) -> Html { - let communicator = props.communicator; - - props - .fp - .into_iter() - .map(|(register, data)| { - html! { - - {format!("f{register}")} - - (); - let input_string = input.value(); - let val = match u64::from_str_radix(&input_string[2..], 2) { - Ok(value) => { - input.set_class_name("valid"); - value - }, - Err(_err) => { - input.set_class_name("invalid"); - return - } - }; - log::debug!("{val:#b}"); - communicator.set_register(register.to_string(), val); - if register.is_valid_register_value(val) { - input.set_class_name("valid"); - } else { - input.set_class_name("invalid"); - } - }} - value={format!("{data:#b}").to_string()}/> - - - } - }) - .collect::() -} - -pub fn generate_fpr_rows_float(props: &Regviewprops) -> Html { - let communicator = props.communicator; - - props.fp.into_iter() - .map(|(register, data)| { - html! { - - {format!("f{register}")} - - (); - let input_string = input.value(); - let value = match input_string.parse::() { - Ok(value) => { - input.set_class_name("valid"); - value - }, - Err(_err) => { - input.set_class_name("invalid"); - return - } - }; - log::debug!("{:e}", value); - communicator.set_register(register.to_string(), value as u64); - if register.is_valid_register_value(value as u64) { - input.set_class_name("valid"); - } else { - input.set_class_name("invalid"); - } - }} - value={format!("{:e}",f32::from_bits((data).try_into().unwrap())).to_string()}/> - - - } - }) - .collect::() -} - -pub fn generate_fpr_rows_double(props: &Regviewprops) -> Html { - let communicator = props.communicator; - - props - .fp - .into_iter() - .map(|(register, data)| { - html! { - - {format!("f{register}")} - - (); - let input_string = input.value(); - let value = match input_string.parse::() { - Ok(value) => { - input.set_class_name("valid"); - value - }, - Err(_err) => { - input.set_class_name("invalid"); - return - } - }; - log::debug!("{:e}", value); - communicator.set_register(register.to_string(), value as u64); - if register.is_valid_register_value(value as u64) { - input.set_class_name("valid"); - } else { - input.set_class_name("invalid"); - } - }} - value={format!("{:e}", f64::from_bits(data)).to_string()}/> - - - } - }) - .collect::() -} #[function_component(Regview)] pub fn regview(props: &Regviewprops) -> Html { From c4e5a185bb0e70dfae8119168df59e6e78b3220f Mon Sep 17 00:00:00 2001 From: Cay Date: Fri, 1 Mar 2024 17:51:05 -0500 Subject: [PATCH 115/355] Run cargo fmt --- src/agent.rs | 8 ++++++-- src/agent/datapath_reducer.rs | 4 ++-- src/agent/messages.rs | 2 +- src/emulation_core/mips/control_signals.rs | 2 +- src/emulation_core/mips/coprocessor.rs | 2 +- src/emulation_core/mips/instruction.rs | 2 +- src/emulation_core/mips/line_info.rs | 7 +++++-- src/parser/parser_assembler_main.rs | 6 ++++-- src/ui/footer/component.rs | 2 +- src/ui/visual_datapath/mod.rs | 6 +++++- src/ui/visual_datapath/utils.rs | 17 +++++++++++++---- 11 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index 794b80830..13c4f742d 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -58,8 +58,12 @@ pub async fn emulation_core_agent(scope: ReactorScope) DatapathUpdate::MIPS(MipsStateUpdate::UpdateRegisters(datapath.registers)); let memory_update = DatapathUpdate::MIPS(MipsStateUpdate::UpdateMemory(datapath.memory.clone())); - let stage_update = DatapathUpdate::MIPS(MipsStateUpdate::UpdateStage(datapath.current_stage.clone())); - let coprocessor_update = DatapathUpdate::MIPS(MipsStateUpdate::UpdateCoprocessor(datapath.coprocessor.clone())); + let stage_update = DatapathUpdate::MIPS(MipsStateUpdate::UpdateStage( + datapath.current_stage.clone(), + )); + let coprocessor_update = DatapathUpdate::MIPS(MipsStateUpdate::UpdateCoprocessor( + datapath.coprocessor.clone(), + )); state.scope.send(state_update).await.unwrap(); state.scope.send(register_update).await.unwrap(); state.scope.send(memory_update).await.unwrap(); diff --git a/src/agent/datapath_reducer.rs b/src/agent/datapath_reducer.rs index dcbe98b5a..9af82706b 100644 --- a/src/agent/datapath_reducer.rs +++ b/src/agent/datapath_reducer.rs @@ -20,7 +20,7 @@ pub struct MipsCoreState { pub registers: GpRegisters, pub memory: Memory, pub current_stage: Stage, - pub coprocessor: MipsFpCoprocessor + pub coprocessor: MipsFpCoprocessor, } impl Default for DatapathReducer { @@ -73,7 +73,7 @@ impl Reducible for DatapathReducer { registers: self.mips.registers, memory: self.mips.memory.clone(), current_stage: self.mips.current_stage.clone(), - coprocessor + coprocessor, }, }, }, diff --git a/src/agent/messages.rs b/src/agent/messages.rs index d44f41dd3..8de055b0a 100644 --- a/src/agent/messages.rs +++ b/src/agent/messages.rs @@ -1,8 +1,8 @@ use crate::emulation_core::mips::coprocessor::MipsFpCoprocessor; -use crate::emulation_core::{architectures::AvailableDatapaths, mips::datapath::Stage}; use crate::emulation_core::mips::datapath::DatapathState; use crate::emulation_core::mips::memory::Memory; use crate::emulation_core::mips::registers::GpRegisters; +use crate::emulation_core::{architectures::AvailableDatapaths, mips::datapath::Stage}; use serde::{Deserialize, Serialize}; /// Commands sent from the UI thread to the worker thread. diff --git a/src/emulation_core/mips/control_signals.rs b/src/emulation_core/mips/control_signals.rs index 2336fc558..e7f11de77 100644 --- a/src/emulation_core/mips/control_signals.rs +++ b/src/emulation_core/mips/control_signals.rs @@ -278,8 +278,8 @@ pub enum RegWrite { } pub mod floating_point { - use serde::{Deserialize, Serialize}; use super::super::constants::*; + use serde::{Deserialize, Serialize}; #[derive(Clone, Default, PartialEq, Serialize, Deserialize, Debug)] pub struct FpuControlSignals { diff --git a/src/emulation_core/mips/coprocessor.rs b/src/emulation_core/mips/coprocessor.rs index 8a3e75146..2b8b29a2a 100644 --- a/src/emulation_core/mips/coprocessor.rs +++ b/src/emulation_core/mips/coprocessor.rs @@ -1,9 +1,9 @@ //! Implementation of a MIPS64 floating-point coprocessor. -use serde::{Deserialize, Serialize}; use super::constants::*; use super::control_signals::floating_point::*; use super::instruction::Instruction; +use serde::{Deserialize, Serialize}; /// An implementation of a floating-point coprocessor for the MIPS64 ISA. /// diff --git a/src/emulation_core/mips/instruction.rs b/src/emulation_core/mips/instruction.rs index 70a45b0f9..d321f57b7 100644 --- a/src/emulation_core/mips/instruction.rs +++ b/src/emulation_core/mips/instruction.rs @@ -1,7 +1,7 @@ //! Abstract representation of an instruction. -use serde::{Deserialize, Serialize}; use crate::parser::parser_structs_and_enums::GP_REGISTERS; +use serde::{Deserialize, Serialize}; use super::constants::*; diff --git a/src/emulation_core/mips/line_info.rs b/src/emulation_core/mips/line_info.rs index 1467d8e16..e8c18dc08 100644 --- a/src/emulation_core/mips/line_info.rs +++ b/src/emulation_core/mips/line_info.rs @@ -1,8 +1,8 @@ //! Module for mapping lines in the visual datapath to information //! and variables in the coded datapath. -use yew::UseReducerHandle; use crate::agent::datapath_reducer::DatapathReducer; +use yew::UseReducerHandle; use super::super::datapath::VisualDatapath; use super::datapath::MipsDatapath; @@ -334,7 +334,10 @@ impl VisualDatapath for MipsDatapath { } } -pub fn visual_line_to_data(variable: &str, datapath_state: &UseReducerHandle) -> LineInformation { +pub fn visual_line_to_data( + variable: &str, + datapath_state: &UseReducerHandle, +) -> LineInformation { match variable { "alu_input2" => LineInformation { title: String::from("ALU Input 2"), diff --git a/src/parser/parser_assembler_main.rs b/src/parser/parser_assembler_main.rs index 4a04a7c81..b345be4ea 100644 --- a/src/parser/parser_assembler_main.rs +++ b/src/parser/parser_assembler_main.rs @@ -56,7 +56,8 @@ pub fn parser(file_string: String) -> (ProgramInfo, Vec) { &mut program_info.monaco_line_info, ); - let (binary, data_starting_point) = create_binary_vec(program_info.instructions.clone(), vec_of_data); + let (binary, data_starting_point) = + create_binary_vec(program_info.instructions.clone(), vec_of_data); for entry in &program_info.monaco_line_info { program_info @@ -115,7 +116,8 @@ pub fn parser(file_string: String) -> (ProgramInfo, Vec) { &mut program_info.monaco_line_info, ); - let (binary, data_starting_point) = create_binary_vec(program_info.instructions.clone(), vec_of_data); + let (binary, data_starting_point) = + create_binary_vec(program_info.instructions.clone(), vec_of_data); for entry in &program_info.monaco_line_info { program_info diff --git a/src/ui/footer/component.rs b/src/ui/footer/component.rs index 70a03086b..76b794cc8 100644 --- a/src/ui/footer/component.rs +++ b/src/ui/footer/component.rs @@ -1,4 +1,5 @@ use crate::agent::datapath_communicator::DatapathCommunicator; +use crate::agent::datapath_reducer::DatapathReducer; use crate::ui::console::component::Console; use crate::ui::hex_editor::component::HexEditor; use crate::ui::visual_datapath::VisualDatapath; @@ -7,7 +8,6 @@ use wasm_bindgen::JsCast; use web_sys::HtmlElement; use yew::prelude::*; use yew_hooks::prelude::*; -use crate::agent::datapath_reducer::DatapathReducer; #[derive(PartialEq, Properties)] pub struct Footerprops { diff --git a/src/ui/visual_datapath/mod.rs b/src/ui/visual_datapath/mod.rs index 7bb01ef1f..e5afc9c4e 100644 --- a/src/ui/visual_datapath/mod.rs +++ b/src/ui/visual_datapath/mod.rs @@ -206,7 +206,11 @@ impl VisualDatapath { /// circumvented by creating an event listener on the `` element for the /// "load" event, which will guarantee when that virtual DOM is actually ready /// to be manipulated. - pub fn initialize(&mut self, current_stage: String, datapath_state: UseReducerHandle) { + pub fn initialize( + &mut self, + current_stage: String, + datapath_state: UseReducerHandle, + ) { let on_load = Callback::from(move |_| { let nodes = get_g_elements(); diff --git a/src/ui/visual_datapath/utils.rs b/src/ui/visual_datapath/utils.rs index aaa43107c..f0c67597a 100644 --- a/src/ui/visual_datapath/utils.rs +++ b/src/ui/visual_datapath/utils.rs @@ -5,7 +5,10 @@ use wasm_bindgen::JsCast; use web_sys::{Element, HtmlCollection, HtmlElement, HtmlObjectElement, MouseEvent}; use yew::UseReducerHandle; -use crate::{agent::datapath_reducer::DatapathReducer, emulation_core::{architectures::AvailableDatapaths, mips::line_info::LineInformation}}; +use crate::{ + agent::datapath_reducer::DatapathReducer, + emulation_core::{architectures::AvailableDatapaths, mips::line_info::LineInformation}, +}; use super::consts::*; @@ -139,7 +142,10 @@ where /// Parameters: /// - `datapath`: A reference to the datapath that information will be pulled from. /// - `variable`: The "variable" attribute of the line in the diagram that will have information. -pub fn populate_popup_information(datapath_state: &UseReducerHandle, variable: &str) { +pub fn populate_popup_information( + datapath_state: &UseReducerHandle, + variable: &str, +) { let popup = get_popup_element(); let title = popup.query_selector(".title").unwrap().unwrap(); @@ -172,7 +178,10 @@ pub fn u64_to_bits(mut value: u64, bits: u64) -> String { output } -pub fn visual_line_to_data(variable: &str, datapath_state: &UseReducerHandle) -> LineInformation { +pub fn visual_line_to_data( + variable: &str, + datapath_state: &UseReducerHandle, +) -> LineInformation { match datapath_state.current_architecture { AvailableDatapaths::MIPS => { match variable { @@ -802,4 +811,4 @@ pub fn visual_line_to_data(variable: &str, datapath_state: &UseReducerHandle Date: Fri, 1 Mar 2024 17:54:28 -0500 Subject: [PATCH 116/355] Run clippy --- src/agent.rs | 2 +- src/agent/datapath_reducer.rs | 8 ++++---- src/ui/visual_datapath/mod.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/agent.rs b/src/agent.rs index 13c4f742d..991b11199 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -59,7 +59,7 @@ pub async fn emulation_core_agent(scope: ReactorScope) let memory_update = DatapathUpdate::MIPS(MipsStateUpdate::UpdateMemory(datapath.memory.clone())); let stage_update = DatapathUpdate::MIPS(MipsStateUpdate::UpdateStage( - datapath.current_stage.clone(), + datapath.current_stage, )); let coprocessor_update = DatapathUpdate::MIPS(MipsStateUpdate::UpdateCoprocessor( datapath.coprocessor.clone(), diff --git a/src/agent/datapath_reducer.rs b/src/agent/datapath_reducer.rs index 9af82706b..c14bdad90 100644 --- a/src/agent/datapath_reducer.rs +++ b/src/agent/datapath_reducer.rs @@ -44,21 +44,21 @@ impl Reducible for DatapathReducer { state, registers: self.mips.registers, memory: self.mips.memory.clone(), - current_stage: self.mips.current_stage.clone(), + current_stage: self.mips.current_stage, coprocessor: self.mips.coprocessor.clone(), }, MipsStateUpdate::UpdateRegisters(registers) => MipsCoreState { state: self.mips.state.clone(), registers, memory: self.mips.memory.clone(), - current_stage: self.mips.current_stage.clone(), + current_stage: self.mips.current_stage, coprocessor: self.mips.coprocessor.clone(), }, MipsStateUpdate::UpdateMemory(memory) => MipsCoreState { state: self.mips.state.clone(), registers: self.mips.registers, memory, - current_stage: self.mips.current_stage.clone(), + current_stage: self.mips.current_stage, coprocessor: self.mips.coprocessor.clone(), }, MipsStateUpdate::UpdateStage(stage) => MipsCoreState { @@ -72,7 +72,7 @@ impl Reducible for DatapathReducer { state: self.mips.state.clone(), registers: self.mips.registers, memory: self.mips.memory.clone(), - current_stage: self.mips.current_stage.clone(), + current_stage: self.mips.current_stage, coprocessor, }, }, diff --git a/src/ui/visual_datapath/mod.rs b/src/ui/visual_datapath/mod.rs index e5afc9c4e..b4a9125ce 100644 --- a/src/ui/visual_datapath/mod.rs +++ b/src/ui/visual_datapath/mod.rs @@ -85,7 +85,7 @@ impl Component for VisualDatapath { html! {
- +