Helper instruction functions, begin allowing the execution of instructions, start writing info statements for operations

This commit is contained in:
Lumi Kalt 2024-01-23 23:58:27 +00:00
parent 385278d8e9
commit e410fe0069
9 changed files with 282 additions and 39 deletions

83
Cargo.lock generated
View file

@ -18,6 +18,16 @@ dependencies = [
"unicode-width", "unicode-width",
] ]
[[package]]
name = "colored"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
dependencies = [
"lazy_static",
"windows-sys",
]
[[package]] [[package]]
name = "crossbeam-deque" name = "crossbeam-deque"
version = "0.8.5" version = "0.8.5"
@ -58,6 +68,12 @@ dependencies = [
"either", "either",
] ]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "rayon" name = "rayon"
version = "1.8.1" version = "1.8.1"
@ -84,6 +100,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"codespan-reporting", "codespan-reporting",
"colored",
"itertools", "itertools",
"rayon", "rayon",
] ]
@ -133,3 +150,69 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"

View file

@ -6,5 +6,6 @@ edition = "2021"
[dependencies] [dependencies]
anyhow = "1.0.79" anyhow = "1.0.79"
codespan-reporting = "0.11.1" codespan-reporting = "0.11.1"
colored = "2.1.0"
itertools = "0.12.0" itertools = "0.12.0"
rayon = "1.8.1" rayon = "1.8.1"

View file

