Make output box modular, fix bug in the expansion of li
This commit is contained in:
parent
6d81417701
commit
3ee54491be
10 changed files with 544 additions and 234 deletions
88
Cargo.lock
generated
88
Cargo.lock
generated
|
@ -14,6 +14,18 @@ version = "0.14.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
|
||||
|
||||
[[package]]
|
||||
name = "codespan-reporting"
|
||||
version = "0.11.1"
|
||||
|
@ -74,6 +86,16 @@ dependencies = [
|
|||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
dependencies = [
|
||||
"winapi 0.2.8",
|
||||
"winapi-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
|
@ -86,6 +108,23 @@ version = "0.2.152"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"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"
|
||||
|
@ -106,6 +145,21 @@ dependencies = [
|
|||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
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 = "riscv_interpreter"
|
||||
version = "0.1.0"
|
||||
|
@ -117,16 +171,18 @@ 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",
|
||||
"winapi 0.2.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -138,12 +194,30 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termion"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "417813675a504dfbbf21bfde32c03e5bf9f2413999962b479023c02848c1c7a5"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"libredox",
|
||||
"numtoa",
|
||||
"redox_termios",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
@ -154,6 +228,12 @@ dependencies = [
|
|||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
|
@ -166,7 +246,7 @@ version = "0.1.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -10,4 +10,5 @@ codespan-reporting = "0.11.1"
|
|||
colored = "2.1.0"
|
||||
itertools = "0.12.0"
|
||||
rayon = "1.8.1"
|
||||
term_size = "0.3.2"
|
||||
term_size = "1.0.0-beta1"
|
||||
termion = "3.0.0"
|
||||
|
|
165
src/env.rs
165
src/env.rs
|
@ -160,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 {
|
||||
|
@ -183,98 +183,107 @@ impl Env {
|
|||
));
|
||||
}
|
||||
|
||||
let _ =
|
||||
i.1.clone()
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.try_for_each(|(k, v)| match v {
|
||||
Arg::Immediate => {
|
||||
if let Token::Immediate(i) = args[k].0 {
|
||||
imm = i as u32;
|
||||
let _ = i
|
||||
.1
|
||||
.clone()
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.try_for_each(|(k, v)| match v {
|
||||
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,
|
||||
))
|
||||
}
|
||||
}
|
||||
Arg::Register(id) => {
|
||||
if let Token::Register(r) = &args[k].0 {
|
||||
regs[id] = self.str_to_register(&r).unwrap();
|
||||
_ => 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();
|
||||
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(),
|
||||
),
|
||||
RuntimeErr::LabelNotFound,
|
||||
args[k].1,
|
||||
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({
|
||||
if let Kind::Pseudo(_) = i.0 {
|
||||
handle_pseudo(i, imm, regs)
|
||||
|
@ -312,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);
|
||||
|
|
15
src/err.rs
15
src/err.rs
|
@ -21,7 +21,7 @@ impl Display for SyntaxErr {
|
|||
match self {
|
||||
SyntaxErr::UnmatchedParen(_) => write!(f, "unmatched parenthesis"),
|
||||
SyntaxErr::UnexpectedChar => write!(f, "unexpected character"),
|
||||
SyntaxErr::OutsideOp(kind) => write!(f, "`{kind}` before opcode"),
|
||||
SyntaxErr::OutsideOp(kind) => write!(f, "'{kind}' before opcode"),
|
||||
SyntaxErr::InvalidRegister => write!(f, "invalid register"),
|
||||
}
|
||||
}
|
||||
|
@ -49,18 +49,20 @@ pub enum RuntimeErr {
|
|||
InvalidOpArity(String, usize, usize),
|
||||
/// actual, expected
|
||||
InvalidType(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::InvalidOpArity(_, actual, expected) => {
|
||||
write!(f, "expected {} args, got {}", expected, actual)
|
||||
}
|
||||
RuntimeErr::InvalidType(actual, expected) => {
|
||||
write!(f, "expected `{}`, got `{}`", expected, actual)
|
||||
write!(f, "expected '{}', got '{}'", expected, actual)
|
||||
}
|
||||
RuntimeErr::LabelNotFound => write!(f, "label not found"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +80,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 +88,12 @@ impl RuntimeErr {
|
|||
.unwrap()
|
||||
.iter()
|
||||
.map(|arg| arg.kind())
|
||||
.join("`, `")
|
||||
.join("', '")
|
||||
),
|
||||
}
|
||||
}
|
||||
RuntimeErr::InvalidType(_, _) => "ensure the operation is valid".to_string(),
|
||||
RuntimeErr::LabelNotFound => "ensure the label is spelled correctly".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,14 @@ 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
|
||||
|
@ -15,41 +20,75 @@ 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)));
|
||||
}
|
||||
|
||||
/// 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);
|
||||
}
|
||||
|
||||
/// 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));
|
||||
env.set_fregister(
|
||||
fd,
|
||||
env.get_fregister(fa) * env.get_fregister(fb) + env.get_fregister(fc),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn run_instruction(env: &mut Env, kind: Kind) {
|
||||
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) = (regs[0], regs[1], regs[2]);
|
||||
let (fd, fa, fb, fc) = (regs[0], regs[1], regs[2], regs[3]);
|
||||
let imm = kind.get_imm().unwrap();
|
||||
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
|
||||
}
|
||||
0b0110011 => {
|
||||
xor(env, rd, ra, rb)
|
||||
0b0110011 if funct3 == 0b100 && funct7 == 0b0000000 => {
|
||||
xor(env, rd, ra, rb);
|
||||
false
|
||||
}
|
||||
0b0110011 if funct3 == 0b000 && funct7 == 0b0000001 => {
|
||||
mul(env, rd, ra, rb);
|
||||
false
|
||||
}
|
||||
0b1100011 => beq(env, ra, rb, imm.unwrap()),
|
||||
0b1101111 => {
|
||||
jal(env, rd, imm)
|
||||
jal(env, rd, imm.unwrap());
|
||||
true
|
||||
}
|
||||
0b1000011 => {
|
||||
fmadd_s(env, fd, fa, fb, fc)
|
||||
fmadd_s(env, fd, fa, fb, fc);
|
||||
false
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
pub mod kind {
|
||||
use std::{
|
||||
fmt::{self, Display, Formatter},
|
||||
mem,
|
||||
};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use bitfield::bitfield;
|
||||
|
||||
|
@ -154,21 +151,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 },
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -194,17 +201,41 @@ 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()),
|
||||
other => {
|
||||
println!("{: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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -565,28 +596,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 => {
|
||||
// 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 => {
|
||||
// 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
|
||||
else if imm & 0xfff == 0 {
|
||||
// lui rd, imm
|
||||
vec![with(get_instruction("lui"), imm, regs)]
|
||||
}
|
||||
// otherwise, use lui and addi
|
||||
else {
|
||||
vec![
|
||||
// lui rd, imm
|
||||
vec![with(get_instruction("lui"), imm, regs)]
|
||||
}
|
||||
// otherwise, use lui and addi
|
||||
_ => vec![
|
||||
// lui rd, imm
|
||||
with(get_instruction("lui"), imm & 0xfffff000, regs.clone()),
|
||||
with(
|
||||
get_instruction("lui"),
|
||||
(imm & 0xFFFF000) | ((imm >> 11) & 0x1) << 12,
|
||||
regs.clone(),
|
||||
),
|
||||
// addi rd, rd, imm
|
||||
with(
|
||||
get_instruction("addi"),
|
||||
imm & 0x00000fff,
|
||||
vec![regs[0], regs[0]],
|
||||
),
|
||||
],
|
||||
]
|
||||
}
|
||||
}
|
||||
"beqz" => vec![
|
||||
|
|
121
src/main.rs
121
src/main.rs
|
@ -7,11 +7,11 @@ use codespan_reporting::{
|
|||
Config,
|
||||
},
|
||||
};
|
||||
use colored::Colorize;
|
||||
use itertools::Itertools;
|
||||
use riscv_interpreter::{
|
||||
env::Env,
|
||||
execution::run_instruction,
|
||||
instructions::kind::Kind,
|
||||
parser::{parse, Token},
|
||||
};
|
||||
|
||||
|
@ -19,12 +19,13 @@ fn main() -> anyhow::Result<()> {
|
|||
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 ops: Vec<u32> = Vec::new();
|
||||
|
||||
match parse(&env, &input) {
|
||||
Ok(tokens) => {
|
||||
|
@ -46,7 +47,7 @@ fn main() -> anyhow::Result<()> {
|
|||
op[0],
|
||||
loc.mem_offset
|
||||
);
|
||||
ops.push(Kind::to_op(op[0].clone()));
|
||||
ops.push(op[0]);
|
||||
|
||||
if op.len() > 1 {
|
||||
for op in op[1..].iter() {
|
||||
|
@ -57,14 +58,14 @@ fn main() -> anyhow::Result<()> {
|
|||
op,
|
||||
loc.mem_offset
|
||||
);
|
||||
ops.push(Kind::to_op(op.clone()));
|
||||
ops.push(*op);
|
||||
}
|
||||
}
|
||||
println!("{}", 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),
|
||||
|
@ -120,11 +121,115 @@ fn main() -> anyhow::Result<()> {
|
|||
}
|
||||
};
|
||||
|
||||
for op in ops {
|
||||
run_instruction(&mut env, op.0);
|
||||
// Print the register values
|
||||
|
||||
println!("{}\n{}", op.1, env.registers.iter().enumerate().map(|(i, r)| format!("x{:<1$} {2:032b}", i.to_string() + ":", 3, r)).join("\n"));
|
||||
while env.pc / 4 < ops.clone().len() as u32 {
|
||||
let pc = env.pc.clone();
|
||||
let prev_regs = env.registers.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);
|
||||
}
|
||||
|
||||
println!(
|
||||
"{}",
|
||||
make_box(
|
||||
term_width as u32,
|
||||
pc as usize,
|
||||
env.registers.clone().into_iter().collect(),
|
||||
changed,
|
||||
's'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
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:
|
||||
/// - b: binary
|
||||
/// - u: unsigned decimal
|
||||
/// - h: hex
|
||||
/// - s: signed decimal
|
||||
/// - f: float
|
||||
fn make_box(
|
||||
width: u32,
|
||||
pc: usize,
|
||||
regs: Vec<u32>,
|
||||
changed: Vec<usize>,
|
||||
display_mode: char,
|
||||
) -> String {
|
||||
let cell_inner_width: u32 = match display_mode {
|
||||
'b' => 32,
|
||||
'u' => 10,
|
||||
'h' => 8,
|
||||
's' => 11,
|
||||
'f' => todo!("float display mode"),
|
||||
_ => unreachable!(),
|
||||
} + 7;
|
||||
|
||||
// Nnumber of boxes that fit horizontally
|
||||
let num_boxes = round_down_to_power_of_two((width / (cell_inner_width + 2)) as u32);
|
||||
let mut boxed = String::new();
|
||||
|
||||
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: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)
|
||||
}
|
||||
'f' => todo!("float display mode"),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let reg = if changed.contains(&i) {
|
||||
reg.bright_green()
|
||||
} else {
|
||||
reg.normal()
|
||||
};
|
||||
formatted += &format!("{} │ ", reg);
|
||||
}
|
||||
|
||||
boxed += &format!("{}\n", formatted);
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
136
src/tests.rs
136
src/tests.rs
|
@ -16,17 +16,13 @@ fn nop() {
|
|||
};
|
||||
// nop
|
||||
assert_eq!(
|
||||
u32::from_str_radix(
|
||||
&handle_pseudo(
|
||||
get_instruction("nop"),
|
||||
0, // imm
|
||||
vec![]
|
||||
)[0]
|
||||
.0
|
||||
.to_string(),
|
||||
2
|
||||
)
|
||||
.unwrap(),
|
||||
handle_pseudo(
|
||||
get_instruction("nop"),
|
||||
0, // imm
|
||||
vec![]
|
||||
)[0]
|
||||
.0
|
||||
.to_u32(),
|
||||
0b00000000000000000000000000010011
|
||||
);
|
||||
}
|
||||
|
@ -42,12 +38,10 @@ fn li() {
|
|||
// U-Type
|
||||
// | imm20 | rd | opcode
|
||||
// 00000000000000001101 01010 0110111
|
||||
// 00000000000000001101 01010 0110111
|
||||
// 2 -> addi
|
||||
// I-Type
|
||||
// | imm12 | ra |f3 | rd | opcode
|
||||
// 000000101001 01010 000 01010 0010011
|
||||
// 000000101001 01010 000 01010 0010011
|
||||
};
|
||||
// li a0 53289
|
||||
assert!(handle_pseudo(
|
||||
|
@ -56,7 +50,7 @@ fn li() {
|
|||
vec![env.str_to_register("a0").unwrap()]
|
||||
)
|
||||
.into_iter()
|
||||
.map(|i| u32::from_str_radix(dbg!(&i.0.to_string()), 2).unwrap())
|
||||
.map(|i| i.0.to_u32())
|
||||
.eq([
|
||||
0b00000000000000001101010100110111,
|
||||
0b00000010100101010000010100010011
|
||||
|
@ -72,22 +66,19 @@ fn lui() {
|
|||
{
|
||||
// U-Type
|
||||
// | imm20 | rd | opcode
|
||||
// 00000000000000000011 01010 0110111
|
||||
// 00000011010100101001 01010 0110111
|
||||
// 11111111111101111011 01010 0110111
|
||||
// 00001111111101111011 01010 0110111
|
||||
};
|
||||
// lui a0 13609
|
||||
assert_eq!(
|
||||
u32::from_str_radix(
|
||||
&with(
|
||||
get_instruction("lui"),
|
||||
13609 << 12,
|
||||
vec![env.str_to_register("a0").unwrap()]
|
||||
)
|
||||
.0
|
||||
.to_string(),
|
||||
2
|
||||
with(
|
||||
get_instruction("lui"),
|
||||
13609 << 12,
|
||||
vec![env.str_to_register("a0").unwrap()]
|
||||
)
|
||||
.unwrap(),
|
||||
.0
|
||||
.to_u32(),
|
||||
0b00000011010100101001010100110111
|
||||
);
|
||||
}
|
||||
|
@ -104,21 +95,17 @@ fn sb() {
|
|||
};
|
||||
// sb t5 -4(sp)
|
||||
assert_eq!(
|
||||
u32::from_str_radix(
|
||||
&with(
|
||||
get_instruction("sb"),
|
||||
-4i32 as u32, // imm
|
||||
vec![
|
||||
0, // rd
|
||||
env.str_to_register("sp").unwrap(), // ra
|
||||
env.str_to_register("t5").unwrap() // rb
|
||||
],
|
||||
)
|
||||
.0
|
||||
.to_string(),
|
||||
2
|
||||
with(
|
||||
get_instruction("sb"),
|
||||
-4i32 as u32, // imm
|
||||
vec![
|
||||
0, // rd
|
||||
env.str_to_register("sp").unwrap(), // ra
|
||||
env.str_to_register("t5").unwrap() // rb
|
||||
],
|
||||
)
|
||||
.unwrap(),
|
||||
.0
|
||||
.to_u32(),
|
||||
0b11111111111000010000111000100011
|
||||
);
|
||||
}
|
||||
|
@ -135,21 +122,17 @@ fn add() {
|
|||
};
|
||||
// add a0 a0 a1
|
||||
assert_eq!(
|
||||
u32::from_str_radix(
|
||||
&with(
|
||||
get_instruction("add"),
|
||||
0, // imm
|
||||
vec![
|
||||
env.str_to_register("a0").unwrap(), // rd
|
||||
env.str_to_register("a0").unwrap(), // ra
|
||||
env.str_to_register("a1").unwrap() // rb
|
||||
]
|
||||
)
|
||||
.0
|
||||
.to_string(),
|
||||
2
|
||||
with(
|
||||
get_instruction("add"),
|
||||
0, // imm
|
||||
vec![
|
||||
env.str_to_register("a0").unwrap(), // rd
|
||||
env.str_to_register("a0").unwrap(), // ra
|
||||
env.str_to_register("a1").unwrap() // rb
|
||||
]
|
||||
)
|
||||
.unwrap(),
|
||||
.0
|
||||
.to_u32(),
|
||||
0b00000000101101010000010100110011
|
||||
);
|
||||
}
|
||||
|
@ -167,21 +150,16 @@ fn addi() {
|
|||
};
|
||||
// addi a0 a0 1
|
||||
assert_eq!(
|
||||
u32::from_str_radix(
|
||||
with(
|
||||
get_instruction("addi"),
|
||||
1,
|
||||
vec![
|
||||
env.str_to_register("a0").unwrap(),
|
||||
env.str_to_register("a0").unwrap()
|
||||
],
|
||||
)
|
||||
.0
|
||||
.to_string()
|
||||
.as_str(),
|
||||
2
|
||||
with(
|
||||
get_instruction("addi"),
|
||||
1,
|
||||
vec![
|
||||
env.str_to_register("a0").unwrap(),
|
||||
env.str_to_register("a0").unwrap()
|
||||
],
|
||||
)
|
||||
.unwrap(),
|
||||
.0
|
||||
.to_u32(),
|
||||
0b00000000000101010000010100010011
|
||||
);
|
||||
}
|
||||
|
@ -200,21 +178,17 @@ fn beq() {
|
|||
};
|
||||
// beq a0 a1 4
|
||||
assert_eq!(
|
||||
u32::from_str_radix(
|
||||
&with(
|
||||
get_instruction("beq"),
|
||||
4,
|
||||
vec![
|
||||
0, // no rd
|
||||
env.str_to_register("a0").unwrap(),
|
||||
env.str_to_register("a1").unwrap()
|
||||
]
|
||||
)
|
||||
.0
|
||||
.to_string(),
|
||||
2
|
||||
with(
|
||||
get_instruction("beq"),
|
||||
4,
|
||||
vec![
|
||||
0, // no rd
|
||||
env.str_to_register("a0").unwrap(),
|
||||
env.str_to_register("a1").unwrap()
|
||||
]
|
||||
)
|
||||
.unwrap(),
|
||||
.0
|
||||
.to_u32(),
|
||||
0b00000000101101010000001001100011
|
||||
);
|
||||
}
|
||||
|
|
13
test.s
13
test.s
|
@ -1,12 +1 @@
|
|||
# li a0 55743235
|
||||
li a1 1
|
||||
|
||||
# 5!
|
||||
factorial:
|
||||
# beqz a0 end
|
||||
# mul a1 a1 a0
|
||||
# addi a0 a0 -1
|
||||
# j factorial
|
||||
|
||||
end:
|
||||
# nop
|
||||
li a0 -543643
|
||||
|
|
Loading…
Reference in a new issue