Compare commits

...

10 commits

Author SHA1 Message Date
Lumi Kalt
837f611955 Gave up on the idea of colored script visualizations for now 2024-07-27 19:33:31 +01:00
Lumi Kalt
7e7cd5d7b6 Don't commit the produced 'binary' 2024-07-27 19:32:34 +01:00
Lumi Kalt
1913df1f3d Enable nightly feature 2024-05-01 14:51:51 +01:00
Lumi Kalt
386a3b7403 Show the FP reg table and use the new info format 2024-05-01 13:15:29 +01:00
Lumi Kalt
ac07031631 FP instruction implementations 2024-05-01 13:15:03 +01:00
Lumi Kalt
29a7dfa277 Prepare for handling the .data section 2024-05-01 13:14:00 +01:00
Lumi Kalt
fc429dedbf Update deps 2024-04-27 10:25:48 +01:00
Lumi Kalt
98c8e3d4eb There's one more bug with the imm of U-Types, trying to find it 2024-01-26 01:45:36 +00:00
Lumi Kalt
3ee54491be Make output box modular, fix bug in the expansion of li 2024-01-26 01:41:50 +00:00
Lumi Kalt
6d81417701 Fix mem_offset being off by 4, streamlined some helpers, more op impls 2024-01-24 15:02:04 +00:00
14 changed files with 1368 additions and 418 deletions

2
.gitignore vendored
View file

@ -1 +1,3 @@
/target /target
test.bin

221
Cargo.lock generated
View file

@ -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"

View file

@ -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"

View file

@ -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(),
}
}

View file

@ -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 {

View file

@ -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(),
} }
} }
} }

View file

@ -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),
} }
} }

View file

@ -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)
} }

View file

@ -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
}

View file

@ -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;

View file

@ -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 &regs.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 &regs.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
}

View file

@ -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,

View file

@ -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
View file

@ -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