@ -16,7 +16,7 @@ pub enum Variables {
#[derive(Debug)] #[derive(Debug)]
pub struct Env { pub struct Env {
register_alias: HashMap<String, u32>, register_alias: HashMap<String, usize>,
labels: HashMap<String, u32>, labels: HashMap<String, u32>,
registers: [u32; 32], registers: [u32; 32],
/// EQ, LT, GT /// EQ, LT, GT
@ -79,19 +79,20 @@ impl Env {
} }
} }
pub fn set_register(&mut self, reg: u32, value: u32) { pub fn set_register(&mut self, reg: usize, value: u32) {
self.registers[reg as usize] = value; if reg == 0 {
return;
} }
self.registers[reg] = value;
pub fn get_register(&self, reg: u32) -> u32 {
self.registers[reg as usize]
} }
pub fn get_register(&self, reg: usize) -> u32 {
pub fn str_to_register(&self, reg: &str) -> Option<u32> { self.registers[reg]
}
pub fn str_to_register(&self, reg: &str) -> Option<usize> {
if reg == "x0" { if reg == "x0" {
Some(0) Some(0)
} else if reg.starts_with("x") && !reg[1..].starts_with("0") { } else if reg.starts_with("x") && !reg[1..].starts_with("0") {
match reg[1..].parse::<u32>() { match reg[1..].parse::<usize>() {
Ok(n) if n < 32 => Some(n), Ok(n) if n < 32 => Some(n),
_ => None, _ => None,
} }
@ -103,7 +104,6 @@ impl Env {
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);
} }
pub fn get_label(&self, label: &str) -> Option<u32> { pub fn get_label(&self, label: &str) -> Option<u32> {
self.labels.get(label).copied() self.labels.get(label).copied()
} }
@ -273,7 +273,10 @@ impl Env {
} }
/// Assume memory offsets have been handled /// Assume memory offsets have been handled
pub fn exec_op(&mut self, (op, loc): (Token, Loc)) -> Result<(), (RuntimeErr, Loc, Option<String>)> { pub fn exec_op(
&mut self,
(op, loc): (Token, Loc),
) -> Result<(), (RuntimeErr, Loc, Option<String>)> {
let (i, args) = if let Token::Op(name, args) = op { let (i, args) = if let Token::Op(name, args) = op {
if let Some(i) = instruction(&name) { if let Some(i) = instruction(&name) {
(i, args.clone()) (i, args.clone())

View file

@ -0,0 +1,38 @@
use crate::{env::Env, instructions::kind::Kind};
/// lui rd, imm
fn lui(env: &mut Env, rd: usize, imm: u32) {
env.set_register(rd, imm);
}
/// jal rd, imm
fn jal(env: &mut Env, rd: usize, imm: u32) {
env.set_register(rd, env.pc);
env.pc += imm;
}
const fn to_u32<const N: usize>(bits: &[bool; N]) -> u32 {
let mut val = 0;
for i in 0..N {
if bits[i] {
val |= 1 << i;
}
}
val
}
pub fn run_instruction(env: &mut Env, kind: Kind) {
let mut regs = kind.get_regs().unwrap();
// Ensure all four registers have a value
regs.extend([0].repeat(4 - regs.len()));
let (rd, ra, rb, _rc) = (regs[0], regs[1], regs[2], regs[3]);
let imm = kind.get_imm().unwrap();
let opcode = kind.get_opcode().unwrap();
match to_u32(opcode) {
0b0110111 => {
lui(env, rd, imm)
}
_ => todo!(),
}
}

30
src/info.rs Normal file
View file

@ -0,0 +1,30 @@
use colored::Colorize;
use crate::env::Env;
pub fn info(env: &Env, op: &str, args: Vec<String>) -> Vec<String> {
match op {
"nop" => vec!["Do nothing - wait 1 cycle".to_string()],
"li" => vec![format!("load {} into the register {}", args[1], args[0])],
"lui" => {
let imm = format!("{:032b}", args[1].parse::<i32>().unwrap() as u32)
.chars()
.rev()
.collect::<String>();
vec![
format!(
"load the upper 20 bits of {} into the register {}",
args[1], args[0]
),
format!(
"{} = {}{}",
args[1],
imm[12..32].to_string().red(),
imm[0..12].to_string()
),
format!("{:>1$} = {2}{3:0>12}", args[0], args[1].to_string().len(), imm[12..32].to_string(), "0".to_string().bold()),
]
}
_ => todo!(),
}
}

View file

@ -3,6 +3,8 @@ pub mod kind {
use crate::instructions::to_u32; use crate::instructions::to_u32;
use super::to_reg;
/// will be converted by the engine to a real instruction /// will be converted by the engine to a real instruction
pub struct Pseudo(pub &'static str); pub struct Pseudo(pub &'static str);
@ -108,6 +110,74 @@ pub mod kind {
} }
} }
impl Kind {
pub fn get_opcode(&self) -> Option<&[bool; 7]> {
match self {
Kind::Pseudo(_) => None,
Kind::R(r) => Some(&r.opcode),
Kind::R4(r4) => Some(&r4.opcode),
Kind::I(i) => Some(&i.opcode),
Kind::I2(i2) => Some(&i2.opcode),
Kind::S(s) => Some(&s.opcode),
Kind::B(b) => Some(&b.opcode),
Kind::U(u) => Some(&u.opcode),
Kind::J(j) => Some(&j.opcode),
}
}
pub fn get_imm(&self) -> Option<u32> {
match self {
Kind::Pseudo(_) => None,
Kind::R(_) => None,
Kind::R4(_) => None,
Kind::I(i) => Some(to_u32(&i.imm)),
Kind::I2(i2) => Some(to_u32(&i2.imm)),
Kind::S(s) => {
let mut imm = [false; 12];
imm[0..=4].copy_from_slice(&s.imm2);
imm[5..=11].copy_from_slice(&s.imm);
Some(to_u32(&imm))
}
Kind::B(b) => {
let mut imm = [false; 13];
imm[1..=4].copy_from_slice(&b.imm2[1..=4]);
imm[5..=10].copy_from_slice(&b.imm[0..=5]);
imm[11] = b.imm2[0];
imm[12] = b.imm[6];
Some(to_u32(&imm))
}
Kind::U(u) => Some(to_u32(&u.imm) << 12),
Kind::J(j) => {
let mut imm = [false; 21];
imm[1..=10].copy_from_slice(&j.imm[9..=18]);
imm[11] = j.imm[8];
imm[12..=19].copy_from_slice(&j.imm[0..=7]);
imm[20] = j.imm[19];
Some(to_u32(&imm))
}
}
}
pub fn get_regs(&self) -> Option<Vec<usize>> {
match self {
Kind::Pseudo(_) => None,
Kind::R(r) => Some(vec![to_reg(&r.rd), to_reg(&r.ra), to_reg(&r.rb)]),
Kind::R4(r4) => Some(vec![
to_reg(&r4.rd),
to_reg(&r4.ra),
to_reg(&r4.rb),
to_reg(&r4.rc),
]),
Kind::I(i) => Some(vec![to_reg(&i.rd), to_reg(&i.ra)]),
Kind::I2(i2) => Some(vec![to_reg(&i2.rd), to_reg(&i2.ra)]),
Kind::S(s) => Some(vec![0, to_reg(&s.ra), to_reg(&s.rb)]),
Kind::B(b) => Some(vec![0, to_reg(&b.ra), to_reg(&b.rb)]),
Kind::U(u) => Some(vec![to_reg(&u.rd)]),
Kind::J(j) => Some(vec![to_reg(&j.rd)]),
}
}
}
impl Display for Pseudo { impl Display for Pseudo {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{:0^32}", 0) write!(f, "{:0^32}", 0)
@ -391,28 +461,28 @@ pub fn get_instruction(op: &str) -> (Kind, Vec<Arg>) {
} }
/// regs order: rd, ra, rb, rc /// regs order: rd, ra, rb, rc
pub fn with((kind, args): (Kind, Vec<Arg>), imm: u32, regs: Vec<u32>) -> (Kind, Vec<Arg>) { pub fn with((kind, args): (Kind, Vec<Arg>), imm: u32, regs: Vec<usize>) -> (Kind, Vec<Arg>) {
match kind { match kind {
Kind::Pseudo(_) => (kind, args), Kind::Pseudo(_) => (kind, args),
Kind::R(r) => ( Kind::R(r) => (
Kind::R(R { Kind::R(R {
funct7: r.funct7, funct7: r.funct7,
rb: to_bits(regs[2]), rb: reg_bits(regs[2]),
ra: to_bits(regs[1]), ra: reg_bits(regs[1]),
funct3: r.funct3, funct3: r.funct3,
rd: to_bits(regs[0]), rd: reg_bits(regs[0]),
opcode: r.opcode, opcode: r.opcode,
}), }),
args, args,
), ),
Kind::R4(r4) => ( Kind::R4(r4) => (
Kind::R4(R4 { Kind::R4(R4 {
rc: to_bits(regs[3]), rc: reg_bits(regs[3]),
funct2: r4.funct2, funct2: r4.funct2,
rb: to_bits(regs[2]), rb: reg_bits(regs[2]),
ra: to_bits(regs[1]), ra: reg_bits(regs[1]),
funct3: r4.funct3, funct3: r4.funct3,
rd: to_bits(regs[0]), rd: reg_bits(regs[0]),
opcode: r4.opcode, opcode: r4.opcode,
}), }),
args, args,
@ -420,9 +490,9 @@ pub fn with((kind, args): (Kind, Vec<Arg>), imm: u32, regs: Vec<u32>) -> (Kind,
Kind::I(i) => ( Kind::I(i) => (
Kind::I(I { Kind::I(I {
imm: to_bits(imm), imm: to_bits(imm),
ra: to_bits(regs[1]), ra: reg_bits(regs[1]),
funct3: i.funct3, funct3: i.funct3,
rd: to_bits(regs[0]), rd: reg_bits(regs[0]),
opcode: i.opcode, opcode: i.opcode,
}), }),
args, args,
@ -431,9 +501,9 @@ pub fn with((kind, args): (Kind, Vec<Arg>), imm: u32, regs: Vec<u32>) -> (Kind,
Kind::I2(I2 { Kind::I2(I2 {
funct6: i2.funct6, funct6: i2.funct6,
imm: to_bits(imm), imm: to_bits(imm),
ra: to_bits(regs[1]), ra: reg_bits(regs[1]),
funct3: i2.funct3, funct3: i2.funct3,
rd: to_bits(regs[0]), rd: reg_bits(regs[0]),
opcode: i2.opcode, opcode: i2.opcode,
}), }),
args, args,
@ -447,8 +517,8 @@ pub fn with((kind, args): (Kind, Vec<Arg>), imm: u32, regs: Vec<u32>) -> (Kind,
imm.copy_from_slice(&bits[5..=11]); imm.copy_from_slice(&bits[5..=11]);
imm imm
}, },
rb: to_bits(regs[2]), rb: reg_bits(regs[2]),
ra: to_bits(regs[1]), ra: reg_bits(regs[1]),
funct3: s.funct3, funct3: s.funct3,
imm2: { imm2: {
let mut imm2 = [false; 5]; let mut imm2 = [false; 5];
@ -470,8 +540,8 @@ pub fn with((kind, args): (Kind, Vec<Arg>), imm: u32, regs: Vec<u32>) -> (Kind,
imm[0..=5].copy_from_slice(&bits[5..=10]); imm[0..=5].copy_from_slice(&bits[5..=10]);
imm imm
}, },
rb: to_bits(regs[2]), rb: reg_bits(regs[2]),
ra: to_bits(regs[1]), ra: reg_bits(regs[1]),
funct3: b.funct3, funct3: b.funct3,
imm2: { imm2: {
let mut imm2 = [false; 5]; let mut imm2 = [false; 5];
@ -487,7 +557,7 @@ pub fn with((kind, args): (Kind, Vec<Arg>), imm: u32, regs: Vec<u32>) -> (Kind,
Kind::U(u) => ( Kind::U(u) => (
Kind::U(U { Kind::U(U {
imm: to_bits(imm >> 12), // 31:12 imm: to_bits(imm >> 12), // 31:12
rd: to_bits(regs[0]), rd: reg_bits(regs[0]),
opcode: u.opcode, opcode: u.opcode,
}), }),
args, args,
@ -503,7 +573,7 @@ pub fn with((kind, args): (Kind, Vec<Arg>), imm: u32, regs: Vec<u32>) -> (Kind,
imm[0..=7].copy_from_slice(&bits[12..=19]); imm[0..=7].copy_from_slice(&bits[12..=19]);
imm imm
}, },
rd: to_bits(regs[0]), rd: reg_bits(regs[0]),
opcode: j.opcode, opcode: j.opcode,
}), }),
args, args,
@ -515,7 +585,7 @@ pub fn with((kind, args): (Kind, Vec<Arg>), imm: u32, regs: Vec<u32>) -> (Kind,
pub fn handle_pseudo( pub fn handle_pseudo(
(kind, args): (Kind, Vec<Arg>), (kind, args): (Kind, Vec<Arg>),
imm: u32, imm: u32,
regs: Vec<u32>, regs: Vec<usize>,
) -> Vec<(Kind, Vec<Arg>)> { ) -> Vec<(Kind, Vec<Arg>)> {
let op = if let Kind::Pseudo(Pseudo(op)) = kind { let op = if let Kind::Pseudo(Pseudo(op)) = kind {
op op
@ -532,16 +602,24 @@ pub fn handle_pseudo(
match imm { match imm {
// if the immediate is small enough (12 bits), use addi // if the immediate is small enough (12 bits), use addi
_ if imm >> 12 == 0 => { _ if imm >> 12 == 0 => {
// 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
_ if imm & 0xfff == 0 => { _ if imm & 0xfff == 0 => {
// lui rd, imm
vec![with(get_instruction("lui"), imm, regs)] vec![with(get_instruction("lui"), imm, regs)]
} }
// otherwise, use lui and addi // otherwise, use lui and addi
_ => vec![ _ => vec![
// lui rd, imm
with(get_instruction("lui"), imm & 0xfffff000, regs.clone()), with(get_instruction("lui"), imm & 0xfffff000, regs.clone()),
with(get_instruction("addi"), imm & 0x00000fff, regs), // addi rd, rd, imm
with(
get_instruction("addi"),
imm & 0x00000fff,
vec![regs[0], regs[0]],
),
], ],
} }
} }
@ -572,6 +650,10 @@ 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 { const fn to_u32<const N: usize>(bits: &[bool; N]) -> u32 {
let mut val = 0; let mut val = 0;
for i in 0..N { for i in 0..N {
@ -581,3 +663,7 @@ const fn to_u32<const N: usize>(bits: &[bool; N]) -> u32 {
} }
val val
} }
const fn to_reg<const N: usize>(bits: &[bool; N]) -> usize {
to_u32(bits) as usize
}

View file

@ -6,6 +6,7 @@
pub mod env; pub mod env;
pub mod err; pub mod err;
pub mod execution; pub mod execution;
pub mod info;
pub mod instructions; pub mod instructions;
pub mod parser; pub mod parser;
pub mod tests; pub mod tests;

View file

@ -8,8 +8,7 @@ use codespan_reporting::{
}, },
}; };
use riscv_interpreter::{ use riscv_interpreter::{
env::Env, env::Env, info::info, parser::{parse, Token}
parser::{parse, Token},
}; };
fn main() -> anyhow::Result<()> { fn main() -> anyhow::Result<()> {
@ -105,5 +104,7 @@ fn main() -> anyhow::Result<()> {
} }
}; };
println!("{}", info(&env, "lui", vec!["a0".to_string(), "573498".to_string()]).join("\n"));
Ok(()) Ok(())
} }

12
test.s
View file

@ -1,12 +1,12 @@
li a0 55743235 # li a0 55743235
li a1 1 li a1 1
# 5! # 5!
factorial: factorial:
beqz a0 end # beqz a0 end
mul a1 a1 a0 # mul a1 a1 a0
addi a0 a0 -1 # addi a0 a0 -1
j factorial # j factorial
end: end:
nop # nop