Full encoding supported, add tests, start encoding the parsed code

This commit is contained in:
Lumi Kalt 2024-01-22 00:12:59 +00:00
parent 4509218b49
commit f0b5be8c63
8 changed files with 342 additions and 173 deletions

View file

@ -1,13 +1,33 @@
use std::collections::HashMap;
use std::{collections::HashMap, env::Args};
use crate::{err::RuntimeErr, parser::{Loc, Token}};
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
use crate::{
err::RuntimeErr,
instructions::{instruction, with, Arg},
parser::{Loc, Token},
};
pub enum SymbolValue {
Byte(u8),
Half(u16),
Word(u32),
DWord(u64),
String(String),
}
pub enum Value {
Immediate(i64),
Register(u32),
Symbol(String, SymbolValue),
}
#[derive(Debug)]
pub struct Env {
pub register_alias: HashMap<String, u32>,
labels: HashMap<String, u32>,
registers: [i64; 32],
pub stack: Vec<i64>, // TODO: Find the size of the stack
registers: [u64; 32],
pub stack: Vec<u64>, // TODO: Find the size of the stack
pub instructions: Vec<u32>,
}
@ -24,6 +44,7 @@ impl Env {
("t1", 6),
("t2", 7),
("s0", 8),
("fp", 8),
("s1", 9),
("a0", 10),
("a1", 11),
@ -56,16 +77,16 @@ impl Env {
register_alias,
labels: HashMap::new(),
registers: [0; 32],
stack: Vec::new(),
stack: Vec::from([0; 1024]),
instructions: Vec::new(),
}
}
pub fn set_register(&mut self, reg: u32, value: i64) {
pub fn set_register(&mut self, reg: u32, value: u64) {
self.registers[reg as usize] = value;
}
pub fn get_register(&self, reg: u32) -> i64 {
pub fn get_register(&self, reg: u32) -> u64 {
self.registers[reg as usize]
}
@ -84,6 +105,13 @@ impl Env {
None
}
}
pub fn reg_to_register(&self, reg: &str) -> Option<u32> {
if reg.starts_with("x") {
self.xn_to_register(reg)
} else {
self.alias_to_register(reg)
}
}
pub fn is_valid_register(&self, reg: &str) -> bool {
self.alias_to_register(reg)
.or_else(|| self.xn_to_register(reg))
@ -98,12 +126,53 @@ impl Env {
self.labels.get(label).copied()
}
pub fn to_instruction(&self, tokens: Vec<(Token, Loc)>) -> Result<u32, RuntimeErr> {
let (op, args) = match &tokens[0].0 {
Token::Op(op, args) => (op, args),
_ => unreachable!(),
};
pub fn assemble_op(&mut self, op: (Token, Loc)) -> Result<u32, RuntimeErr> {
if let (Token::Op(name, args), loc) = op {
let i = instruction(&name);
let mut imm = 0u32;
let mut regs = vec![0; 4];
if args.len() != i.1.len() {
return Err(RuntimeErr::InvalidOpArity(
name,
args.len(),
i.1.len(),
));
}
todo!()
let _ = i.1.into_par_iter()
.enumerate()
.try_for_each(|(k, v)| match v {
Arg::Immediate => {
if let Token::Immediate(i) = args[k].0 {
imm = i as u32;
Ok(())
} else {
Err(RuntimeErr::InvalidType("Immediate".to_string(), v.kind()))
}
}
Arg::Register => {
if let Token::Register(r) = args[k].0 {
regs[k] = self.reg_to_register(&r).unwrap();
Ok(())
} else {
Err(RuntimeErr::InvalidType("Register".to_string(), v.kind()))
}
}
Arg::Memory => {
if let Token::Memory(i, r) = args[k].0 {
if r.is_some() {
regs[k] = self.reg_to_register(&r.unwrap()).unwrap();
}
Ok(())
} else {
Err(RuntimeErr::InvalidType("Memory".to_string(), v.kind()))
}
}
_ => unimplemented!()
})?;
Ok(u32::from_str_radix(&with(i, imm, regs).0.to_string(), 2).unwrap())
} else {
unreachable!()
}
}
}

View file

@ -30,7 +30,10 @@ impl SyntaxErr {
SyntaxErr::UnmatchedParen(true) => "add '(' before the register name".to_string(),
SyntaxErr::UnexpectedChar => "ensure the input is well-formed".to_string(),
SyntaxErr::OutsideOp(_) => format!("add arguments after the opcode"),
SyntaxErr::MemoryInvalidRegister => "registers are either xN (N < 32 with no leading 0) or the standard aliases".to_string(),
SyntaxErr::MemoryInvalidRegister => {
"registers are either xN (N < 32 with no leading 0) or the standard aliases"
.to_string()
}
}
}
}
@ -42,6 +45,7 @@ pub enum RuntimeErr {
UnexpectedRegister,
InvalidOp(String),
InvalidOpArity(String, usize, usize),
InvalidType(String, String),
}
impl Display for RuntimeErr {
@ -51,11 +55,14 @@ impl Display for RuntimeErr {
RuntimeErr::UnexpectedImmediate => write!(f, "unexpected immediate"),
RuntimeErr::UnexpectedRegister => write!(f, "unexpected register"),
RuntimeErr::InvalidOp(op) => write!(f, "invalid operation {}", op),
RuntimeErr::InvalidOpArity(op, expected, actual) => write!(
RuntimeErr::InvalidOpArity(op, actual, expected) => write!(
f,
"invalid operation arity {} expected {} got {}",
op, expected, actual
),
RuntimeErr::InvalidType(actual, expected) => {
write!(f, "expected {}, got {}", expected, actual)
}
}
}
}

