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
|
||||
|
||||
test.bin
|
||||
|
|
221
Cargo.lock
generated
221
Cargo.lock
generated
|
@ -4,15 +4,27 @@ version = 3
|
|||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.79"
|
||||
version = "1.0.82"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
|
||||
checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
|
||||
|
||||
[[package]]
|
||||
name = "bitfield"
|
||||
version = "0.14.0"
|
||||
version = "0.15.0"
|
||||
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]]
|
||||
name = "codespan-reporting"
|
||||
|
@ -31,7 +43,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"windows-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -61,19 +73,29 @@ checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
|
|||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.9.0"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||
checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.0"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
|
||||
dependencies = [
|
||||
"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]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
|
@ -82,15 +104,32 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.152"
|
||||
version = "0.2.154"
|
||||
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]]
|
||||
name = "rayon"
|
||||
version = "1.8.1"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051"
|
||||
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
|
@ -107,7 +146,22 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[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"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
|
@ -117,14 +171,16 @@ dependencies = [
|
|||
"itertools",
|
||||
"rayon",
|
||||
"term_size",
|
||||
"termion",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "term_size"
|
||||
version = "0.3.2"
|
||||
version = "1.0.0-beta1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9"
|
||||
checksum = "a8a17d8699e154863becdf18e4fd28bd0be27ca72856f54daf75c00f2566898f"
|
||||
dependencies = [
|
||||
"kernel32-sys",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
@ -139,49 +195,60 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.11"
|
||||
name = "termion"
|
||||
version = "3.0.0"
|
||||
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]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.6"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
|
||||
checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
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]]
|
||||
|
@ -190,13 +257,29 @@ version = "0.48.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
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",
|
||||
"windows_aarch64_gnullvm 0.48.5",
|
||||
"windows_aarch64_msvc 0.48.5",
|
||||
"windows_i686_gnu 0.48.5",
|
||||
"windows_i686_msvc 0.48.5",
|
||||
"windows_x86_64_gnu 0.48.5",
|
||||
"windows_x86_64_gnullvm 0.48.5",
|
||||
"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]]
|
||||
|
@ -205,38 +288,86 @@ version = "0.48.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]
|
||||
name = "riscv_interpreter"
|
||||
name = "rizz-v"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.79"
|
||||
bitfield = "0.14.0"
|
||||
anyhow = "1.0.82"
|
||||
bitfield = "0.15.0"
|
||||
codespan-reporting = "0.11.1"
|
||||
colored = "2.1.0"
|
||||
itertools = "0.12.0"
|
||||
rayon = "1.8.1"
|
||||
term_size = "0.3.2"
|
||||
itertools = "0.12.1"
|
||||
rayon = "1.10.0"
|
||||
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(),
|
||||
}
|
||||
}
|
95
src/env.rs
95
src/env.rs
|
@ -18,7 +18,8 @@ pub enum Variables {
|
|||
pub struct Env {
|
||||
register_alias: HashMap<String, usize>,
|
||||
labels: HashMap<String, u32>,
|
||||
registers: [u32; 32],
|
||||
pub registers: [u32; 32],
|
||||
pub fregisters: [f32; 32],
|
||||
pub prev_stacks: Vec<Vec<u32>>,
|
||||
pub stack: Vec<u32>, // TODO: Find the actual size of the stack
|
||||
pub instructions: Vec<u32>,
|
||||
|
@ -29,6 +30,7 @@ impl Env {
|
|||
pub fn new() -> Self {
|
||||
// alias -> xN
|
||||
let register_alias = [
|
||||
// Integer regs
|
||||
("zero", 0),
|
||||
("ra", 1),
|
||||
("sp", 2),
|
||||
|
@ -62,6 +64,39 @@ impl Env {
|
|||
("t4", 29),
|
||||
("t5", 30),
|
||||
("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()
|
||||
.map(|(k, v)| (k.to_string(), v.to_owned()))
|
||||
|
@ -71,6 +106,7 @@ impl Env {
|
|||
register_alias,
|
||||
labels: HashMap::new(),
|
||||
registers: [0; 32],
|
||||
fregisters: [0.0; 32],
|
||||
prev_stacks: Vec::new(),
|
||||
stack: Vec::from([0; 1024]), // 1024 * 64 = 64 KiB stack
|
||||
instructions: Vec::new(),
|
||||
|
@ -99,6 +135,22 @@ impl Env {
|
|||
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) {
|
||||
self.labels.insert(label.to_string(), value);
|
||||
|
@ -108,7 +160,7 @@ impl Env {
|
|||
}
|
||||
|
||||
pub fn assemble_op(
|
||||
&self,
|
||||
&mut self,
|
||||
op: (Token, Loc),
|
||||
) -> Result<Vec<u32>, (RuntimeErr, Loc, Option<String>)> {
|
||||
if let (Token::Op(name, args), loc) = op {
|
||||
|
@ -131,26 +183,35 @@ impl Env {
|
|||
));
|
||||
}
|
||||
|
||||
let _ =
|
||||
i.1.clone()
|
||||
let _ = i
|
||||
.1
|
||||
.clone()
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.try_for_each(|(k, v)| match v {
|
||||
Arg::Immediate => {
|
||||
if let Token::Immediate(i) = args[k].0 {
|
||||
Arg::Immediate => match args[k].0.clone() {
|
||||
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(())
|
||||
} else {
|
||||
Err((
|
||||
RuntimeErr::InvalidType(
|
||||
Arg::from(args[k].0.clone()).kind(),
|
||||
v.kind(),
|
||||
),
|
||||
RuntimeErr::LabelNotFound,
|
||||
args[k].1,
|
||||
None,
|
||||
))
|
||||
}
|
||||
}
|
||||
_ => Err((
|
||||
RuntimeErr::InvalidType(Arg::from(args[k].0.clone()).kind(), v.kind()),
|
||||
args[k].1,
|
||||
None,
|
||||
)),
|
||||
},
|
||||
Arg::Register(id) => {
|
||||
if let Token::Register(r) = &args[k].0 {
|
||||
regs[id] = self.str_to_register(&r).unwrap();
|
||||
|
@ -203,14 +264,14 @@ impl Env {
|
|||
Ok(())
|
||||
} else {
|
||||
Err((
|
||||
RuntimeErr::InvalidType(
|
||||
Arg::from(args[k].0.clone()).kind(),
|
||||
v.kind(),
|
||||
),
|
||||
RuntimeErr::LabelNotFound,
|
||||
args[k].1,
|
||||
None,
|
||||
))
|
||||
}
|
||||
} else if let Token::Immediate(i) = &args[k].0 {
|
||||
imm = *i as u32;
|
||||
Ok(())
|
||||
} else {
|
||||
Err((
|
||||
RuntimeErr::InvalidType(
|
||||
|
@ -250,7 +311,7 @@ impl Env {
|
|||
Token::Op(name, _) => {
|
||||
if let Some((kind, args)) = instruction(&name) {
|
||||
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])
|
||||
.into_iter()
|
||||
.for_each(|_| i += 4);
|
||||
|
@ -260,7 +321,7 @@ impl Env {
|
|||
}
|
||||
}
|
||||
Token::Label(name) => {
|
||||
self.add_label(&name, (i + 4) as u32);
|
||||
self.add_label(&name, i as u32);
|
||||
}
|
||||
other => {
|
||||
dbg!(other);
|
||||
|
@ -276,7 +337,7 @@ impl Env {
|
|||
&mut self,
|
||||
(op, loc): (Token, Loc),
|
||||
) -> 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) {
|
||||
(i, args.clone())
|
||||
} else {
|
||||
|
|
60
src/err.rs
60
src/err.rs
|
@ -9,20 +9,30 @@ use crate::instructions::instruction;
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SyntaxErr {
|
||||
UnexpectedChar,
|
||||
|
||||
//.text specific
|
||||
/// false for '(' true for ')'
|
||||
UnmatchedParen(bool),
|
||||
UnexpectedChar,
|
||||
OutsideOp(String),
|
||||
OutsideMnemonic(String),
|
||||
InvalidRegister,
|
||||
|
||||
// .data specific
|
||||
InvalidType,
|
||||
InvalidVarName,
|
||||
MalformedData,
|
||||
}
|
||||
|
||||
impl Display for SyntaxErr {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
SyntaxErr::UnmatchedParen(_) => write!(f, "unmatched parenthesis"),
|
||||
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::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 {
|
||||
pub fn note(&self) -> String {
|
||||
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::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 => {
|
||||
"registers are either xN (N < 32 with no leading 0) or the standard aliases"
|
||||
.to_string()
|
||||
"registers are either (x|f)N, for N < 32 with no leading 0, or an alias".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)]
|
||||
pub enum RuntimeErr {
|
||||
InvalidOp,
|
||||
/// TODO: only worth using this after all the instructions are implemented!
|
||||
InvalidMnemonic,
|
||||
/// op, actual, expected
|
||||
InvalidOpArity(String, usize, usize),
|
||||
/// actual, expected
|
||||
InvalidType(String, String),
|
||||
TypeMissmatch(String, String),
|
||||
LabelNotFound,
|
||||
}
|
||||
|
||||
impl Display for RuntimeErr {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
RuntimeErr::InvalidOp => write!(f, "invalid opcode"),
|
||||
RuntimeErr::InvalidOpArity(op, actual, expected) => {
|
||||
write!(f, "`{}` expected {} args, got {}", op, expected, actual)
|
||||
RuntimeErr::InvalidMnemonic => write!(f, "invalid mnemonic"),
|
||||
RuntimeErr::InvalidOpArity(_, actual, expected) => {
|
||||
write!(f, "expected {} args, got {}", expected, actual)
|
||||
}
|
||||
RuntimeErr::InvalidType(actual, expected) => {
|
||||
write!(f, "expected `{}`, got `{}`", expected, actual)
|
||||
RuntimeErr::TypeMissmatch(actual, expected) => {
|
||||
write!(f, "expected '{}', got '{}'", expected, actual)
|
||||
}
|
||||
RuntimeErr::LabelNotFound => write!(f, "label not found"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +83,9 @@ impl Display for RuntimeErr {
|
|||
impl RuntimeErr {
|
||||
pub fn note(&self) -> String {
|
||||
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) => {
|
||||
let args = instruction(op).unwrap().1;
|
||||
match actual.cmp(expected) {
|
||||
|
@ -78,7 +95,7 @@ impl RuntimeErr {
|
|||
}
|
||||
Ordering::Greater => "remove the extra arguments".to_string(),
|
||||
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!(
|
||||
"add the extra `{}` arguments",
|
||||
|
@ -86,11 +103,14 @@ impl RuntimeErr {
|
|||
.unwrap()
|
||||
.iter()
|
||||
.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};
|
||||
|
||||
/// 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
|
||||
fn lui(env: &mut Env, rd: usize, imm: u32) {
|
||||
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
|
||||
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
|
||||
fn jal(env: &mut Env, rd: usize, imm: u32) {
|
||||
env.set_register(rd, env.pc);
|
||||
env.pc += imm;
|
||||
env.set_register(rd, env.pc + 4);
|
||||
env.pc = env.pc.wrapping_add(imm);
|
||||
}
|
||||
|
||||
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
|
||||
/// fadd.s fd, fa, fb
|
||||
fn fadd_s(env: &mut Env, fd: usize, fa: usize, fb: usize) {
|
||||
env.set_fregister(fd, env.get_fregister(fa) + env.get_fregister(fb));
|
||||
}
|
||||
|
||||
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();
|
||||
// Ensure all four registers have a value
|
||||
regs.extend([0].repeat(4 - regs.len()));
|
||||
let (rd, ra, rb, _rc) = (regs[0], regs[1], regs[2], regs[3]);
|
||||
let imm = kind.get_imm().unwrap();
|
||||
let (rd, ra, rb) = (regs[0], regs[1], regs[2]);
|
||||
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 funct3 = instruction >> 12 & 0b111;
|
||||
let funct7 = instruction >> 25 & 0b1111111;
|
||||
|
||||
match opcode {
|
||||
0b0110111 => {
|
||||
lui(env, rd, imm)
|
||||
lui(env, rd, imm.unwrap());
|
||||
false
|
||||
}
|
||||
0b0110011 if funct3 == 0b000 && funct7 == 0b0000000 => {
|
||||
add(env, rd, ra, rb);
|
||||
false
|
||||
}
|
||||
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;
|
||||
|
||||
pub fn info(env: &Env, op: &str, args: Vec<String>) -> Vec<String> {
|
||||
match op {
|
||||
"nop" => vec!["Do nothing - wait 1 cycle".to_string()],
|
||||
"li" => vec![format!("load {} into the register {}", args[1], args[0])],
|
||||
/// Display a helpful message about an instruction.
|
||||
///
|
||||
/// Returns the message and, if needed, tags to highlight specific registers ([x regs...], [fregs...]).
|
||||
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" => {
|
||||
let imm = format!("{:032b}", args[1].parse::<i32>().unwrap() as u32)
|
||||
.chars()
|
||||
.rev()
|
||||
.collect::<String>();
|
||||
vec![
|
||||
format!(
|
||||
"load the upper 20 bits of {} into {}",
|
||||
args[1], args[0]
|
||||
),
|
||||
format!("load the upper 20 bits of {} into {}", args[1], args[0]),
|
||||
format!(
|
||||
"{} = {}{}",
|
||||
args[1],
|
||||
imm[12..32].to_string().red(),
|
||||
imm[0..12].to_string()
|
||||
args[1].italic().yellow(),
|
||||
imm[12..32].to_string().green(),
|
||||
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 {
|
||||
use std::{
|
||||
fmt::{self, Display, Formatter},
|
||||
mem,
|
||||
};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use bitfield::bitfield;
|
||||
|
||||
use crate::instructions::{instruction, to_u32};
|
||||
|
||||
use super::{to_bits, to_reg};
|
||||
|
||||
/// will be converted by the engine to a real instruction
|
||||
/// A pseudo instruction is an instruction that
|
||||
/// will be converted by the engine to real instructions
|
||||
#[derive(Debug)]
|
||||
pub struct Pseudo(pub &'static str);
|
||||
|
||||
bitfield! {
|
||||
|
@ -108,6 +103,7 @@ pub mod kind {
|
|||
pub opcode, set_opcode: 6, 0;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Kind {
|
||||
Pseudo(Pseudo),
|
||||
R(R),
|
||||
|
@ -156,21 +152,31 @@ pub mod kind {
|
|||
Kind::Pseudo(_) => None,
|
||||
Kind::R(_) => None,
|
||||
Kind::R4(_) => None,
|
||||
Kind::I(i) => Some(i.imm()),
|
||||
Kind::I2(i2) => Some(i2.imm() >> 20),
|
||||
Kind::I(i) => Some(if i.imm() >> 11 == 1 {
|
||||
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::B(b) => Some(
|
||||
((b.imm_12() as u32) << 12)
|
||||
| ((b.imm_11() as u32) << 11)
|
||||
| (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::J(j) => Some(
|
||||
((j.imm_20() as u32) << 20)
|
||||
| ((j.imm_19_12() as u32) << 12)
|
||||
| ((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) {
|
||||
let opcode = instruction & 0b00000000000000000000000001111111;
|
||||
let funct3 = (instruction & 0b00000000000000000111000000000000) >> 12;
|
||||
let funct7 = (instruction & 0b11111110000000000000000000000000) >> 25;
|
||||
|
||||
match opcode {
|
||||
0b0110111 => (
|
||||
Kind::U(unsafe { mem::transmute_copy(&instruction) }),
|
||||
"lui".into(),
|
||||
),
|
||||
0b0010011 => (
|
||||
Kind::I(unsafe { mem::transmute_copy(&instruction) }),
|
||||
"addi".into(),
|
||||
),
|
||||
_ => todo!(),
|
||||
0b0110111 => (Kind::U(U(instruction)), "lui".into()),
|
||||
0b0010011 => (Kind::I(I(instruction)), "addi".into()),
|
||||
0b0110011 if funct3 == 0b000 && funct7 == 0b0000000 => {
|
||||
(Kind::R(R(instruction)), "add".into())
|
||||
}
|
||||
0b0110011 if funct3 == 0b000 && funct7 == 0b0100000 => {
|
||||
(Kind::R(R(instruction)), "sub".into())
|
||||
}
|
||||
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],
|
||||
),
|
||||
|
||||
// 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),
|
||||
})
|
||||
}
|
||||
|
@ -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_11(to_bits::<1>(imm >> 11)[0]);
|
||||
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::U(mut u) => {
|
||||
|
@ -567,28 +655,32 @@ pub fn handle_pseudo(
|
|||
with(get_instruction("addi"), 0, vec![0, 0]),
|
||||
],
|
||||
"li" => {
|
||||
match imm {
|
||||
// if the immediate is small enough (12 bits), use addi
|
||||
_ if imm >> 12 == 0 => {
|
||||
// if the immediate only has the lower 12 bits set, use addi
|
||||
if imm >> 12 == 0 {
|
||||
// addi rd, x0, imm
|
||||
vec![with(get_instruction("addi"), imm, regs)]
|
||||
}
|
||||
// if the immediate is a multiple of 0x1000, use lui
|
||||
_ if imm & 0xfff == 0 => {
|
||||
else if imm & 0xfff == 0 {
|
||||
// lui rd, imm
|
||||
vec![with(get_instruction("lui"), imm, regs)]
|
||||
}
|
||||
// otherwise, use lui and addi
|
||||
_ => vec![
|
||||
else {
|
||||
vec![
|
||||
// lui rd, imm
|
||||
with(get_instruction("lui"), imm & 0xfffff000, regs.clone()),
|
||||
with(
|
||||
get_instruction("lui"),
|
||||
(imm & 0xfffff000) ^ ((imm >> 11) & 0x1) << 12,
|
||||
regs.clone(),
|
||||
),
|
||||
// addi rd, rd, imm
|
||||
with(
|
||||
get_instruction("addi"),
|
||||
imm & 0x00000fff,
|
||||
vec![regs[0], regs[0]],
|
||||
),
|
||||
],
|
||||
]
|
||||
}
|
||||
}
|
||||
"beqz" => vec![
|
||||
|
@ -617,21 +709,3 @@ const fn to_bits<const N: usize>(val: u32) -> [bool; N] {
|
|||
}
|
||||
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_trait_impl)]
|
||||
#![feature(effects)]
|
||||
#![feature(iterator_try_reduce)]
|
||||
#![feature(try_blocks)]
|
||||
|
||||
pub mod colorizer;
|
||||
// pub mod colorizer;
|
||||
pub mod env;
|
||||
pub mod err;
|
||||
pub mod execution;
|
||||
|
|
377
src/main.rs
377
src/main.rs
|
@ -1,3 +1,5 @@
|
|||
use std::io::Write;
|
||||
|
||||
use codespan_reporting::{
|
||||
diagnostic::{Diagnostic, Label},
|
||||
files::SimpleFile,
|
||||
|
@ -7,20 +9,31 @@ use codespan_reporting::{
|
|||
Config,
|
||||
},
|
||||
};
|
||||
use riscv_interpreter::{
|
||||
env::Env, execution::run_instruction, info::info, instructions::{instruction, kind::Kind}, parser::{parse, Token}
|
||||
use colored::Colorize;
|
||||
use itertools::Itertools;
|
||||
use rizz_v::{
|
||||
env::Env,
|
||||
execution::run_instruction,
|
||||
info::info,
|
||||
parser::{parse, Token},
|
||||
};
|
||||
use termion::input::TermRead;
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let display_mode = 's';
|
||||
let writer = StandardStream::stderr(ColorChoice::Always);
|
||||
let config = Config::default();
|
||||
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 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) {
|
||||
Ok(tokens) => {
|
||||
|
@ -33,7 +46,8 @@ fn main() -> anyhow::Result<()> {
|
|||
let token = token.clone();
|
||||
|
||||
match token.clone() {
|
||||
Token::Op(name, _) => match env.assemble_op((token, loc.clone())) {
|
||||
Token::Mnemonic(..) => {
|
||||
match env.assemble_op((token.clone(), loc.clone())) {
|
||||
Ok(op) => {
|
||||
let mut formatted = format!(
|
||||
"{:<1$} {3:02x}: {2:032b}",
|
||||
|
@ -42,7 +56,8 @@ fn main() -> anyhow::Result<()> {
|
|||
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 {
|
||||
for op in op[1..].iter() {
|
||||
|
@ -53,14 +68,15 @@ fn main() -> anyhow::Result<()> {
|
|||
op,
|
||||
loc.mem_offset
|
||||
);
|
||||
ops.push(Kind::to_op(op.clone()));
|
||||
ops.push(*op);
|
||||
toks.push(token.clone());
|
||||
}
|
||||
}
|
||||
println!("{}", formatted);
|
||||
parse_asm_result += &format!("{}\n", formatted);
|
||||
}
|
||||
Err(err) => {
|
||||
let diagnostic = Diagnostic::error()
|
||||
.with_message("Runtime Error")
|
||||
.with_message("Engine Error")
|
||||
.with_labels(vec![Label::primary(
|
||||
(),
|
||||
err.1.start..(err.1.end + 1),
|
||||
|
@ -78,10 +94,11 @@ fn main() -> anyhow::Result<()> {
|
|||
term::emit(&mut writer.lock(), &config, &file, &diagnostic)
|
||||
.unwrap();
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
Token::Label(name) => {
|
||||
println!(
|
||||
"{:<1$} <{2:02x}>",
|
||||
parse_asm_result += &format!(
|
||||
"{:<1$} <{2:02x}>\n",
|
||||
name.clone() + ":",
|
||||
size + 3,
|
||||
env.get_label(&name).unwrap()
|
||||
|
@ -116,15 +133,341 @@ fn main() -> anyhow::Result<()> {
|
|||
}
|
||||
};
|
||||
|
||||
for op in ops {
|
||||
run_instruction(&mut env, op.0);
|
||||
let mut file = std::fs::File::create("test.bin")?;
|
||||
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!(
|
||||
"{:<1$} <{2:02x}>",
|
||||
op.1,
|
||||
32,
|
||||
env.get_register(10));
|
||||
"{}\n",
|
||||
parse_asm_result
|
||||
.lines()
|
||||
.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(())
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
'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' => {
|
||||
let mut num = c.to_string();
|
||||
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;
|
||||
}
|
||||
if let Some('(') | Some(' ') | None = chars.peek() {
|
||||
Immediate(num.parse().unwrap())
|
||||
dbg!(Immediate(num.parse().unwrap()))
|
||||
} else {
|
||||
let err = Err((
|
||||
SyntaxErr::UnexpectedChar,
|
||||
|
|
98
src/tests.rs
98
src/tests.rs
|
@ -2,11 +2,10 @@
|
|||
/// Test values come from Ripes
|
||||
use crate::{
|
||||
env::Env,
|
||||
instructions::{get_instruction, with},
|
||||
instructions::{get_instruction, handle_pseudo, with},
|
||||
};
|
||||
|
||||
#[test]
|
||||
#[ignore = "TODO"]
|
||||
fn nop() {
|
||||
#[rustfmt::skip]
|
||||
{
|
||||
|
@ -17,21 +16,48 @@ fn nop() {
|
|||
};
|
||||
// nop
|
||||
assert_eq!(
|
||||
u32::from_str_radix(
|
||||
&with(
|
||||
handle_pseudo(
|
||||
get_instruction("nop"),
|
||||
0, // imm
|
||||
vec![]
|
||||
)
|
||||
)[0]
|
||||
.0
|
||||
.to_string(),
|
||||
2
|
||||
)
|
||||
.unwrap(),
|
||||
0b00000000000000000000000000010011u32
|
||||
.to_u32(),
|
||||
0b00000000000000000000000000010011
|
||||
);
|
||||
}
|
||||
|
||||
#[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]
|
||||
fn lui() {
|
||||
let env = Env::new();
|
||||
|
@ -40,23 +66,18 @@ fn lui() {
|
|||
{
|
||||
// U-Type
|
||||
// | imm20 | rd | opcode
|
||||
// 00000000000000000011 01010 0110111
|
||||
// 00000011010100101001 01010 0110111
|
||||
};
|
||||
// lui a0 13609
|
||||
assert_eq!(
|
||||
u32::from_str_radix(
|
||||
&with(
|
||||
with(
|
||||
get_instruction("lui"),
|
||||
13609 << 12,
|
||||
vec![env.str_to_register("a0").unwrap()]
|
||||
)
|
||||
.0
|
||||
.to_string(),
|
||||
2
|
||||
)
|
||||
.unwrap(),
|
||||
0b00000011010100101001010100110111u32
|
||||
.to_u32(),
|
||||
0b00000011010100101001010100110111
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -72,8 +93,7 @@ fn sb() {
|
|||
};
|
||||
// sb t5 -4(sp)
|
||||
assert_eq!(
|
||||
u32::from_str_radix(
|
||||
&with(
|
||||
with(
|
||||
get_instruction("sb"),
|
||||
-4i32 as u32, // imm
|
||||
vec![
|
||||
|
@ -83,11 +103,8 @@ fn sb() {
|
|||
],
|
||||
)
|
||||
.0
|
||||
.to_string(),
|
||||
2
|
||||
)
|
||||
.unwrap(),
|
||||
0b11111111111000010000111000100011u32
|
||||
.to_u32(),
|
||||
0b11111111111000010000111000100011
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -103,8 +120,7 @@ fn add() {
|
|||
};
|
||||
// add a0 a0 a1
|
||||
assert_eq!(
|
||||
u32::from_str_radix(
|
||||
&with(
|
||||
with(
|
||||
get_instruction("add"),
|
||||
0, // imm
|
||||
vec![
|
||||
|
@ -114,11 +130,8 @@ fn add() {
|
|||
]
|
||||
)
|
||||
.0
|
||||
.to_string(),
|
||||
2
|
||||
)
|
||||
.unwrap(),
|
||||
0b00000000101101010000010100110011u32
|
||||
.to_u32(),
|
||||
0b00000000101101010000010100110011
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -131,11 +144,9 @@ fn addi() {
|
|||
// I-Type
|
||||
// | imm12 | ra |f3 | rd | opcode
|
||||
// 000000000001 01010 000 01010 0010011
|
||||
// 000000000001 01010 000 01010 0010011 (Ripes)
|
||||
};
|
||||
// addi a0 a0 1
|
||||
assert_eq!(
|
||||
u32::from_str_radix(
|
||||
with(
|
||||
get_instruction("addi"),
|
||||
1,
|
||||
|
@ -145,12 +156,8 @@ fn addi() {
|
|||
],
|
||||
)
|
||||
.0
|
||||
.to_string()
|
||||
.as_str(),
|
||||
2
|
||||
)
|
||||
.unwrap(),
|
||||
0b00000000000101010000010100010011u32
|
||||
.to_u32(),
|
||||
0b00000000000101010000010100010011
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -163,12 +170,10 @@ fn beq() {
|
|||
// B-Type
|
||||
// | imm7 | rb | ra |f3 |imm5 | opcode
|
||||
// 0000000 01011 01010 000 00100 1100011
|
||||
// 0000000 01011 01010 000 00100 1100011 (Ripes)
|
||||
};
|
||||
// beq a0 a1 4
|
||||
assert_eq!(
|
||||
u32::from_str_radix(
|
||||
&with(
|
||||
with(
|
||||
get_instruction("beq"),
|
||||
4,
|
||||
vec![
|
||||
|
@ -178,10 +183,7 @@ fn beq() {
|
|||
]
|
||||
)
|
||||
.0
|
||||
.to_string(),
|
||||
2
|
||||
)
|
||||
.unwrap(),
|
||||
0b00000000101101010000001001100011u32
|
||||
.to_u32(),
|
||||
0b00000000101101010000001001100011
|
||||
);
|
||||
}
|
||||
|
|
17
test.s
17
test.s
|
@ -1,12 +1,11 @@
|
|||
# li a0 55743235
|
||||
li a0 5
|
||||
li a1 1
|
||||
lui a2 0x3f800000
|
||||
|
||||
# 5!
|
||||
factorial:
|
||||
# beqz a0 end
|
||||
# mul a1 a1 a0
|
||||
# addi a0 a0 -1
|
||||
# j factorial
|
||||
add a2 a0 a1
|
||||
|
||||
end:
|
||||
# nop
|
||||
fcvt.s.w fa0 a0
|
||||
fcvt.s.w fa1 a1
|
||||
|
||||
fadd.s fa2 fa0 fa1
|
||||
fdiv.s fa3 fa2 fa0
|
||||
|
|
Loading…
Reference in a new issue