Compare commits
10 commits
96202c0d1a
...
837f611955
Author | SHA1 | Date | |
---|---|---|---|
|
837f611955 | ||
|
7e7cd5d7b6 | ||
|
1913df1f3d | ||
|
386a3b7403 | ||
|
ac07031631 | ||
|
29a7dfa277 | ||
|
fc429dedbf | ||
|
98c8e3d4eb | ||
|
3ee54491be | ||
|
6d81417701 |
14 changed files with 1368 additions and 418 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1 +1,3 @@
|
||||||
/target
|
/target
|
||||||
|
|
||||||
|
test.bin
|
||||||
|
|
221
Cargo.lock
generated
221
Cargo.lock
generated
|
@ -4,15 +4,27 @@ version = 3
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.79"
|
version = "1.0.82"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
|
checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitfield"
|
name = "bitfield"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac"
|
checksum = "c821a6e124197eb56d907ccc2188eab1038fb919c914f47976e64dd8dbc855d1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codespan-reporting"
|
name = "codespan-reporting"
|
||||||
|
@ -31,7 +43,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
|
checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"windows-sys",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -61,19 +73,29 @@ checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.9.0"
|
version = "1.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.12.0"
|
version = "0.12.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kernel32-sys"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
"winapi-build",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
@ -82,15 +104,32 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.152"
|
version = "0.2.154"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
|
checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libredox"
|
||||||
|
version = "0.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.5.0",
|
||||||
|
"libc",
|
||||||
|
"redox_syscall",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "numtoa"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayon"
|
name = "rayon"
|
||||||
version = "1.8.1"
|
version = "1.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051"
|
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
"rayon-core",
|
"rayon-core",
|
||||||
|
@ -107,7 +146,22 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "riscv_interpreter"
|
name = "redox_syscall"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_termios"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rizz-v"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
@ -117,14 +171,16 @@ dependencies = [
|
||||||
"itertools",
|
"itertools",
|
||||||
"rayon",
|
"rayon",
|
||||||
"term_size",
|
"term_size",
|
||||||
|
"termion",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "term_size"
|
name = "term_size"
|
||||||
version = "0.3.2"
|
version = "1.0.0-beta1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9"
|
checksum = "a8a17d8699e154863becdf18e4fd28bd0be27ca72856f54daf75c00f2566898f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"kernel32-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
@ -139,49 +195,60 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "termion"
|
||||||
version = "0.1.11"
|
version = "3.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
|
checksum = "417813675a504dfbbf21bfde32c03e5bf9f2413999962b479023c02848c1c7a5"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"libredox",
|
||||||
|
"numtoa",
|
||||||
|
"redox_termios",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.9"
|
version = "0.2.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||||
dependencies = [
|
|
||||||
"winapi-i686-pc-windows-gnu",
|
|
||||||
"winapi-x86_64-pc-windows-gnu",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-i686-pc-windows-gnu"
|
name = "winapi-build"
|
||||||
version = "0.4.0"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-util"
|
name = "winapi-util"
|
||||||
version = "0.1.6"
|
version = "0.1.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
|
checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets",
|
"windows-targets 0.48.5",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.52.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -190,13 +257,29 @@ version = "0.48.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows_aarch64_gnullvm",
|
"windows_aarch64_gnullvm 0.48.5",
|
||||||
"windows_aarch64_msvc",
|
"windows_aarch64_msvc 0.48.5",
|
||||||
"windows_i686_gnu",
|
"windows_i686_gnu 0.48.5",
|
||||||
"windows_i686_msvc",
|
"windows_i686_msvc 0.48.5",
|
||||||
"windows_x86_64_gnu",
|
"windows_x86_64_gnu 0.48.5",
|
||||||
"windows_x86_64_gnullvm",
|
"windows_x86_64_gnullvm 0.48.5",
|
||||||
"windows_x86_64_msvc",
|
"windows_x86_64_msvc 0.48.5",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm 0.52.5",
|
||||||
|
"windows_aarch64_msvc 0.52.5",
|
||||||
|
"windows_i686_gnu 0.52.5",
|
||||||
|
"windows_i686_gnullvm",
|
||||||
|
"windows_i686_msvc 0.52.5",
|
||||||
|
"windows_x86_64_gnu 0.52.5",
|
||||||
|
"windows_x86_64_gnullvm 0.52.5",
|
||||||
|
"windows_x86_64_msvc 0.52.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -205,38 +288,86 @@ version = "0.48.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnullvm"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.52.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||||
|
|
13
Cargo.toml
13
Cargo.toml
|
@ -1,13 +1,14 @@
|
||||||
[package]
|
[package]
|
||||||
name = "riscv_interpreter"
|
name = "rizz-v"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.79"
|
anyhow = "1.0.82"
|
||||||
bitfield = "0.14.0"
|
bitfield = "0.15.0"
|
||||||
codespan-reporting = "0.11.1"
|
codespan-reporting = "0.11.1"
|
||||||
colored = "2.1.0"
|
colored = "2.1.0"
|
||||||
itertools = "0.12.0"
|
itertools = "0.12.1"
|
||||||
rayon = "1.8.1"
|
rayon = "1.10.0"
|
||||||
term_size = "0.3.2"
|
term_size = "1.0.0-beta1"
|
||||||
|
termion = "3.0.0"
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use colored::Colorize;
|
|
||||||
|
|
||||||
fn add_color(input: String) -> String {
|
|
||||||
let map = [
|
|
||||||
("number", "magenta"),
|
|
||||||
("green", "blue"),
|
|
||||||
].iter().cloned().collect::<HashMap<&str, &str>>();
|
|
||||||
|
|
||||||
let mut colored = String::new();
|
|
||||||
|
|
||||||
for word in input.split(' ') {
|
|
||||||
if let Some(num) = word.parse::<i32>().ok() {
|
|
||||||
colored.push_str(&format!("{:032b}", num));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
colored
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_color(input: &str, color: &str) -> String {
|
|
||||||
match color {
|
|
||||||
"magenta" => input.magenta().to_string(),
|
|
||||||
"blue" => input.blue().to_string(),
|
|
||||||
_ => input.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
223
src/env.rs
223
src/env.rs
|
@ -18,7 +18,8 @@ pub enum Variables {
|
||||||
pub struct Env {
|
pub struct Env {
|
||||||
register_alias: HashMap<String, usize>,
|
register_alias: HashMap<String, usize>,
|
||||||
labels: HashMap<String, u32>,
|
labels: HashMap<String, u32>,
|
||||||
registers: [u32; 32],
|
pub registers: [u32; 32],
|
||||||
|
pub fregisters: [f32; 32],
|
||||||
pub prev_stacks: Vec<Vec<u32>>,
|
pub prev_stacks: Vec<Vec<u32>>,
|
||||||
pub stack: Vec<u32>, // TODO: Find the actual size of the stack
|
pub stack: Vec<u32>, // TODO: Find the actual size of the stack
|
||||||
pub instructions: Vec<u32>,
|
pub instructions: Vec<u32>,
|
||||||
|
@ -29,6 +30,7 @@ impl Env {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
// alias -> xN
|
// alias -> xN
|
||||||
let register_alias = [
|
let register_alias = [
|
||||||
|
// Integer regs
|
||||||
("zero", 0),
|
("zero", 0),
|
||||||
("ra", 1),
|
("ra", 1),
|
||||||
("sp", 2),
|
("sp", 2),
|
||||||
|
@ -62,6 +64,39 @@ impl Env {
|
||||||
("t4", 29),
|
("t4", 29),
|
||||||
("t5", 30),
|
("t5", 30),
|
||||||
("t6", 31),
|
("t6", 31),
|
||||||
|
// Floating point regs
|
||||||
|
("ft0", 0),
|
||||||
|
("ft1", 1),
|
||||||
|
("ft2", 2),
|
||||||
|
("ft3", 3),
|
||||||
|
("ft4", 4),
|
||||||
|
("ft5", 5),
|
||||||
|
("ft6", 6),
|
||||||
|
("ft7", 7),
|
||||||
|
("fs0", 8),
|
||||||
|
("fs1", 9),
|
||||||
|
("fa0", 10),
|
||||||
|
("fa1", 11),
|
||||||
|
("fa2", 12),
|
||||||
|
("fa3", 13),
|
||||||
|
("fa4", 14),
|
||||||
|
("fa5", 15),
|
||||||
|
("fa6", 16),
|
||||||
|
("fa7", 17),
|
||||||
|
("fs2", 18),
|
||||||
|
("fs3", 19),
|
||||||
|
("fs4", 20),
|
||||||
|
("fs5", 21),
|
||||||
|
("fs6", 22),
|
||||||
|
("fs7", 23),
|
||||||
|
("fs8", 24),
|
||||||
|
("fs9", 25),
|
||||||
|
("fs10", 26),
|
||||||
|
("fs11", 27),
|
||||||
|
("ft8", 28),
|
||||||
|
("ft9", 29),
|
||||||
|
("ft10", 30),
|
||||||
|
("ft11", 31),
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(k, v)| (k.to_string(), v.to_owned()))
|
.map(|(k, v)| (k.to_string(), v.to_owned()))
|
||||||
|
@ -71,6 +106,7 @@ impl Env {
|
||||||
register_alias,
|
register_alias,
|
||||||
labels: HashMap::new(),
|
labels: HashMap::new(),
|
||||||
registers: [0; 32],
|
registers: [0; 32],
|
||||||
|
fregisters: [0.0; 32],
|
||||||
prev_stacks: Vec::new(),
|
prev_stacks: Vec::new(),
|
||||||
stack: Vec::from([0; 1024]), // 1024 * 64 = 64 KiB stack
|
stack: Vec::from([0; 1024]), // 1024 * 64 = 64 KiB stack
|
||||||
instructions: Vec::new(),
|
instructions: Vec::new(),
|
||||||
|
@ -99,6 +135,22 @@ impl Env {
|
||||||
self.register_alias.get(reg).copied()
|
self.register_alias.get(reg).copied()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn set_fregister(&mut self, reg: usize, value: f32) {
|
||||||
|
self.fregisters[reg] = value;
|
||||||
|
}
|
||||||
|
pub fn get_fregister(&self, reg: usize) -> f32 {
|
||||||
|
self.fregisters[reg]
|
||||||
|
}
|
||||||
|
pub fn str_to_fregister(&self, reg: &str) -> Option<usize> {
|
||||||
|
if reg.starts_with("f") && !reg[1..].starts_with("0") {
|
||||||
|
match reg[1..].parse::<usize>() {
|
||||||
|
Ok(n) if n < 32 => Some(n),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.register_alias.get(reg).copied()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_label(&mut self, label: &str, value: u32) {
|
pub fn add_label(&mut self, label: &str, value: u32) {
|
||||||
self.labels.insert(label.to_string(), value);
|
self.labels.insert(label.to_string(), value);
|
||||||
|
@ -108,7 +160,7 @@ impl Env {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assemble_op(
|
pub fn assemble_op(
|
||||||
&self,
|
&mut self,
|
||||||
op: (Token, Loc),
|
op: (Token, Loc),
|
||||||
) -> Result<Vec<u32>, (RuntimeErr, Loc, Option<String>)> {
|
) -> Result<Vec<u32>, (RuntimeErr, Loc, Option<String>)> {
|
||||||
if let (Token::Op(name, args), loc) = op {
|
if let (Token::Op(name, args), loc) = op {
|
||||||
|
@ -131,98 +183,107 @@ impl Env {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ =
|
let _ = i
|
||||||
i.1.clone()
|
.1
|
||||||
.into_iter()
|
.clone()
|
||||||
.enumerate()
|
.into_iter()
|
||||||
.try_for_each(|(k, v)| match v {
|
.enumerate()
|
||||||
Arg::Immediate => {
|
.try_for_each(|(k, v)| match v {
|
||||||
if let Token::Immediate(i) = args[k].0 {
|
Arg::Immediate => match args[k].0.clone() {
|
||||||
imm = i as u32;
|
Token::Immediate(i) => {
|
||||||
|
imm = i as u32;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Token::Symbol(s) => {
|
||||||
|
if let Some(v) = self.get_label(&s) {
|
||||||
|
imm = v - loc.mem_offset as u32;
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err((
|
Err((
|
||||||
RuntimeErr::InvalidType(
|
RuntimeErr::LabelNotFound,
|
||||||
Arg::from(args[k].0.clone()).kind(),
|
|
||||||
v.kind(),
|
|
||||||
),
|
|
||||||
args[k].1,
|
args[k].1,
|
||||||
None,
|
None,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Arg::Register(id) => {
|
_ => Err((
|
||||||
if let Token::Register(r) = &args[k].0 {
|
RuntimeErr::InvalidType(Arg::from(args[k].0.clone()).kind(), v.kind()),
|
||||||
regs[id] = self.str_to_register(&r).unwrap();
|
args[k].1,
|
||||||
|
None,
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
Arg::Register(id) => {
|
||||||
|
if let Token::Register(r) = &args[k].0 {
|
||||||
|
regs[id] = self.str_to_register(&r).unwrap();
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err((
|
||||||
|
RuntimeErr::InvalidType(
|
||||||
|
Arg::from(args[k].0.clone()).kind(),
|
||||||
|
v.kind(),
|
||||||
|
),
|
||||||
|
args[k].1,
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Arg::Memory => {
|
||||||
|
if let Token::Memory(i, r) = &args[k].0 {
|
||||||
|
if r.is_some() {
|
||||||
|
regs[k] = self
|
||||||
|
.str_to_register(&if let Token::Register(r) =
|
||||||
|
*(r.clone().unwrap())
|
||||||
|
{
|
||||||
|
r
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
imm = if let Token::Immediate(i) = **i {
|
||||||
|
i as u32
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err((
|
||||||
|
RuntimeErr::InvalidType(
|
||||||
|
Arg::from(args[k].0.clone()).kind(),
|
||||||
|
v.kind(),
|
||||||
|
),
|
||||||
|
args[k].1,
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Arg::Symbol => {
|
||||||
|
if let Token::Symbol(s) = &args[k].0 {
|
||||||
|
if let Some(v) = self.get_label(&s) {
|
||||||
|
imm = (v).wrapping_sub(loc.mem_offset as u32);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err((
|
Err((
|
||||||
RuntimeErr::InvalidType(
|
RuntimeErr::LabelNotFound,
|
||||||
Arg::from(args[k].0.clone()).kind(),
|
|
||||||
v.kind(),
|
|
||||||
),
|
|
||||||
args[k].1,
|
args[k].1,
|
||||||
None,
|
None,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
} else if let Token::Immediate(i) = &args[k].0 {
|
||||||
|
imm = *i as u32;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err((
|
||||||
|
RuntimeErr::InvalidType(
|
||||||
|
Arg::from(args[k].0.clone()).kind(),
|
||||||
|
v.kind(),
|
||||||
|
),
|
||||||
|
args[k].1,
|
||||||
|
None,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
Arg::Memory => {
|
}
|
||||||
if let Token::Memory(i, r) = &args[k].0 {
|
})?;
|
||||||
if r.is_some() {
|
|
||||||
regs[k] = self
|
|
||||||
.str_to_register(&if let Token::Register(r) =
|
|
||||||
*(r.clone().unwrap())
|
|
||||||
{
|
|
||||||
r
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
imm = if let Token::Immediate(i) = **i {
|
|
||||||
i as u32
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err((
|
|
||||||
RuntimeErr::InvalidType(
|
|
||||||
Arg::from(args[k].0.clone()).kind(),
|
|
||||||
v.kind(),
|
|
||||||
),
|
|
||||||
args[k].1,
|
|
||||||
None,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Arg::Symbol => {
|
|
||||||
if let Token::Symbol(s) = &args[k].0 {
|
|
||||||
if let Some(v) = self.get_label(&s) {
|
|
||||||
imm = (v).wrapping_sub(loc.mem_offset as u32);
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err((
|
|
||||||
RuntimeErr::InvalidType(
|
|
||||||
Arg::from(args[k].0.clone()).kind(),
|
|
||||||
v.kind(),
|
|
||||||
),
|
|
||||||
args[k].1,
|
|
||||||
None,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err((
|
|
||||||
RuntimeErr::InvalidType(
|
|
||||||
Arg::from(args[k].0.clone()).kind(),
|
|
||||||
v.kind(),
|
|
||||||
),
|
|
||||||
args[k].1,
|
|
||||||
None,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
Ok({
|
Ok({
|
||||||
if let Kind::Pseudo(_) = i.0 {
|
if let Kind::Pseudo(_) = i.0 {
|
||||||
handle_pseudo(i, imm, regs)
|
handle_pseudo(i, imm, regs)
|
||||||
|
@ -250,7 +311,7 @@ impl Env {
|
||||||
Token::Op(name, _) => {
|
Token::Op(name, _) => {
|
||||||
if let Some((kind, args)) = instruction(&name) {
|
if let Some((kind, args)) = instruction(&name) {
|
||||||
if let Kind::Pseudo(_) = kind {
|
if let Kind::Pseudo(_) = kind {
|
||||||
tokens[id].1.mem_offset = i + 4;
|
tokens[id].1.mem_offset = i;
|
||||||
handle_pseudo((kind, args), 0, vec![0; 4])
|
handle_pseudo((kind, args), 0, vec![0; 4])
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|_| i += 4);
|
.for_each(|_| i += 4);
|
||||||
|
@ -260,7 +321,7 @@ impl Env {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Token::Label(name) => {
|
Token::Label(name) => {
|
||||||
self.add_label(&name, (i + 4) as u32);
|
self.add_label(&name, i as u32);
|
||||||
}
|
}
|
||||||
other => {
|
other => {
|
||||||
dbg!(other);
|
dbg!(other);
|
||||||
|
@ -276,7 +337,7 @@ impl Env {
|
||||||
&mut self,
|
&mut self,
|
||||||
(op, loc): (Token, Loc),
|
(op, loc): (Token, Loc),
|
||||||
) -> Result<(), (RuntimeErr, Loc, Option<String>)> {
|
) -> Result<(), (RuntimeErr, Loc, Option<String>)> {
|
||||||
let (i, args) = if let Token::Op(name, args) = op {
|
let (_i, _args) = if let Token::Op(name, args) = op {
|
||||||
if let Some(i) = instruction(&name) {
|
if let Some(i) = instruction(&name) {
|
||||||
(i, args.clone())
|
(i, args.clone())
|
||||||
} else {
|
} else {
|
||||||
|
|
60
src/err.rs
60
src/err.rs
|
@ -9,20 +9,30 @@ use crate::instructions::instruction;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum SyntaxErr {
|
pub enum SyntaxErr {
|
||||||
|
UnexpectedChar,
|
||||||
|
|
||||||
|
//.text specific
|
||||||
/// false for '(' true for ')'
|
/// false for '(' true for ')'
|
||||||
UnmatchedParen(bool),
|
UnmatchedParen(bool),
|
||||||
UnexpectedChar,
|
OutsideMnemonic(String),
|
||||||
OutsideOp(String),
|
|
||||||
InvalidRegister,
|
InvalidRegister,
|
||||||
|
|
||||||
|
// .data specific
|
||||||
|
InvalidType,
|
||||||
|
InvalidVarName,
|
||||||
|
MalformedData,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for SyntaxErr {
|
impl Display for SyntaxErr {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
SyntaxErr::UnmatchedParen(_) => write!(f, "unmatched parenthesis"),
|
|
||||||
SyntaxErr::UnexpectedChar => write!(f, "unexpected character"),
|
SyntaxErr::UnexpectedChar => write!(f, "unexpected character"),
|
||||||
SyntaxErr::OutsideOp(kind) => write!(f, "`{kind}` before opcode"),
|
SyntaxErr::UnmatchedParen(_) => write!(f, "unmatched parenthesis"),
|
||||||
|
SyntaxErr::OutsideMnemonic(kind) => write!(f, "unexpected '{kind}'"),
|
||||||
SyntaxErr::InvalidRegister => write!(f, "invalid register"),
|
SyntaxErr::InvalidRegister => write!(f, "invalid register"),
|
||||||
|
SyntaxErr::InvalidType => write!(f, "invalid type"),
|
||||||
|
SyntaxErr::InvalidVarName => write!(f, "invalid variable name"),
|
||||||
|
SyntaxErr::MalformedData => write!(f, "malformed global definition"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,37 +40,42 @@ impl Display for SyntaxErr {
|
||||||
impl SyntaxErr {
|
impl SyntaxErr {
|
||||||
pub fn note(&self) -> String {
|
pub fn note(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
SyntaxErr::UnmatchedParen(false) => "add `)` after the register name".to_string(),
|
|
||||||
SyntaxErr::UnmatchedParen(true) => "add `(` before the register name".to_string(),
|
|
||||||
SyntaxErr::UnexpectedChar => "ensure the input is well-formed".to_string(),
|
SyntaxErr::UnexpectedChar => "ensure the input is well-formed".to_string(),
|
||||||
SyntaxErr::OutsideOp(_) => format!("only add arguments after the opcode"),
|
SyntaxErr::UnmatchedParen(false) => "add `)` after the register".to_string(),
|
||||||
|
SyntaxErr::UnmatchedParen(true) => "add `(` before the register".to_string(),
|
||||||
|
SyntaxErr::OutsideMnemonic(_) => format!("only add arguments after the mnemonic"),
|
||||||
SyntaxErr::InvalidRegister => {
|
SyntaxErr::InvalidRegister => {
|
||||||
"registers are either xN (N < 32 with no leading 0) or the standard aliases"
|
"registers are either (x|f)N, for N < 32 with no leading 0, or an alias".to_string()
|
||||||
.to_string()
|
|
||||||
}
|
}
|
||||||
|
SyntaxErr::InvalidType => "check the spec for proper types".to_string(),
|
||||||
|
SyntaxErr::InvalidVarName => "variable names must be alphanumeric".to_string(),
|
||||||
|
SyntaxErr::MalformedData => "ensure the global definition is well-formed".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum RuntimeErr {
|
pub enum RuntimeErr {
|
||||||
InvalidOp,
|
/// TODO: only worth using this after all the instructions are implemented!
|
||||||
|
InvalidMnemonic,
|
||||||
/// op, actual, expected
|
/// op, actual, expected
|
||||||
InvalidOpArity(String, usize, usize),
|
InvalidOpArity(String, usize, usize),
|
||||||
/// actual, expected
|
/// actual, expected
|
||||||
InvalidType(String, String),
|
TypeMissmatch(String, String),
|
||||||
|
LabelNotFound,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for RuntimeErr {
|
impl Display for RuntimeErr {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
RuntimeErr::InvalidOp => write!(f, "invalid opcode"),
|
RuntimeErr::InvalidMnemonic => write!(f, "invalid mnemonic"),
|
||||||
RuntimeErr::InvalidOpArity(op, actual, expected) => {
|
RuntimeErr::InvalidOpArity(_, actual, expected) => {
|
||||||
write!(f, "`{}` expected {} args, got {}", op, expected, actual)
|
write!(f, "expected {} args, got {}", expected, actual)
|
||||||
}
|
}
|
||||||
RuntimeErr::InvalidType(actual, expected) => {
|
RuntimeErr::TypeMissmatch(actual, expected) => {
|
||||||
write!(f, "expected `{}`, got `{}`", expected, actual)
|
write!(f, "expected '{}', got '{}'", expected, actual)
|
||||||
}
|
}
|
||||||
|
RuntimeErr::LabelNotFound => write!(f, "label not found"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,7 +83,9 @@ impl Display for RuntimeErr {
|
||||||
impl RuntimeErr {
|
impl RuntimeErr {
|
||||||
pub fn note(&self) -> String {
|
pub fn note(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
RuntimeErr::InvalidOp => "check the ref sheet for the avaliable opcodes".to_string(),
|
RuntimeErr::InvalidMnemonic => {
|
||||||
|
"check the ref sheet for the avaliable mnemonics".to_string()
|
||||||
|
}
|
||||||
RuntimeErr::InvalidOpArity(op, actual, expected) => {
|
RuntimeErr::InvalidOpArity(op, actual, expected) => {
|
||||||
let args = instruction(op).unwrap().1;
|
let args = instruction(op).unwrap().1;
|
||||||
match actual.cmp(expected) {
|
match actual.cmp(expected) {
|
||||||
|
@ -78,7 +95,7 @@ impl RuntimeErr {
|
||||||
}
|
}
|
||||||
Ordering::Greater => "remove the extra arguments".to_string(),
|
Ordering::Greater => "remove the extra arguments".to_string(),
|
||||||
Ordering::Less if expected - actual == 1 => {
|
Ordering::Less if expected - actual == 1 => {
|
||||||
format!("add the extra `{}` argument", args.last().unwrap().kind())
|
format!("add the extra '{}' argument", args.last().unwrap().kind())
|
||||||
}
|
}
|
||||||
Ordering::Less => format!(
|
Ordering::Less => format!(
|
||||||
"add the extra `{}` arguments",
|
"add the extra `{}` arguments",
|
||||||
|
@ -86,11 +103,14 @@ impl RuntimeErr {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|arg| arg.kind())
|
.map(|arg| arg.kind())
|
||||||
.join("`, `")
|
.join("', '")
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RuntimeErr::InvalidType(_, _) => "ensure the operation is valid".to_string(),
|
RuntimeErr::TypeMissmatch(_, _) => {
|
||||||
|
"ensure the instruction is getting the right arguments".to_string()
|
||||||
|
}
|
||||||
|
RuntimeErr::LabelNotFound => "ensure the label is spelled correctly".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
170
src/execution.rs
170
src/execution.rs
|
@ -1,46 +1,182 @@
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
use crate::{env::Env, instructions::kind::Kind};
|
use crate::{env::Env, instructions::kind::Kind};
|
||||||
|
|
||||||
|
/// Always "safe" because f32 and i32 have the same size.
|
||||||
|
fn u32_to_f32(i: u32) -> f32 {
|
||||||
|
unsafe { mem::transmute(i) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Always "safe" because f32 and i32 have the same size.
|
||||||
|
fn _f32_to_u32(f: f32) -> u32 {
|
||||||
|
unsafe { mem::transmute(f) }
|
||||||
|
}
|
||||||
|
|
||||||
/// lui rd, imm
|
/// lui rd, imm
|
||||||
fn lui(env: &mut Env, rd: usize, imm: u32) {
|
fn lui(env: &mut Env, rd: usize, imm: u32) {
|
||||||
env.set_register(rd, imm);
|
env.set_register(rd, imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// add rd, ra, rb
|
||||||
|
fn add(env: &mut Env, rd: usize, ra: usize, rb: usize) {
|
||||||
|
env.set_register(rd, env.get_register(ra).wrapping_add(env.get_register(rb)));
|
||||||
|
}
|
||||||
|
|
||||||
/// addi rd, ra, imm
|
/// addi rd, ra, imm
|
||||||
fn addi(env: &mut Env, rd: usize, ra: usize, imm: u32) {
|
fn addi(env: &mut Env, rd: usize, ra: usize, imm: u32) {
|
||||||
env.set_register(rd, env.get_register(ra) + imm);
|
env.set_register(rd, env.get_register(ra).wrapping_add(imm));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// xor rd, ra, rb
|
||||||
|
fn xor(env: &mut Env, rd: usize, ra: usize, rb: usize) {
|
||||||
|
env.set_register(rd, env.get_register(ra) ^ env.get_register(rb));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// mul rd, ra, rb
|
||||||
|
fn mul(env: &mut Env, rd: usize, ra: usize, rb: usize) {
|
||||||
|
env.set_register(rd, env.get_register(ra).wrapping_mul(env.get_register(rb)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// mulh rd, ra, rb (SxS)
|
||||||
|
fn mulh(env: &mut Env, rd: usize, ra: usize, rb: usize) {
|
||||||
|
env.set_register(
|
||||||
|
rd,
|
||||||
|
(env.get_register(ra) as i64 * env.get_register(rb) as i64 >> 32) as u32,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// mulhsu rd, ra, rb (SxU)
|
||||||
|
fn mulhsu(env: &mut Env, rd: usize, ra: usize, rb: usize) {
|
||||||
|
env.set_register(
|
||||||
|
rd,
|
||||||
|
(env.get_register(ra) as i64 * env.get_register(rb) as i64 >> 32) as u32,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// mulhu rd, ra, rb (UxU)
|
||||||
|
fn mulu(env: &mut Env, rd: usize, ra: usize, rb: usize) {
|
||||||
|
env.set_register(
|
||||||
|
rd,
|
||||||
|
(env.get_register(ra) as u64 * env.get_register(rb) as u64 >> 32) as u32,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// beq ra, rb, imm
|
||||||
|
fn beq(env: &mut Env, ra: usize, rb: usize, imm: u32) -> bool {
|
||||||
|
if env.get_register(ra) == env.get_register(rb) {
|
||||||
|
env.pc = env.pc.wrapping_add(imm);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// jal rd, imm
|
/// jal rd, imm
|
||||||
fn jal(env: &mut Env, rd: usize, imm: u32) {
|
fn jal(env: &mut Env, rd: usize, imm: u32) {
|
||||||
env.set_register(rd, env.pc);
|
env.set_register(rd, env.pc + 4);
|
||||||
env.pc += imm;
|
env.pc = env.pc.wrapping_add(imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn to_u32<const N: usize>(bits: &[bool; N]) -> u32 {
|
/// fadd.s fd, fa, fb
|
||||||
let mut val = 0;
|
fn fadd_s(env: &mut Env, fd: usize, fa: usize, fb: usize) {
|
||||||
for i in 0..N {
|
env.set_fregister(fd, env.get_fregister(fa) + env.get_fregister(fb));
|
||||||
if bits[i] {
|
|
||||||
val |= 1 << i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_instruction(env: &mut Env, kind: Kind) {
|
/// fdiv.s fd, fa, fb
|
||||||
|
fn fdiv_s(env: &mut Env, fd: usize, fa: usize, fb: usize) {
|
||||||
|
env.set_fregister(fd, env.get_fregister(fa) / env.get_fregister(fb));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// fmadd.s fd, fa, fb, fc
|
||||||
|
fn fmadd_s(env: &mut Env, fd: usize, fa: usize, fb: usize, fc: usize) {
|
||||||
|
env.set_fregister(
|
||||||
|
fd,
|
||||||
|
env.get_fregister(fa) * env.get_fregister(fb) + env.get_fregister(fc),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// fcvt.s.w fd, ra
|
||||||
|
fn fcvt_s_w(env: &mut Env, fd: usize, ra: usize) {
|
||||||
|
env.set_fregister(fd, env.get_register(ra) as i32 as f32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// fmv.w.x fd, ra
|
||||||
|
fn fmv_w_x(env: &mut Env, fd: usize, ra: usize) {
|
||||||
|
env.set_fregister(fd, u32_to_f32(env.get_register(ra)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Executes the instruction.
|
||||||
|
///
|
||||||
|
/// Returns true if the instruction is a jump.
|
||||||
|
pub fn run_instruction(env: &mut Env, instruction: u32) -> bool {
|
||||||
|
let (kind, _) = Kind::to_op(instruction);
|
||||||
let mut regs = kind.get_regs().unwrap();
|
let mut regs = kind.get_regs().unwrap();
|
||||||
// Ensure all four registers have a value
|
// Ensure all four registers have a value
|
||||||
regs.extend([0].repeat(4 - regs.len()));
|
regs.extend([0].repeat(4 - regs.len()));
|
||||||
let (rd, ra, rb, _rc) = (regs[0], regs[1], regs[2], regs[3]);
|
let (rd, ra, rb) = (regs[0], regs[1], regs[2]);
|
||||||
let imm = kind.get_imm().unwrap();
|
let (fd, fa, fb, fc) = (regs[0], regs[1], regs[2], regs[3]);
|
||||||
|
let imm = kind.get_imm();
|
||||||
let opcode = kind.get_opcode().unwrap();
|
let opcode = kind.get_opcode().unwrap();
|
||||||
|
let funct3 = instruction >> 12 & 0b111;
|
||||||
|
let funct7 = instruction >> 25 & 0b1111111;
|
||||||
|
|
||||||
match opcode {
|
match opcode {
|
||||||
0b0110111 => {
|
0b0110111 => {
|
||||||
lui(env, rd, imm)
|
lui(env, rd, imm.unwrap());
|
||||||
|
false
|
||||||
|
}
|
||||||
|
0b0110011 if funct3 == 0b000 && funct7 == 0b0000000 => {
|
||||||
|
add(env, rd, ra, rb);
|
||||||
|
false
|
||||||
}
|
}
|
||||||
0b0010011 => {
|
0b0010011 => {
|
||||||
addi(env, rd, ra, imm)
|
addi(env, rd, ra, imm.unwrap());
|
||||||
|
false
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
0b0110011 if funct3 == 0b100 && funct7 == 0b0000000 => {
|
||||||
|
xor(env, rd, ra, rb);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
0b0110011 if funct3 == 0b000 && funct7 == 0b0000001 => {
|
||||||
|
mul(env, rd, ra, rb);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
0b0110011 if funct3 == 0b001 && funct7 == 0b0000001 => {
|
||||||
|
mulh(env, rd, ra, rb);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
0b0110011 if funct3 == 0b010 && funct7 == 0b0000001 => {
|
||||||
|
mulhsu(env, rd, ra, rb);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
0b0110011 if funct3 == 0b011 && funct7 == 0b0000001 => {
|
||||||
|
mulu(env, rd, ra, rb);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
0b1100011 => beq(env, ra, rb, imm.unwrap()),
|
||||||
|
0b1101111 => {
|
||||||
|
jal(env, rd, imm.unwrap());
|
||||||
|
true
|
||||||
|
}
|
||||||
|
0b1010011 if funct7 == 0x00 => {
|
||||||
|
fadd_s(env, fd, fa, fb);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
0b1010011 if funct7 == 0x0c => {
|
||||||
|
fdiv_s(env, fd, fa, fb);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
0b1000011 if fb == 0 => {
|
||||||
|
fmadd_s(env, fd, fa, fb, fc);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
0b1010011 if funct7 == 0x68 => {
|
||||||
|
fcvt_s_w(env, fd, ra);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
0b1010011 if funct7 == 0x78 => {
|
||||||
|
fmv_w_x(env, fd, ra);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
_ => todo!("op: {:032b}", instruction),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
158
src/info.rs
158
src/info.rs
|
@ -2,29 +2,161 @@ use colored::Colorize;
|
||||||
|
|
||||||
use crate::env::Env;
|
use crate::env::Env;
|
||||||
|
|
||||||
pub fn info(env: &Env, op: &str, args: Vec<String>) -> Vec<String> {
|
/// Display a helpful message about an instruction.
|
||||||
match op {
|
///
|
||||||
"nop" => vec!["Do nothing - wait 1 cycle".to_string()],
|
/// Returns the message and, if needed, tags to highlight specific registers ([x regs...], [fregs...]).
|
||||||
"li" => vec![format!("load {} into the register {}", args[1], args[0])],
|
pub fn info(
|
||||||
|
env: &Env,
|
||||||
|
op: &str,
|
||||||
|
args: Vec<String>,
|
||||||
|
display_mode: char,
|
||||||
|
) -> (String, (Vec<usize>, Vec<usize>)) {
|
||||||
|
let args: Vec<_> = args
|
||||||
|
.into_iter()
|
||||||
|
.map(|a| {
|
||||||
|
if let Ok(num) = a.parse::<u32>() {
|
||||||
|
match display_mode {
|
||||||
|
'd' => num.to_string(),
|
||||||
|
's' => (num as i32).to_string(),
|
||||||
|
'b' => format!("{:032b}", num),
|
||||||
|
'h' => format!("{:08x}", num),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
a
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut tag = (vec![], vec![]);
|
||||||
|
let msg = match op {
|
||||||
|
"nop" => vec!["do nothing".to_string()],
|
||||||
|
"li" => vec![format!(
|
||||||
|
"load {} into {}",
|
||||||
|
args[1].italic().yellow(),
|
||||||
|
args[0].red()
|
||||||
|
)],
|
||||||
"lui" => {
|
"lui" => {
|
||||||
let imm = format!("{:032b}", args[1].parse::<i32>().unwrap() as u32)
|
let imm = format!("{:032b}", args[1].parse::<i32>().unwrap() as u32)
|
||||||
.chars()
|
.chars()
|
||||||
.rev()
|
.rev()
|
||||||
.collect::<String>();
|
.collect::<String>();
|
||||||
vec![
|
vec![
|
||||||
format!(
|
format!("load the upper 20 bits of {} into {}", args[1], args[0]),
|
||||||
"load the upper 20 bits of {} into {}",
|
|
||||||
args[1], args[0]
|
|
||||||
),
|
|
||||||
format!(
|
format!(
|
||||||
"{} = {}{}",
|
"{} = {}{}",
|
||||||
args[1],
|
args[1].italic().yellow(),
|
||||||
imm[12..32].to_string().red(),
|
imm[12..32].to_string().green(),
|
||||||
imm[0..12].to_string()
|
imm[0..12].to_string().strikethrough().black()
|
||||||
|
),
|
||||||
|
format!(
|
||||||
|
"{:>1$} ← {2} << 12",
|
||||||
|
args[0].blue(),
|
||||||
|
args[1].to_string().len(),
|
||||||
|
imm[12..32].to_string(),
|
||||||
),
|
),
|
||||||
format!("{:>1$} <- {2}{3:0>12}", args[0], args[1].to_string().len() - 1, imm[12..32].to_string(), "0".to_string().bold()),
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
"add" => {
|
||||||
|
tag = (
|
||||||
|
vec![
|
||||||
|
env.str_to_register(&args[1]).unwrap(),
|
||||||
|
env.str_to_register(&args[2]).unwrap(),
|
||||||
|
],
|
||||||
|
vec![],
|
||||||
|
);
|
||||||
|
vec![format!(
|
||||||
|
"add the values of {0} and {1} and store the result in {2}\n{2} ← {0} + {1}",
|
||||||
|
args[1].blue(),
|
||||||
|
args[2].blue(),
|
||||||
|
args[0].blue()
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
"addi" => {
|
||||||
|
tag = (
|
||||||
|
vec![
|
||||||
|
env.str_to_register(&args[1]).unwrap(),
|
||||||
|
env.str_to_register(&args[2]).unwrap(),
|
||||||
|
],
|
||||||
|
vec![],
|
||||||
|
);
|
||||||
|
vec![format!(
|
||||||
|
"add the values of {0} and {1} and store the result in {2}\n{2} ← {0} + {1}",
|
||||||
|
args[2].blue(),
|
||||||
|
args[1].italic().yellow(),
|
||||||
|
args[0].blue()
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
"sub" => vec![format!(
|
||||||
|
"subtract the value of {} from the value of {} and store the result in {}",
|
||||||
|
args[1].blue(),
|
||||||
|
args[2].blue(),
|
||||||
|
args[0].blue()
|
||||||
|
)],
|
||||||
|
"mul" => {
|
||||||
|
tag = (
|
||||||
|
vec![],
|
||||||
|
vec![
|
||||||
|
env.str_to_fregister(&args[1]).unwrap(),
|
||||||
|
env.str_to_fregister(&args[2]).unwrap(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
vec![format!(
|
||||||
|
"multiply the values of {0} and {1} and store the result in {2}\n{2} ← {0} ✕ {1}",
|
||||||
|
args[1].blue(),
|
||||||
|
args[2].blue(),
|
||||||
|
args[0].blue()
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
"fadd.s" => {
|
||||||
|
tag = (
|
||||||
|
vec![],
|
||||||
|
vec![
|
||||||
|
env.str_to_fregister(&args[1]).unwrap(),
|
||||||
|
env.str_to_fregister(&args[2]).unwrap(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
vec![format!(
|
||||||
|
"add the values of {0} and {1} and store the result in {2}\n{2} ← {0} + {1}",
|
||||||
|
args[1].blue(),
|
||||||
|
args[2].blue(),
|
||||||
|
args[0].blue()
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
"fdiv.s" => {
|
||||||
|
tag = (
|
||||||
|
vec![],
|
||||||
|
vec![
|
||||||
|
env.str_to_fregister(&args[1]).unwrap(),
|
||||||
|
env.str_to_fregister(&args[2]).unwrap(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
vec![format!(
|
||||||
|
"divide the value of {0} by the value of {1} and store the result in {2}\n{2} ← {0} ÷ {1}",
|
||||||
|
args[1].blue(),
|
||||||
|
args[2].blue(),
|
||||||
|
args[0].blue()
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
"fcvt.s.w" => {
|
||||||
|
tag = (vec![env.str_to_register(&args[1]).unwrap()], vec![]);
|
||||||
|
vec![format!(
|
||||||
|
"convert the value of {} to a float and store it in {}",
|
||||||
|
args[1].blue(),
|
||||||
|
args[0].blue()
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
"fmv.w.x" => {
|
||||||
|
tag = (vec![env.str_to_register(&args[1]).unwrap()], vec![]);
|
||||||
|
vec![format!(
|
||||||
|
"interpret the value of {0} as a float and store it in {1}\n{1} ← {0}",
|
||||||
|
args[1].blue(),
|
||||||
|
args[0].blue()
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
op => todo!("{}", op),
|
||||||
}
|
}
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
|
(msg, tag)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,11 @@
|
||||||
pub mod kind {
|
pub mod kind {
|
||||||
use std::{
|
use std::fmt::{self, Display, Formatter};
|
||||||
fmt::{self, Display, Formatter},
|
|
||||||
mem,
|
|
||||||
};
|
|
||||||
|
|
||||||
use bitfield::bitfield;
|
use bitfield::bitfield;
|
||||||
|
|
||||||
use crate::instructions::{instruction, to_u32};
|
/// A pseudo instruction is an instruction that
|
||||||
|
/// will be converted by the engine to real instructions
|
||||||
use super::{to_bits, to_reg};
|
#[derive(Debug)]
|
||||||
|
|
||||||
/// will be converted by the engine to a real instruction
|
|
||||||
pub struct Pseudo(pub &'static str);
|
pub struct Pseudo(pub &'static str);
|
||||||
|
|
||||||
bitfield! {
|
bitfield! {
|
||||||
|
@ -108,6 +103,7 @@ pub mod kind {
|
||||||
pub opcode, set_opcode: 6, 0;
|
pub opcode, set_opcode: 6, 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum Kind {
|
pub enum Kind {
|
||||||
Pseudo(Pseudo),
|
Pseudo(Pseudo),
|
||||||
R(R),
|
R(R),
|
||||||
|
@ -156,21 +152,31 @@ pub mod kind {
|
||||||
Kind::Pseudo(_) => None,
|
Kind::Pseudo(_) => None,
|
||||||
Kind::R(_) => None,
|
Kind::R(_) => None,
|
||||||
Kind::R4(_) => None,
|
Kind::R4(_) => None,
|
||||||
Kind::I(i) => Some(i.imm()),
|
Kind::I(i) => Some(if i.imm() >> 11 == 1 {
|
||||||
Kind::I2(i2) => Some(i2.imm() >> 20),
|
i.imm() | 0xFFFFF000
|
||||||
|
} else {
|
||||||
|
i.imm()
|
||||||
|
}),
|
||||||
|
Kind::I2(i2) => Some(if i2.imm() >> 5 == 1 {
|
||||||
|
i2.imm() | 0xFFFFFFE0
|
||||||
|
} else {
|
||||||
|
i2.imm()
|
||||||
|
}),
|
||||||
Kind::S(s) => Some(s.imm_11_5() | s.imm_4_0()),
|
Kind::S(s) => Some(s.imm_11_5() | s.imm_4_0()),
|
||||||
Kind::B(b) => Some(
|
Kind::B(b) => Some(
|
||||||
((b.imm_12() as u32) << 12)
|
((b.imm_12() as u32) << 12)
|
||||||
| ((b.imm_11() as u32) << 11)
|
| ((b.imm_11() as u32) << 11)
|
||||||
| (b.imm_10_5() << 5)
|
| (b.imm_10_5() << 5)
|
||||||
| (b.imm_4_1() << 1),
|
| (b.imm_4_1() << 1)
|
||||||
|
| if b.imm_12() == true { 0xFFFFE000 } else { 0 },
|
||||||
),
|
),
|
||||||
Kind::U(u) => Some(u.imm31_12() << 12),
|
Kind::U(u) => Some(u.imm31_12() << 12),
|
||||||
Kind::J(j) => Some(
|
Kind::J(j) => Some(
|
||||||
((j.imm_20() as u32) << 20)
|
((j.imm_20() as u32) << 20)
|
||||||
| ((j.imm_19_12() as u32) << 12)
|
| ((j.imm_19_12() as u32) << 12)
|
||||||
| ((j.imm_11() as u32) << 11)
|
| ((j.imm_11() as u32) << 11)
|
||||||
| (j.imm_10_1() << 1),
|
| (j.imm_10_1() << 1)
|
||||||
|
| if j.imm_20() == true { 0xFFE00000 } else { 0 },
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,17 +202,53 @@ pub mod kind {
|
||||||
|
|
||||||
pub fn to_op(instruction: u32) -> (Kind, String) {
|
pub fn to_op(instruction: u32) -> (Kind, String) {
|
||||||
let opcode = instruction & 0b00000000000000000000000001111111;
|
let opcode = instruction & 0b00000000000000000000000001111111;
|
||||||
|
let funct3 = (instruction & 0b00000000000000000111000000000000) >> 12;
|
||||||
|
let funct7 = (instruction & 0b11111110000000000000000000000000) >> 25;
|
||||||
|
|
||||||
match opcode {
|
match opcode {
|
||||||
0b0110111 => (
|
0b0110111 => (Kind::U(U(instruction)), "lui".into()),
|
||||||
Kind::U(unsafe { mem::transmute_copy(&instruction) }),
|
0b0010011 => (Kind::I(I(instruction)), "addi".into()),
|
||||||
"lui".into(),
|
0b0110011 if funct3 == 0b000 && funct7 == 0b0000000 => {
|
||||||
),
|
(Kind::R(R(instruction)), "add".into())
|
||||||
0b0010011 => (
|
}
|
||||||
Kind::I(unsafe { mem::transmute_copy(&instruction) }),
|
0b0110011 if funct3 == 0b000 && funct7 == 0b0100000 => {
|
||||||
"addi".into(),
|
(Kind::R(R(instruction)), "sub".into())
|
||||||
),
|
}
|
||||||
_ => todo!(),
|
0b0110011 if funct3 == 0b000 && funct7 == 0b0000001 => {
|
||||||
|
(Kind::R(R(instruction)), "mul".into())
|
||||||
|
}
|
||||||
|
0b1100011 => (Kind::B(B(instruction)), "beq".into()),
|
||||||
|
0b1101111 => (Kind::J(J(instruction)), "jal".into()),
|
||||||
|
0b1010011 if funct7 == 0x00 => {
|
||||||
|
(Kind::R(R(instruction)), "fadd.s".into())
|
||||||
|
}
|
||||||
|
0b1010011 if funct7 == 0x0c => {
|
||||||
|
(Kind::R(R(instruction)), "fdiv.s".into())
|
||||||
|
}
|
||||||
|
0b1010011 if funct7 == 0x68 => {
|
||||||
|
(Kind::R(R(instruction)), "fcvt.s.w".into())
|
||||||
|
}
|
||||||
|
0b1010011 if funct7 == 0x78 => {
|
||||||
|
(Kind::R(R(instruction)), "fmv.w.x".into())
|
||||||
|
}
|
||||||
|
other => {
|
||||||
|
println!("todo: opcode={:07b}", other);
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_u32(&self) -> u32 {
|
||||||
|
match self {
|
||||||
|
Kind::Pseudo(_) => unreachable!(),
|
||||||
|
Kind::R(r) => r.0,
|
||||||
|
Kind::R4(r4) => r4.0,
|
||||||
|
Kind::I(i) => i.0,
|
||||||
|
Kind::I2(i2) => i2.0,
|
||||||
|
Kind::S(s) => s.0,
|
||||||
|
Kind::B(b) => b.0,
|
||||||
|
Kind::U(u) => u.0,
|
||||||
|
Kind::J(j) => j.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -480,6 +522,52 @@ pub fn instruction(op: &str) -> Option<(Kind, Vec<Arg>)> {
|
||||||
}),
|
}),
|
||||||
vec![Arg::Register(0), Arg::Symbol],
|
vec![Arg::Register(0), Arg::Symbol],
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// F Extension - assune rm is 0b000
|
||||||
|
|
||||||
|
// Arithmetic
|
||||||
|
"fadd.s" => (
|
||||||
|
Kind::R({
|
||||||
|
let mut r = R(0);
|
||||||
|
r.set_funct7(0x00);
|
||||||
|
r.set_funct3(0b000);
|
||||||
|
r.set_opcode(0b1010011);
|
||||||
|
r
|
||||||
|
}),
|
||||||
|
vec![Arg::Register(0), Arg::Register(1), Arg::Register(2)],
|
||||||
|
),
|
||||||
|
"fdiv.s" => (
|
||||||
|
Kind::R({
|
||||||
|
let mut r = R(0);
|
||||||
|
r.set_funct7(0x0c);
|
||||||
|
r.set_funct3(0b000);
|
||||||
|
r.set_opcode(0b1010011);
|
||||||
|
r
|
||||||
|
}),
|
||||||
|
vec![Arg::Register(0), Arg::Register(1), Arg::Register(2)],
|
||||||
|
),
|
||||||
|
|
||||||
|
// Move / Convert
|
||||||
|
"fcvt.s.w" => (
|
||||||
|
Kind::R({
|
||||||
|
let mut r = R(0);
|
||||||
|
r.set_funct7(0x68);
|
||||||
|
r.set_funct3(0b000);
|
||||||
|
r.set_opcode(0b1010011);
|
||||||
|
r
|
||||||
|
}),
|
||||||
|
vec![Arg::Register(0), Arg::Register(1)], // rb is not used
|
||||||
|
),
|
||||||
|
"fmv.w.x" => (
|
||||||
|
Kind::R({
|
||||||
|
let mut r = R(0);
|
||||||
|
r.set_funct7(0x78);
|
||||||
|
r.set_funct3(0b000);
|
||||||
|
r.set_opcode(0b1010011);
|
||||||
|
r
|
||||||
|
}),
|
||||||
|
vec![Arg::Register(0), Arg::Register(1)], // rb is not used
|
||||||
|
),
|
||||||
op => unimplemented!("{}", op),
|
op => unimplemented!("{}", op),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -530,7 +618,7 @@ pub fn with((kind, args): (Kind, Vec<Arg>), imm: u32, regs: Vec<usize>) -> (Kind
|
||||||
b.set_imm_12(to_bits::<1>(imm >> 12)[0]);
|
b.set_imm_12(to_bits::<1>(imm >> 12)[0]);
|
||||||
b.set_imm_11(to_bits::<1>(imm >> 11)[0]);
|
b.set_imm_11(to_bits::<1>(imm >> 11)[0]);
|
||||||
b.set_imm_10_5(imm >> 5);
|
b.set_imm_10_5(imm >> 5);
|
||||||
b.set_imm_4_1(imm);
|
b.set_imm_4_1(imm >> 1);
|
||||||
(Kind::B(b), args)
|
(Kind::B(b), args)
|
||||||
}
|
}
|
||||||
Kind::U(mut u) => {
|
Kind::U(mut u) => {
|
||||||
|
@ -567,28 +655,32 @@ pub fn handle_pseudo(
|
||||||
with(get_instruction("addi"), 0, vec![0, 0]),
|
with(get_instruction("addi"), 0, vec![0, 0]),
|
||||||
],
|
],
|
||||||
"li" => {
|
"li" => {
|
||||||
match imm {
|
// if the immediate only has the lower 12 bits set, use addi
|
||||||
// if the immediate is small enough (12 bits), use addi
|
if imm >> 12 == 0 {
|
||||||
_ if imm >> 12 == 0 => {
|
// addi rd, x0, imm
|
||||||
// addi rd, x0, imm
|
vec![with(get_instruction("addi"), imm, regs)]
|
||||||
vec![with(get_instruction("addi"), imm, regs)]
|
}
|
||||||
}
|
// if the immediate is a multiple of 0x1000, use lui
|
||||||
// if the immediate is a multiple of 0x1000, use lui
|
else if imm & 0xfff == 0 {
|
||||||
_ if imm & 0xfff == 0 => {
|
// lui rd, imm
|
||||||
|
vec![with(get_instruction("lui"), imm, regs)]
|
||||||
|
}
|
||||||
|
// otherwise, use lui and addi
|
||||||
|
else {
|
||||||
|
vec![
|
||||||
// lui rd, imm
|
// lui rd, imm
|
||||||
vec![with(get_instruction("lui"), imm, regs)]
|
with(
|
||||||
}
|
get_instruction("lui"),
|
||||||
// otherwise, use lui and addi
|
(imm & 0xfffff000) ^ ((imm >> 11) & 0x1) << 12,
|
||||||
_ => vec![
|
regs.clone(),
|
||||||
// lui rd, imm
|
),
|
||||||
with(get_instruction("lui"), imm & 0xfffff000, regs.clone()),
|
|
||||||
// addi rd, rd, imm
|
// addi rd, rd, imm
|
||||||
with(
|
with(
|
||||||
get_instruction("addi"),
|
get_instruction("addi"),
|
||||||
imm & 0x00000fff,
|
imm & 0x00000fff,
|
||||||
vec![regs[0], regs[0]],
|
vec![regs[0], regs[0]],
|
||||||
),
|
),
|
||||||
],
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"beqz" => vec![
|
"beqz" => vec![
|
||||||
|
@ -617,21 +709,3 @@ const fn to_bits<const N: usize>(val: u32) -> [bool; N] {
|
||||||
}
|
}
|
||||||
bits
|
bits
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn reg_bits<const N: usize>(reg: usize) -> [bool; N] {
|
|
||||||
to_bits(reg as u32)
|
|
||||||
}
|
|
||||||
|
|
||||||
const fn to_u32<const N: usize>(bits: &[bool; N]) -> u32 {
|
|
||||||
let mut val = 0;
|
|
||||||
for i in 0..N {
|
|
||||||
if bits[i] {
|
|
||||||
val |= 1 << i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val
|
|
||||||
}
|
|
||||||
|
|
||||||
const fn to_reg<const N: usize>(bits: &[bool; N]) -> usize {
|
|
||||||
to_u32(bits) as usize
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
#![feature(const_mut_refs)]
|
#![feature(const_mut_refs)]
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
#![feature(effects)]
|
#![feature(effects)]
|
||||||
|
#![feature(iterator_try_reduce)]
|
||||||
|
#![feature(try_blocks)]
|
||||||
|
|
||||||
pub mod colorizer;
|
// pub mod colorizer;
|
||||||
pub mod env;
|
pub mod env;
|
||||||
pub mod err;
|
pub mod err;
|
||||||
pub mod execution;
|
pub mod execution;
|
||||||
|
|
449
src/main.rs
449
src/main.rs
|
@ -1,3 +1,5 @@
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
use codespan_reporting::{
|
use codespan_reporting::{
|
||||||
diagnostic::{Diagnostic, Label},
|
diagnostic::{Diagnostic, Label},
|
||||||
files::SimpleFile,
|
files::SimpleFile,
|
||||||
|
@ -7,20 +9,31 @@ use codespan_reporting::{
|
||||||
Config,
|
Config,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use riscv_interpreter::{
|
use colored::Colorize;
|
||||||
env::Env, execution::run_instruction, info::info, instructions::{instruction, kind::Kind}, parser::{parse, Token}
|
use itertools::Itertools;
|
||||||
|
use rizz_v::{
|
||||||
|
env::Env,
|
||||||
|
execution::run_instruction,
|
||||||
|
info::info,
|
||||||
|
parser::{parse, Token},
|
||||||
};
|
};
|
||||||
|
use termion::input::TermRead;
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
|
let display_mode = 's';
|
||||||
let writer = StandardStream::stderr(ColorChoice::Always);
|
let writer = StandardStream::stderr(ColorChoice::Always);
|
||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
let input = std::fs::read_to_string("test.s").unwrap();
|
let input = std::fs::read_to_string("test.s").unwrap();
|
||||||
|
let term_width = term_size::dimensions().map(|(w, _)| w).unwrap_or(80);
|
||||||
|
|
||||||
let file = SimpleFile::new("test.s", input.clone());
|
let file = SimpleFile::new("test.s", input.clone());
|
||||||
|
|
||||||
let mut env = Env::new();
|
let mut env = Env::new();
|
||||||
|
|
||||||
let mut ops: Vec<(Kind, String)> = Vec::new();
|
let mut toks: Vec<Token> = Vec::new();
|
||||||
|
let mut ops: Vec<u32> = Vec::new();
|
||||||
|
|
||||||
|
let mut parse_asm_result = String::new();
|
||||||
|
|
||||||
match parse(&env, &input) {
|
match parse(&env, &input) {
|
||||||
Ok(tokens) => {
|
Ok(tokens) => {
|
||||||
|
@ -33,55 +46,59 @@ fn main() -> anyhow::Result<()> {
|
||||||
let token = token.clone();
|
let token = token.clone();
|
||||||
|
|
||||||
match token.clone() {
|
match token.clone() {
|
||||||
Token::Op(name, _) => match env.assemble_op((token, loc.clone())) {
|
Token::Mnemonic(..) => {
|
||||||
Ok(op) => {
|
match env.assemble_op((token.clone(), loc.clone())) {
|
||||||
let mut formatted = format!(
|
Ok(op) => {
|
||||||
"{:<1$} {3:02x}: {2:032b}",
|
let mut formatted = format!(
|
||||||
lines[loc.line - 1],
|
"{:<1$} {3:02x}: {2:032b}",
|
||||||
size + 3,
|
lines[loc.line - 1],
|
||||||
op[0],
|
size + 3,
|
||||||
loc.mem_offset
|
op[0],
|
||||||
);
|
loc.mem_offset
|
||||||
ops.push(Kind::to_op(op[0].clone()));
|
);
|
||||||
|
ops.push(op[0]);
|
||||||
|
toks.push(token.clone());
|
||||||
|
|
||||||
if op.len() > 1 {
|
if op.len() > 1 {
|
||||||
for op in op[1..].iter() {
|
for op in op[1..].iter() {
|
||||||
formatted += &format!(
|
formatted += &format!(
|
||||||
"\n{:<1$} {3:02x}: {2:032b}",
|
"\n{:<1$} {3:02x}: {2:032b}",
|
||||||
"",
|
"",
|
||||||
size + 3,
|
size + 3,
|
||||||
op,
|
op,
|
||||||
loc.mem_offset
|
loc.mem_offset
|
||||||
);
|
);
|
||||||
ops.push(Kind::to_op(op.clone()));
|
ops.push(*op);
|
||||||
}
|
toks.push(token.clone());
|
||||||
}
|
|
||||||
println!("{}", formatted);
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
let diagnostic = Diagnostic::error()
|
|
||||||
.with_message("Runtime Error")
|
|
||||||
.with_labels(vec![Label::primary(
|
|
||||||
(),
|
|
||||||
err.1.start..(err.1.end + 1),
|
|
||||||
)
|
|
||||||
.with_message(err.0.to_string())])
|
|
||||||
.with_notes({
|
|
||||||
let mut notes = Vec::new();
|
|
||||||
if let Some(note) = &err.2 {
|
|
||||||
notes.push(note.to_string());
|
|
||||||
}
|
}
|
||||||
notes.push(err.0.note());
|
}
|
||||||
notes
|
parse_asm_result += &format!("{}\n", formatted);
|
||||||
});
|
}
|
||||||
|
Err(err) => {
|
||||||
|
let diagnostic = Diagnostic::error()
|
||||||
|
.with_message("Engine Error")
|
||||||
|
.with_labels(vec![Label::primary(
|
||||||
|
(),
|
||||||
|
err.1.start..(err.1.end + 1),
|
||||||
|
)
|
||||||
|
.with_message(err.0.to_string())])
|
||||||
|
.with_notes({
|
||||||
|
let mut notes = Vec::new();
|
||||||
|
if let Some(note) = &err.2 {
|
||||||
|
notes.push(note.to_string());
|
||||||
|
}
|
||||||
|
notes.push(err.0.note());
|
||||||
|
notes
|
||||||
|
});
|
||||||
|
|
||||||
term::emit(&mut writer.lock(), &config, &file, &diagnostic)
|
term::emit(&mut writer.lock(), &config, &file, &diagnostic)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Token::Label(name) => {
|
Token::Label(name) => {
|
||||||
println!(
|
parse_asm_result += &format!(
|
||||||
"{:<1$} <{2:02x}>",
|
"{:<1$} <{2:02x}>\n",
|
||||||
name.clone() + ":",
|
name.clone() + ":",
|
||||||
size + 3,
|
size + 3,
|
||||||
env.get_label(&name).unwrap()
|
env.get_label(&name).unwrap()
|
||||||
|
@ -116,15 +133,341 @@ fn main() -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for op in ops {
|
let mut file = std::fs::File::create("test.bin")?;
|
||||||
run_instruction(&mut env, op.0);
|
for op in ops.iter() {
|
||||||
|
let formatted = format!("{:08x}\n", op);
|
||||||
|
file.write_all(formatted.as_bytes()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the register values
|
||||||
|
|
||||||
|
while env.pc / 4 < ops.clone().len() as u32 {
|
||||||
|
let pc = env.pc.clone();
|
||||||
|
let prev_regs = env.registers.clone();
|
||||||
|
let prev_fregs = env.fregisters.clone();
|
||||||
|
|
||||||
|
env.pc += 4 * !run_instruction(&mut env, ops[pc as usize >> 2]) as u32;
|
||||||
|
|
||||||
|
let mut changed = Vec::new();
|
||||||
|
for (i, _) in prev_regs
|
||||||
|
.iter()
|
||||||
|
.zip(env.registers.iter())
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_, (prev, curr))| prev != curr)
|
||||||
|
{
|
||||||
|
changed.push(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut fchanged = Vec::new();
|
||||||
|
for (i, _) in prev_fregs
|
||||||
|
.iter()
|
||||||
|
.zip(env.fregisters.iter())
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_, (prev, curr))| prev != curr)
|
||||||
|
{
|
||||||
|
fchanged.push(i);
|
||||||
|
}
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"{:<1$} <{2:02x}>",
|
"{}\n",
|
||||||
op.1,
|
parse_asm_result
|
||||||
32,
|
.lines()
|
||||||
env.get_register(10));
|
.enumerate()
|
||||||
|
.map(|(i, line)| {
|
||||||
|
if i == pc as usize >> 2 {
|
||||||
|
format!("> {}", line).bright_green()
|
||||||
|
} else {
|
||||||
|
format!(" {}", line).normal()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.join("\n")
|
||||||
|
);
|
||||||
|
let (right, tag) = if let Token::Mnemonic(op, args) = &toks[pc as usize >> 2] {
|
||||||
|
info(
|
||||||
|
&env,
|
||||||
|
&op,
|
||||||
|
args.iter().map(|(token, _)| token.to_string()).collect(),
|
||||||
|
display_mode,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
let left = make_box(
|
||||||
|
term_width as u32 / 2,
|
||||||
|
pc as usize,
|
||||||
|
env.registers.clone().into_iter().collect(),
|
||||||
|
changed,
|
||||||
|
display_mode,
|
||||||
|
true,
|
||||||
|
tag.clone(),
|
||||||
|
) + &make_box_fp(
|
||||||
|
term_width as u32 / 2,
|
||||||
|
env.fregisters.clone().into_iter().collect(),
|
||||||
|
fchanged,
|
||||||
|
display_mode,
|
||||||
|
true,
|
||||||
|
tag,
|
||||||
|
);
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"{}",
|
||||||
|
left.lines()
|
||||||
|
.zip(right.lines().chain([""].repeat(left.lines().count())))
|
||||||
|
.map(|(l, r)| format!("{} {}", l, r))
|
||||||
|
.join("\n")
|
||||||
|
);
|
||||||
|
|
||||||
|
println!("\nPress enter to continue...");
|
||||||
|
for c in std::io::stdin().keys() {
|
||||||
|
match c.unwrap() {
|
||||||
|
termion::event::Key::Char('\n') => break,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fn round_down_to_power_of_two(n: u32) -> u32 {
|
||||||
|
1 << (32 - n.leading_zeros() - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Assuming the terminal is at least 80 characters wide
|
||||||
|
///
|
||||||
|
/// Display Mode:
|
||||||
|
/// - s: signed decimal
|
||||||
|
/// - u: unsigned decimal
|
||||||
|
/// - b: binary
|
||||||
|
/// - h: hex
|
||||||
|
fn make_box(
|
||||||
|
width: u32,
|
||||||
|
pc: usize,
|
||||||
|
regs: Vec<u32>,
|
||||||
|
changed: Vec<usize>,
|
||||||
|
display_mode: char,
|
||||||
|
first: bool,
|
||||||
|
tag: (Vec<usize>, Vec<usize>),
|
||||||
|
) -> String {
|
||||||
|
let cell_inner_width: u32 = match display_mode {
|
||||||
|
'b' => 32,
|
||||||
|
'u' => 10,
|
||||||
|
'h' => 8,
|
||||||
|
's' => 11,
|
||||||
|
_ => unreachable!(),
|
||||||
|
} + 7;
|
||||||
|
|
||||||
|
// Nnumber of boxes that fit horizontally
|
||||||
|
let num_boxes = round_down_to_power_of_two((width / (cell_inner_width + 2)) as u32);
|
||||||
|
if num_boxes <= 1 {
|
||||||
|
return make_one_wide_box(pc, regs, changed, display_mode, first, tag);
|
||||||
|
}
|
||||||
|
let mut boxed = String::new();
|
||||||
|
|
||||||
|
if first {
|
||||||
|
boxed += &format!(
|
||||||
|
"┌─╢ pc = {pc:04x} ╟{:─<1$}┬",
|
||||||
|
"",
|
||||||
|
cell_inner_width.saturating_sub(14) as usize
|
||||||
|
);
|
||||||
|
for _ in 1..(num_boxes - 1) {
|
||||||
|
boxed += &format!("{:─<1$}┬", "", cell_inner_width as usize);
|
||||||
|
}
|
||||||
|
boxed += &format!("{:─<1$}┐\n", "", cell_inner_width as usize);
|
||||||
|
} else {
|
||||||
|
boxed += &format!(
|
||||||
|
"├─╢ pc = {pc:04x} ╟{:─<1$}┼",
|
||||||
|
"",
|
||||||
|
cell_inner_width.saturating_sub(14) as usize
|
||||||
|
);
|
||||||
|
for _ in 1..(num_boxes - 1) {
|
||||||
|
boxed += &format!("{:─<1$}┼", "", cell_inner_width as usize);
|
||||||
|
}
|
||||||
|
boxed += &format!("{:─<1$}┤\n", "", cell_inner_width as usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
for chunk in ®s.iter().enumerate().chunks(num_boxes as usize) {
|
||||||
|
let chunk = chunk.collect::<Vec<_>>();
|
||||||
|
let mut formatted = String::from("│ ");
|
||||||
|
|
||||||
|
for (i, reg) in chunk {
|
||||||
|
let reg = match display_mode {
|
||||||
|
'b' => format!("x{:<3} {1:0>32b}", i.to_string() + ":", reg),
|
||||||
|
'u' => format!("x{:<3} {1:>10}", i.to_string() + ":", reg),
|
||||||
|
'h' => format!("x{:<3} {1:0>8x}", i.to_string() + ":", reg),
|
||||||
|
's' => {
|
||||||
|
let signed = *reg as i32;
|
||||||
|
let sign = if signed < 0 { "-" } else { "+" };
|
||||||
|
format!(
|
||||||
|
"x{:<3} {:>11}",
|
||||||
|
i.to_string() + ":",
|
||||||
|
sign.to_string() + &signed.abs().to_string()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let reg = if changed.contains(&i) {
|
||||||
|
reg.bright_green()
|
||||||
|
} else {
|
||||||
|
if tag.0.contains(&i) {
|
||||||
|
reg.bright_yellow()
|
||||||
|
} else {
|
||||||
|
reg.normal()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
formatted += &format!("{} │ ", reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
boxed += &format!("{}\n", formatted);
|
||||||
|
}
|
||||||
|
|
||||||
|
boxed
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_one_wide_box(
|
||||||
|
pc: usize,
|
||||||
|
regs: Vec<u32>,
|
||||||
|
changed: Vec<usize>,
|
||||||
|
display_mode: char,
|
||||||
|
first: bool,
|
||||||
|
tag: (Vec<usize>, Vec<usize>),
|
||||||
|
) -> String {
|
||||||
|
let mut boxed = String::new();
|
||||||
|
|
||||||
|
boxed += &if first {
|
||||||
|
format!("┌─╢ pc = {pc:04x} ╟{:─<1$}┐\n", "", 32)
|
||||||
|
} else {
|
||||||
|
format!("├─╢ pc = {pc:04x} ╟{:─<1$}┤\n", "", 32)
|
||||||
|
};
|
||||||
|
for (i, reg) in regs.iter().enumerate() {
|
||||||
|
let reg = match display_mode {
|
||||||
|
'b' => format!("x{:<3} {1:0>32b}", i.to_string() + ":", reg),
|
||||||
|
'u' => format!("x{:<3} {1:0>10}", i.to_string() + ":", reg),
|
||||||
|
'h' => format!("x{:<3} {1:0>8x}", i.to_string() + ":", reg),
|
||||||
|
's' => {
|
||||||
|
let signed = *reg as i32;
|
||||||
|
let sign = if signed < 0 { "-" } else { "+" };
|
||||||
|
format!("x{:<3} {}{:0>10}", i.to_string() + ":", sign, signed.abs())
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let reg = if changed.contains(&i) {
|
||||||
|
reg.bright_green()
|
||||||
|
} else {
|
||||||
|
if tag.0.contains(&i) {
|
||||||
|
reg.bright_yellow()
|
||||||
|
} else {
|
||||||
|
reg.normal()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
boxed += &format!("│ {} │\n", reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
boxed
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Assuming the terminal is at least 80 characters wide
|
||||||
|
/// Display Mode:
|
||||||
|
/// - s,u: floating point
|
||||||
|
/// - b: binary
|
||||||
|
/// - x: hexadecimal
|
||||||
|
/// - e: scientific
|
||||||
|
fn make_box_fp(
|
||||||
|
width: u32,
|
||||||
|
regs: Vec<f32>,
|
||||||
|
changed: Vec<usize>,
|
||||||
|
display_mode: char,
|
||||||
|
last: bool,
|
||||||
|
tag: (Vec<usize>, Vec<usize>),
|
||||||
|
) -> String {
|
||||||
|
let cell_inner_width: u32 = 11 + 7;
|
||||||
|
|
||||||
|
// Nnumber of boxes that fit horizontally
|
||||||
|
let num_boxes = round_down_to_power_of_two((width / (cell_inner_width + 2)) as u32);
|
||||||
|
if num_boxes <= 1 {
|
||||||
|
return make_one_wide_box_fp(regs, changed, last, tag);
|
||||||
|
}
|
||||||
|
let mut boxed = String::new();
|
||||||
|
|
||||||
|
boxed += &format!("├─{:─<1$}┼", "", (cell_inner_width - 1) as usize);
|
||||||
|
for _ in 1..(num_boxes - 1) {
|
||||||
|
boxed += &format!("{:─<1$}┼", "", cell_inner_width as usize);
|
||||||
|
}
|
||||||
|
boxed += &format!("{:─<1$}┤\n", "", cell_inner_width as usize);
|
||||||
|
|
||||||
|
for chunk in ®s.iter().enumerate().chunks(num_boxes as usize) {
|
||||||
|
let chunk = chunk.collect::<Vec<_>>();
|
||||||
|
let mut formatted = String::from("│ ");
|
||||||
|
|
||||||
|
for (i, freg) in chunk {
|
||||||
|
// let freg = format!("f{:<3} {:>11}", i.to_string() + ":", freg);
|
||||||
|
let freg = match display_mode {
|
||||||
|
's' | 'u' => format!("f{:<3} {:>11}", i.to_string() + ":", freg),
|
||||||
|
'b' => format!("f{:<3} {:0>32b}", i.to_string() + ":", freg.to_bits()),
|
||||||
|
'x' => format!("f{:<3} {:0>8x}", i.to_string() + ":", freg.to_bits()),
|
||||||
|
'e' => format!("f{:<3} {:>11e}", i.to_string() + ":", freg),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let reg = if changed.contains(&i) {
|
||||||
|
freg.bright_green()
|
||||||
|
} else {
|
||||||
|
if tag.1.contains(&i) {
|
||||||
|
freg.bright_yellow()
|
||||||
|
} else {
|
||||||
|
freg.normal()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
formatted += &format!("{} │ ", reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
boxed += &format!("{}\n", formatted);
|
||||||
|
}
|
||||||
|
|
||||||
|
if last {
|
||||||
|
boxed += &format!("└{:─<1$}┴", "", cell_inner_width as usize);
|
||||||
|
for _ in 1..(num_boxes - 1) {
|
||||||
|
boxed += &format!("{:─<1$}┴", "", cell_inner_width as usize);
|
||||||
|
}
|
||||||
|
boxed += &format!("{:─<1$}┘", "", cell_inner_width as usize);
|
||||||
|
} else {
|
||||||
|
boxed += &format!("├{:─<1$}┼", "", cell_inner_width as usize);
|
||||||
|
for _ in 1..(num_boxes - 1) {
|
||||||
|
boxed += &format!("{:─<1$}┼", "", cell_inner_width as usize);
|
||||||
|
}
|
||||||
|
boxed += &format!("{:─<1$}┤", "", cell_inner_width as usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
boxed
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_one_wide_box_fp(
|
||||||
|
regs: Vec<f32>,
|
||||||
|
changed: Vec<usize>,
|
||||||
|
last: bool,
|
||||||
|
tag: (Vec<usize>, Vec<usize>),
|
||||||
|
) -> String {
|
||||||
|
let mut boxed = String::new();
|
||||||
|
|
||||||
|
boxed += &format!("├─{:─<1$}┤\n", "", 32);
|
||||||
|
|
||||||
|
for (i, freg) in regs.iter().enumerate() {
|
||||||
|
let freg = format!("f{:<3} {:0>11}", i.to_string() + ":", freg);
|
||||||
|
let reg = if changed.contains(&i) {
|
||||||
|
freg.bright_green()
|
||||||
|
} else {
|
||||||
|
if tag.1.contains(&i) {
|
||||||
|
freg.bright_yellow()
|
||||||
|
} else {
|
||||||
|
freg.normal()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
boxed += &format!("│ {} │\n", reg);
|
||||||
|
}
|
||||||
|
boxed += &if last {
|
||||||
|
format!("└{:─<1$}┘", "", 32)
|
||||||
|
} else {
|
||||||
|
format!("├{:─<1$}┤", "", 32)
|
||||||
|
};
|
||||||
|
|
||||||
|
boxed
|
||||||
|
}
|
||||||
|
|
|
@ -83,6 +83,81 @@ fn parse_line(env: &Env, input: &str, loc: &mut Loc) -> Result<Vec<(Token, Loc)>
|
||||||
Spacing
|
Spacing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
'0' if chars.peek() == Some(&'x') => {
|
||||||
|
chars.next();
|
||||||
|
loc.end += 1;
|
||||||
|
let mut num = std::string::String::new();
|
||||||
|
while let Some('0'..='9') | Some('a'..='f') | Some('A'..='F') = chars.peek() {
|
||||||
|
num.push(chars.next().unwrap());
|
||||||
|
loc.end += 1;
|
||||||
|
}
|
||||||
|
if let Some('(') | Some(' ') | None = chars.peek() {
|
||||||
|
Immediate(u32::from_str_radix(&num, 16).unwrap())
|
||||||
|
} else {
|
||||||
|
let err = Err((
|
||||||
|
SyntaxErr::UnexpectedChar,
|
||||||
|
Loc {
|
||||||
|
start: loc.end + 1,
|
||||||
|
end: loc.end + 1,
|
||||||
|
..*loc
|
||||||
|
},
|
||||||
|
tokens.clone(),
|
||||||
|
None,
|
||||||
|
));
|
||||||
|
advance_to_next_line(&mut chars, loc);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'0' if chars.peek() == Some(&'b') => {
|
||||||
|
chars.next();
|
||||||
|
loc.end += 1;
|
||||||
|
let mut num = std::string::String::new();
|
||||||
|
while let Some('0'..='1') = chars.peek() {
|
||||||
|
num.push(chars.next().unwrap());
|
||||||
|
loc.end += 1;
|
||||||
|
}
|
||||||
|
if let Some('(') | Some(' ') | None = chars.peek() {
|
||||||
|
Immediate(u32::from_str_radix(&num, 2).unwrap())
|
||||||
|
} else {
|
||||||
|
let err = Err((
|
||||||
|
SyntaxErr::UnexpectedChar,
|
||||||
|
Loc {
|
||||||
|
start: loc.end + 1,
|
||||||
|
end: loc.end + 1,
|
||||||
|
..*loc
|
||||||
|
},
|
||||||
|
tokens.clone(),
|
||||||
|
None,
|
||||||
|
));
|
||||||
|
advance_to_next_line(&mut chars, loc);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'0' if chars.peek() == Some(&'o') => {
|
||||||
|
chars.next();
|
||||||
|
loc.end += 1;
|
||||||
|
let mut num = std::string::String::new();
|
||||||
|
while let Some('0'..='7') = chars.peek() {
|
||||||
|
num.push(chars.next().unwrap());
|
||||||
|
loc.end += 1;
|
||||||
|
}
|
||||||
|
if let Some('(') | Some(' ') | None = chars.peek() {
|
||||||
|
Immediate(u32::from_str_radix(&num, 8).unwrap())
|
||||||
|
} else {
|
||||||
|
let err = Err((
|
||||||
|
SyntaxErr::UnexpectedChar,
|
||||||
|
Loc {
|
||||||
|
start: loc.end + 1,
|
||||||
|
end: loc.end + 1,
|
||||||
|
..*loc
|
||||||
|
},
|
||||||
|
tokens.clone(),
|
||||||
|
None,
|
||||||
|
));
|
||||||
|
advance_to_next_line(&mut chars, loc);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
'0'..='9' => {
|
'0'..='9' => {
|
||||||
let mut num = c.to_string();
|
let mut num = c.to_string();
|
||||||
while let Some('0'..='9') = chars.peek() {
|
while let Some('0'..='9') = chars.peek() {
|
||||||
|
@ -90,7 +165,7 @@ fn parse_line(env: &Env, input: &str, loc: &mut Loc) -> Result<Vec<(Token, Loc)>
|
||||||
loc.end += 1;
|
loc.end += 1;
|
||||||
}
|
}
|
||||||
if let Some('(') | Some(' ') | None = chars.peek() {
|
if let Some('(') | Some(' ') | None = chars.peek() {
|
||||||
Immediate(num.parse().unwrap())
|
dbg!(Immediate(num.parse().unwrap()))
|
||||||
} else {
|
} else {
|
||||||
let err = Err((
|
let err = Err((
|
||||||
SyntaxErr::UnexpectedChar,
|
SyntaxErr::UnexpectedChar,
|
||||||
|
|
178
src/tests.rs
178
src/tests.rs
|
@ -2,11 +2,10 @@
|
||||||
/// Test values come from Ripes
|
/// Test values come from Ripes
|
||||||
use crate::{
|
use crate::{
|
||||||
env::Env,
|
env::Env,
|
||||||
instructions::{get_instruction, with},
|
instructions::{get_instruction, handle_pseudo, with},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore = "TODO"]
|
|
||||||
fn nop() {
|
fn nop() {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
{
|
{
|
||||||
|
@ -17,21 +16,48 @@ fn nop() {
|
||||||
};
|
};
|
||||||
// nop
|
// nop
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
u32::from_str_radix(
|
handle_pseudo(
|
||||||
&with(
|
get_instruction("nop"),
|
||||||
get_instruction("nop"),
|
0, // imm
|
||||||
0, // imm
|
vec![]
|
||||||
vec![]
|
)[0]
|
||||||
)
|
.0
|
||||||
.0
|
.to_u32(),
|
||||||
.to_string(),
|
0b00000000000000000000000000010011
|
||||||
2
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
0b00000000000000000000000000010011u32
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn li() {
|
||||||
|
let env = Env::new();
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
{
|
||||||
|
// li (pseudo) -> Myriad Sequence (in this case, both addi and lui)
|
||||||
|
// 1 -> lui
|
||||||
|
// U-Type
|
||||||
|
// | imm20 | rd | opcode
|
||||||
|
// 00000000000000001101 01010 0110111
|
||||||
|
// 2 -> addi
|
||||||
|
// I-Type
|
||||||
|
// | imm12 | ra |f3 | rd | opcode
|
||||||
|
// 000000101001 01010 000 01010 0010011
|
||||||
|
};
|
||||||
|
// li a0 53289
|
||||||
|
assert!(handle_pseudo(
|
||||||
|
get_instruction("li"),
|
||||||
|
53289,
|
||||||
|
vec![env.str_to_register("a0").unwrap()]
|
||||||
|
)
|
||||||
|
.into_iter()
|
||||||
|
.map(|i| i.0.to_u32())
|
||||||
|
.eq([
|
||||||
|
0b00000000000000001101010100110111,
|
||||||
|
0b00000010100101010000010100010011
|
||||||
|
]
|
||||||
|
.into_iter()));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn lui() {
|
fn lui() {
|
||||||
let env = Env::new();
|
let env = Env::new();
|
||||||
|
@ -40,23 +66,18 @@ fn lui() {
|
||||||
{
|
{
|
||||||
// U-Type
|
// U-Type
|
||||||
// | imm20 | rd | opcode
|
// | imm20 | rd | opcode
|
||||||
// 00000000000000000011 01010 0110111
|
|
||||||
// 00000011010100101001 01010 0110111
|
// 00000011010100101001 01010 0110111
|
||||||
};
|
};
|
||||||
// lui a0 13609
|
// lui a0 13609
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
u32::from_str_radix(
|
with(
|
||||||
&with(
|
get_instruction("lui"),
|
||||||
get_instruction("lui"),
|
13609 << 12,
|
||||||
13609 << 12,
|
vec![env.str_to_register("a0").unwrap()]
|
||||||
vec![env.str_to_register("a0").unwrap()]
|
|
||||||
)
|
|
||||||
.0
|
|
||||||
.to_string(),
|
|
||||||
2
|
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.0
|
||||||
0b00000011010100101001010100110111u32
|
.to_u32(),
|
||||||
|
0b00000011010100101001010100110111
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,22 +93,18 @@ fn sb() {
|
||||||
};
|
};
|
||||||
// sb t5 -4(sp)
|
// sb t5 -4(sp)
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
u32::from_str_radix(
|
with(
|
||||||
&with(
|
get_instruction("sb"),
|
||||||
get_instruction("sb"),
|
-4i32 as u32, // imm
|
||||||
-4i32 as u32, // imm
|
vec![
|
||||||
vec![
|
0, // rd
|
||||||
0, // rd
|
env.str_to_register("sp").unwrap(), // ra
|
||||||
env.str_to_register("sp").unwrap(), // ra
|
env.str_to_register("t5").unwrap() // rb
|
||||||
env.str_to_register("t5").unwrap() // rb
|
],
|
||||||
],
|
|
||||||
)
|
|
||||||
.0
|
|
||||||
.to_string(),
|
|
||||||
2
|
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.0
|
||||||
0b11111111111000010000111000100011u32
|
.to_u32(),
|
||||||
|
0b11111111111000010000111000100011
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,22 +120,18 @@ fn add() {
|
||||||
};
|
};
|
||||||
// add a0 a0 a1
|
// add a0 a0 a1
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
u32::from_str_radix(
|
with(
|
||||||
&with(
|
get_instruction("add"),
|
||||||
get_instruction("add"),
|
0, // imm
|
||||||
0, // imm
|
vec![
|
||||||
vec![
|
env.str_to_register("a0").unwrap(), // rd
|
||||||
env.str_to_register("a0").unwrap(), // rd
|
env.str_to_register("a0").unwrap(), // ra
|
||||||
env.str_to_register("a0").unwrap(), // ra
|
env.str_to_register("a1").unwrap() // rb
|
||||||
env.str_to_register("a1").unwrap() // rb
|
]
|
||||||
]
|
|
||||||
)
|
|
||||||
.0
|
|
||||||
.to_string(),
|
|
||||||
2
|
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.0
|
||||||
0b00000000101101010000010100110011u32
|
.to_u32(),
|
||||||
|
0b00000000101101010000010100110011
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,26 +144,20 @@ fn addi() {
|
||||||
// I-Type
|
// I-Type
|
||||||
// | imm12 | ra |f3 | rd | opcode
|
// | imm12 | ra |f3 | rd | opcode
|
||||||
// 000000000001 01010 000 01010 0010011
|
// 000000000001 01010 000 01010 0010011
|
||||||
// 000000000001 01010 000 01010 0010011 (Ripes)
|
|
||||||
};
|
};
|
||||||
// addi a0 a0 1
|
// addi a0 a0 1
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
u32::from_str_radix(
|
with(
|
||||||
with(
|
get_instruction("addi"),
|
||||||
get_instruction("addi"),
|
1,
|
||||||
1,
|
vec![
|
||||||
vec![
|
env.str_to_register("a0").unwrap(),
|
||||||
env.str_to_register("a0").unwrap(),
|
env.str_to_register("a0").unwrap()
|
||||||
env.str_to_register("a0").unwrap()
|
],
|
||||||
],
|
|
||||||
)
|
|
||||||
.0
|
|
||||||
.to_string()
|
|
||||||
.as_str(),
|
|
||||||
2
|
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.0
|
||||||
0b00000000000101010000010100010011u32
|
.to_u32(),
|
||||||
|
0b00000000000101010000010100010011
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,25 +170,20 @@ fn beq() {
|
||||||
// B-Type
|
// B-Type
|
||||||
// | imm7 | rb | ra |f3 |imm5 | opcode
|
// | imm7 | rb | ra |f3 |imm5 | opcode
|
||||||
// 0000000 01011 01010 000 00100 1100011
|
// 0000000 01011 01010 000 00100 1100011
|
||||||
// 0000000 01011 01010 000 00100 1100011 (Ripes)
|
|
||||||
};
|
};
|
||||||
// beq a0 a1 4
|
// beq a0 a1 4
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
u32::from_str_radix(
|
with(
|
||||||
&with(
|
get_instruction("beq"),
|
||||||
get_instruction("beq"),
|
4,
|
||||||
4,
|
vec![
|
||||||
vec![
|
0, // no rd
|
||||||
0, // no rd
|
env.str_to_register("a0").unwrap(),
|
||||||
env.str_to_register("a0").unwrap(),
|
env.str_to_register("a1").unwrap()
|
||||||
env.str_to_register("a1").unwrap()
|
]
|
||||||
]
|
|
||||||
)
|
|
||||||
.0
|
|
||||||
.to_string(),
|
|
||||||
2
|
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.0
|
||||||
0b00000000101101010000001001100011u32
|
.to_u32(),
|
||||||
|
0b00000000101101010000001001100011
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
17
test.s
17
test.s
|
@ -1,12 +1,11 @@
|
||||||
# li a0 55743235
|
li a0 5
|
||||||
li a1 1
|
li a1 1
|
||||||
|
lui a2 0x3f800000
|
||||||
|
|
||||||
# 5!
|
add a2 a0 a1
|
||||||
factorial:
|
|
||||||
# beqz a0 end
|
|
||||||
# mul a1 a1 a0
|
|
||||||
# addi a0 a0 -1
|
|
||||||
# j factorial
|
|
||||||
|
|
||||||
end:
|
fcvt.s.w fa0 a0
|
||||||
# nop
|
fcvt.s.w fa1 a1
|
||||||
|
|
||||||
|
fadd.s fa2 fa0 fa1
|
||||||
|
fdiv.s fa3 fa2 fa0
|
||||||
|
|
Loading…
Reference in a new issue