View file

@ -222,36 +222,56 @@ pub mod kind {
}
}
pub enum Value {
pub enum Arg {
Register,
Immediate,
Memory,
Symbol,
}
impl Arg {
pub fn kind(&self) -> String {
match self {
Arg::Register => "register",
Arg::Immediate => "immediate",
Arg::Memory => "memory",
Arg::Symbol => "symbol",
}
.to_string()
}
}
use kind::*;
/// (kind, (arity, Vec<token kind>))
pub fn instruction(op: &str) -> (Kind, Vec<Value>) {
pub fn instruction(op: &str) -> (Kind, Vec<Arg>) {
match op {
// -
"nop" => (Kind::Pseudo(Pseudo {}), vec![]),
// Move
"li" => (
Kind::Pseudo(Pseudo {}),
vec![Value::Register, Value::Immediate],
),
"li" => (Kind::Pseudo(Pseudo {}), vec![Arg::Register, Arg::Immediate]),
"lui" => (
Kind::U(U {
imm: to_bits(0),
rd: to_bits(0),
opcode: to_bits(0b0110111),
}),
vec![Value::Register, Value::Immediate],
vec![Arg::Register, Arg::Immediate],
),
// Memory
"sb" => (
Kind::S(S {
imm: to_bits(0),
rb: to_bits(0),
ra: to_bits(0),
funct3: to_bits(0b000),
imm2: to_bits(0),
opcode: to_bits(0b0100011),
}),
vec![Arg::Register, Arg::Memory],
),
// Arithmetic, Logic, Shift
"add" => (
@ -263,7 +283,7 @@ pub fn instruction(op: &str) -> (Kind, Vec<Value>) {
rd: to_bits(0),
opcode: to_bits(0b0110011),
}),
vec![Value::Register, Value::Register, Value::Register],
vec![Arg::Register, Arg::Register, Arg::Register],
),
"addi" => (
Kind::I(I {
@ -273,14 +293,30 @@ pub fn instruction(op: &str) -> (Kind, Vec<Value>) {
rd: to_bits(0),
opcode: to_bits(0b0010011),
}),
vec![Value::Register, Value::Register, Value::Immediate],
vec![Arg::Register, Arg::Register, Arg::Immediate],
),
// Multiply, Divide
// Compare
// Flow control (branch, jump, call, ret)
"beq" => (
Kind::B(B {
imm: to_bits(0),
rb: to_bits(0),
ra: to_bits(0),
funct3: to_bits(0b000),
imm2: to_bits(0),
opcode: to_bits(0b1100011),
}),
vec![Arg::Register, Arg::Register, Arg::Immediate],
),
_ => unimplemented!(),
}
}
/// Order: rd, ra, rb, rc
pub fn with_reg_args((kind, args): (Kind, Vec<Value>), regs: Vec<u32>) -> (Kind, Vec<Value>) {
/// regs order: rd, ra, rb, rc
pub fn with((kind, args): (Kind, Vec<Arg>), imm: u32, regs: Vec<u32>) -> (Kind, Vec<Arg>) {
match kind {
Kind::Pseudo(_) => (kind, args),
Kind::R(r) => (
@ -308,7 +344,7 @@ pub fn with_reg_args((kind, args): (Kind, Vec<Value>), regs: Vec<u32>) -> (Kind,
),
Kind::I(i) => (
Kind::I(I {
imm: i.imm,
imm: to_bits(imm),
ra: to_bits(regs[1]),
funct3: i.funct3,
rd: to_bits(regs[0]),
@ -319,7 +355,7 @@ pub fn with_reg_args((kind, args): (Kind, Vec<Value>), regs: Vec<u32>) -> (Kind,
Kind::I2(i2) => (
Kind::I2(I2 {
funct6: i2.funct6,
imm: i2.imm,
imm: to_bits(imm),
ra: to_bits(regs[1]),
funct3: i2.funct3,
rd: to_bits(regs[0]),
@ -327,88 +363,21 @@ pub fn with_reg_args((kind, args): (Kind, Vec<Value>), regs: Vec<u32>) -> (Kind,
}),
args,
),
Kind::S(s) => (
Kind::S(S {
imm: s.imm,
rb: to_bits(regs[2]),
ra: to_bits(regs[1]),
funct3: s.funct3,
imm2: s.imm2,
opcode: s.opcode,
}),
args,
),
Kind::B(b) => (
Kind::B(B {
imm: b.imm,
rb: to_bits(regs[2]),
ra: to_bits(regs[1]),
funct3: b.funct3,
imm2: b.imm2,
opcode: b.opcode,
}),
args,
),
Kind::U(u) => (
Kind::U(U {
imm: u.imm,
rd: to_bits(regs[0]),
opcode: u.opcode,
}),
args,
),
Kind::J(j) => (
Kind::J(J {
imm: j.imm,
rd: to_bits(regs[0]),
opcode: j.opcode,
}),
args,
),
}
}
pub fn with_imm((kind, args): (Kind, Vec<Value>), imm: u32) -> (Kind, Vec<Value>) {
match kind {
Kind::Pseudo(_) => (kind, args),
Kind::R(r) => (Kind::R(r), args),
Kind::R4(r4) => (Kind::R4(r4), args),
Kind::I(i) => (
Kind::I(I {
imm: to_bits(imm),
ra: i.ra,
funct3: i.funct3,
rd: i.rd,
opcode: i.opcode,
}),
args,
),
Kind::I2(i2) => (
Kind::I2(I2 {
funct6: i2.funct6,
imm: to_bits(imm),
ra: i2.ra,
funct3: i2.funct3,
rd: i2.rd,
opcode: i2.opcode,
}),
args,
),
Kind::S(s) => {
let bits = to_bits::<32>(imm);
(
Kind::S(S {
imm: {
let mut imm = [false; 7];
imm.copy_from_slice(&bits[11..=5]);
imm.copy_from_slice(&bits[5..=11]); //.into_iter().rev().map(|&b| b).collect::<Vec<_>>()[..]);
imm
},
rb: s.rb,
ra: s.ra,
rb: to_bits(regs[2]),
ra: to_bits(regs[1]),
funct3: s.funct3,
imm2: {
let mut imm2 = [false; 5];
imm2.copy_from_slice(&bits[4..=0]);
imm2.copy_from_slice(&bits[0..=4]); //.into_iter().rev().map(|&b| b).collect::<Vec<_>>()[..]);
imm2
},
opcode: s.opcode,
@ -423,15 +392,15 @@ pub fn with_imm((kind, args): (Kind, Vec<Value>), imm: u32) -> (Kind, Vec<Value>
imm: {
let mut imm = [false; 7];
imm[6] = bits[12];
imm[5..=0].copy_from_slice(&bits[10..=5]);
imm[0..=5].copy_from_slice(&bits[5..=10]);
imm
},
rb: b.rb,
ra: b.ra,
rb: to_bits(regs[2]),
ra: to_bits(regs[1]),
funct3: b.funct3,
imm2: {
let mut imm2 = [false; 5];
imm2[4..=1].copy_from_slice(&bits[4..=1]);
imm2[1..=4].copy_from_slice(&bits[1..=4]);
imm2[0] = bits[11];
imm2
},
@ -448,7 +417,7 @@ pub fn with_imm((kind, args): (Kind, Vec<Value>), imm: u32) -> (Kind, Vec<Value>
imm.copy_from_slice(&bits[31..=12]);
imm
},
rd: u.rd,
rd: to_bits(regs[0]),
opcode: u.opcode,
}),
args,
@ -464,7 +433,7 @@ pub fn with_imm((kind, args): (Kind, Vec<Value>), imm: u32) -> (Kind, Vec<Value>
imm[7..=0].copy_from_slice(&bits[19..=12]);
imm
},
rd: j.rd,
rd: to_bits(regs[0]),
opcode: j.opcode,
}),
args,

View file

@ -2,3 +2,4 @@ pub mod env;
pub mod err;
pub mod instructions;
pub mod parser;
pub mod tests;

View file

@ -9,7 +9,7 @@ use codespan_reporting::{
};
use riscv_interpreter::{
env::Env,
instructions::{instruction, with_imm, with_reg_args},
instructions::{instruction, with},
parser::parse,
};
@ -22,74 +22,35 @@ fn main() -> anyhow::Result<()> {
let env = Env::new();
// match parse(&env, &input) {
// Ok(tokens) => {
// println!("{:#?} -> {:#?}", input, tokens);
// }
// Err(errs) => {
// for err in errs {
// let start = err.1.start;
// let end = err.1.end + 1;
match parse(&env, &input) {
Ok(tokens) => {
println!("{:#?} -> {:#?}", input, tokens);
}
Err(errs) => {
for err in errs {
let start = err.1.start;
let end = err.1.end + 1;
// let diagnostic = Diagnostic::error()
// .with_message("Syntax Error")
// .with_labels(vec![
// Label::primary((), start..end).with_message(err.0.to_string())
// ])
// .with_notes({
// let mut notes = Vec::new();
// if let Some(note) = err.3 {
// notes.push(note);
// }
// notes.push(err.0.note());
// notes
// });
let diagnostic = Diagnostic::error()
.with_message("Syntax Error")
.with_labels(vec![
Label::primary((), start..end).with_message(err.0.to_string())
])
.with_notes({
let mut notes = Vec::new();
if let Some(note) = err.3 {
notes.push(note);
}
notes.push(err.0.note());
notes
});
// term::emit(&mut writer.lock(), &config, &file, &diagnostic).unwrap();
// }
// }
// };
term::emit(&mut writer.lock(), &config, &file, &diagnostic).unwrap();
}
return Ok(());
}
};
println!("nop: {}", instruction("nop").0);
println!(
"add a0 a0 a1: {}",
with_reg_args(
instruction("add"),
vec![
env.alias_to_register("a0").unwrap() as u32,
env.alias_to_register("a0").unwrap() as u32,
env.alias_to_register("a1").unwrap() as u32
]
)
.0 // 011001101010000001010010110000000
// Ripes: 011001101010000001010010110000000
);
println!(
"addi a0 a0 1: {}",
with_imm(
with_reg_args(
instruction("addi"),
vec![
env.alias_to_register("a0").unwrap(),
env.alias_to_register("a0").unwrap()
]
),
1
)
.0 // 00000000000101010000010100010011
// Ripes: 00000000000101010000010100010011
);
println!(
"lui a0 1: {}",
with_imm(
with_reg_args(
instruction("lui"),
vec![env.alias_to_register("a0").unwrap()]
),
1
)
.0
);
Ok(())
}

View file

@ -10,7 +10,7 @@ pub enum Token {
/// \# blablabla,
Comment,
/// 1, 2, -1
Immediate(i64),
Immediate(u32),
/// zero, r1, pc
///
/// Technically also label references and symbols, but we'll handle those later

159
src/tests.rs Normal file
View file

@ -0,0 +1,159 @@
#[cfg(test)]
/// Test values come from Ripes
use crate::{
env::Env,
instructions::{instruction, with},
};
#[test]
#[ignore = "TODO"]
fn nop() {
#[rustfmt::skip]
{
// nop (pseudo) -> addi x0, x0, 0
// I-Type
// | imm12 | ra |f3 | rd | opcode
// 000000000000 00000 000 00000 0010011
};
// nop
assert_eq!(
u32::from_str_radix(
&with(
instruction("nop"),
0, // imm
vec![]
)
.0
.to_string(),
2
)
.unwrap(),
0b00000000000000000000000000010011u32
);
}
#[test]
fn sb() {
let env = Env::new();
#[rustfmt::skip]
{
// S-Type
// | imm | rb | ra |f3 | rd | opcode
// 1111111 11110 00010 000 11100 0100011
};
// sb t5 -4(sp)
assert_eq!(
u32::from_str_radix(
&with(
instruction("sb"),
-4i32 as u32, // imm
vec![
0, // rd
env.alias_to_register("sp").unwrap(), // ra
env.alias_to_register("t5").unwrap() // rb
],
)
.0
.to_string(),
2
)
.unwrap(),
0b11111111111000010000111000100011u32
);
}
#[test]
fn add() {
let env = Env::new();
#[rustfmt::skip]
{
// R-Type
// | f7 | rb | ra |f3 | rd | opcode
// 0000000 01011 01010 000 01010 0110011
};
// add a0 a0 a1
assert_eq!(
u32::from_str_radix(
&with(
instruction("add"),
0, // imm
vec![
env.alias_to_register("a0").unwrap(), // rd
env.alias_to_register("a0").unwrap(), // ra
env.alias_to_register("a1").unwrap() // rb
]
)
.0
.to_string(),
2
)
.unwrap(),
0b00000000101101010000010100110011u32
);
}
#[test]
fn addi() {
let env = Env::new();
#[rustfmt::skip]
{
// I-Type
// | imm12 | ra |f3 | rd | opcode
// 000000000001 01010 000 01010 0010011
// 000000000001 01010 000 01010 0010011 (Ripes)
};
// addi a0 a0 1
assert_eq!(
u32::from_str_radix(
with(
instruction("addi"),
1,
vec![
env.alias_to_register("a0").unwrap(),
env.alias_to_register("a0").unwrap()
],
)
.0
.to_string()
.as_str(),
2
)
.unwrap(),
0b00000000000101010000010100010011u32
);
}
#[test]
fn beq() {
let env = Env::new();
#[rustfmt::skip]
{
// B-Type
// | imm7 | rb | ra |f3 |imm5 | opcode
// 0000000 01011 01010 000 00100 1100011
// 0000000 01011 01010 000 00100 1100011 (Ripes)
};
// beq a0 a1 4
assert_eq!(
u32::from_str_radix(
&with(
instruction("beq"),
4,
vec![
0, // no rd
env.alias_to_register("a0").unwrap(),
env.alias_to_register("a1").unwrap()
]
)
.0
.to_string(),
2
)
.unwrap(),
0b00000000101101010000001001100011u32
);
}

5
test.s
View file

@ -1 +1,4 @@
x0 li 8(x0)
a:
addi a0 zero 1
addi a1 zero 2
add a2 a1 a0