Start being able to encode instructions

This commit is contained in:
Lumi Kalt 2024-01-21 16:31:36 +00:00
parent 5939a1c89b
commit 746d33b0b9
5 changed files with 438 additions and 28 deletions

View file

@ -1,11 +1,14 @@
use std::collections::HashMap; use std::collections::HashMap;
use crate::{err::RuntimeErr, parser::{Loc, Token}};
#[derive(Debug)] #[derive(Debug)]
pub struct Env { pub struct Env {
pub register_alias: HashMap<String, usize>, pub register_alias: HashMap<String, usize>,
labels: HashMap<String, usize>, labels: HashMap<String, usize>,
registers: [i64; 32], registers: [i64; 32],
pub stack: Vec<i64>, // TODO: Find the size of the stack pub stack: Vec<i64>, // TODO: Find the size of the stack
pub instructions: Vec<u32>,
} }
impl Env { impl Env {
@ -54,6 +57,7 @@ impl Env {
labels: HashMap::new(), labels: HashMap::new(),
registers: [0; 32], registers: [0; 32],
stack: Vec::new(), stack: Vec::new(),
instructions: Vec::new(),
} }
} }
@ -81,7 +85,9 @@ impl Env {
} }
} }
pub fn is_valid_register(&self, reg: &str) -> bool { pub fn is_valid_register(&self, reg: &str) -> bool {
self.alias_to_register(reg).or_else(|| self.xn_to_register(reg)).is_some() self.alias_to_register(reg)
.or_else(|| self.xn_to_register(reg))
.is_some()
} }
pub fn add_label(&mut self, label: &str, value: usize) { pub fn add_label(&mut self, label: &str, value: usize) {
@ -91,4 +97,13 @@ impl Env {
pub fn get_label(&self, label: &str) -> Option<usize> { pub fn get_label(&self, label: &str) -> Option<usize> {
self.labels.get(label).copied() 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!(),
};
todo!()
}
} }

View file

@ -29,7 +29,7 @@ impl SyntaxErr {
SyntaxErr::UnmatchedParen(false) => "add ')' after the register name".to_string(), SyntaxErr::UnmatchedParen(false) => "add ')' after the register name".to_string(),
SyntaxErr::UnmatchedParen(true) => "add '(' before 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(kind) => format!("add '{}'s only after an opcode", kind), 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(),
} }
} }

376
src/instructions.rs Normal file
View file

@ -0,0 +1,376 @@
pub mod kind {
use std::fmt::{self, Display, Formatter};
use crate::instructions::to_u32;
/// will be converted by the engine to a real instruction
pub struct Pseudo {}
pub struct R {
pub funct7: [bool; 7],
pub rb: [bool; 5],
pub ra: [bool; 5],
pub funct3: [bool; 3],
pub rd: [bool; 5],
pub opcode: [bool; 7],
}
pub struct R4 {
pub rc: [bool; 5],
pub funct2: [bool; 2],
pub rb: [bool; 5],
pub ra: [bool; 5],
pub funct3: [bool; 3],
pub rd: [bool; 5],
pub opcode: [bool; 7],
}
pub struct I {
pub imm: [bool; 12], // 11:0
pub ra: [bool; 5],
pub funct3: [bool; 3],
pub rd: [bool; 5],
pub opcode: [bool; 7],
}
pub struct I2 {
pub funct6: [bool; 6],
pub imm: [bool; 6], // 5:0
pub ra: [bool; 5],
pub funct3: [bool; 3],
pub rd: [bool; 5],
pub opcode: [bool; 7],
}
pub struct S {
pub imm: [bool; 7], // 11:5
pub rb: [bool; 5],
pub ra: [bool; 5],
pub funct3: [bool; 3],
pub imm2: [bool; 5], // 4:0
pub opcode: [bool; 7],
}
pub struct B {
pub imm: [bool; 7], // 12 | 10:5
pub rb: [bool; 5],
pub ra: [bool; 5],
pub funct3: [bool; 3],
pub imm2: [bool; 5], // 4:1 | 11
pub opcode: [bool; 7],
}
pub struct U {
pub imm: [bool; 20], // 31:12
pub rd: [bool; 5],
pub opcode: [bool; 7],
}
pub struct J {
pub imm: [bool; 20], // 20 | 10:1 | 11 | 19:12
pub rd: [bool; 5],
pub opcode: [bool; 7],
}
pub enum Kind {
Pseudo(Pseudo),
R(R),
R4(R4),
I(I),
I2(I2),
S(S),
B(B),
U(U),
J(J),
}
impl Display for Kind {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Kind::Pseudo(pseudo) => write!(f, "{}", pseudo),
Kind::R(r) => write!(f, "{}", r),
Kind::R4(r4) => write!(f, "{}", r4),
Kind::I(i) => write!(f, "{}", i),
Kind::I2(i2) => write!(f, "{}", i2),
Kind::S(s) => write!(f, "{}", s),
Kind::B(b) => write!(f, "{}", b),
Kind::U(u) => write!(f, "{}", u),
Kind::J(j) => write!(f, "{}", j),
}
}
}
impl Display for Pseudo {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
// (pseudo) padded on either side with - to make it 32 characters
write!(f, "{:-^32}", "(pseudo)")
}
}
impl Display for R {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"{:07b}{:05b}{:05b}{:03b}{:05b}{:07b}",
to_u32(&self.opcode),
to_u32(&self.rd),
to_u32(&self.funct3),
to_u32(&self.ra),
to_u32(&self.rb),
to_u32(&self.funct7),
)
}
}
impl Display for R4 {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"{:07b}{:05b}{:05b}{:03b}{:05b}{:02b}{:05b}{:07b}",
to_u32(&self.opcode),
to_u32(&self.rd),
to_u32(&self.funct3),
to_u32(&self.ra),
to_u32(&self.rb),
to_u32(&self.funct2),
to_u32(&self.rc),
to_u32(&[false; 7]),
)
}
}
impl Display for I {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"{:07b}{:05b}{:03b}{:05b}{:012b}",
to_u32(&self.opcode),
to_u32(&self.rd),
to_u32(&self.funct3),
to_u32(&self.ra),
to_u32(&self.imm),
)
}
}
impl Display for I2 {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"{:07b}{:05b}{:03b}{:05b}{:05b}{:06b}",
to_u32(&self.opcode),
to_u32(&self.rd),
to_u32(&self.funct3),
to_u32(&self.ra),
to_u32(&self.imm),
to_u32(&self.funct6),
)
}
}
impl Display for S {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"{:07b}{:05b}{:03b}{:05b}{:07b}{:05b}",
to_u32(&self.opcode),
to_u32(&self.imm2),
to_u32(&self.funct3),
to_u32(&self.ra),
to_u32(&self.rb),
to_u32(&self.imm),
)
}
}
impl Display for B {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"{:07b}{:05b}{:03b}{:05b}{:07b}{:05b}",
to_u32(&self.opcode),
to_u32(&self.imm2),
to_u32(&self.funct3),
to_u32(&self.ra),
to_u32(&self.rb),
to_u32(&self.imm),
)
}
}
impl Display for U {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"{:07b}{:05b}{:020b}",
to_u32(&self.opcode),
to_u32(&self.rd),
to_u32(&self.imm),
)
}
}
impl Display for J {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"{:07b}{:05b}{:020b}",
to_u32(&self.opcode),
to_u32(&self.rd),
to_u32(&self.imm),
)
}
}
}
pub enum Value {
Register,
Immediate,
Memory,
Symbol,
}
use kind::*;
/// (kind, (arity, Vec<token kind>))
pub fn instruction(op: &str) -> (Kind, Vec<Value>) {
match op {
// -
"nop" => (Kind::Pseudo(Pseudo {}), vec![]),
// Move
"li" => (
Kind::Pseudo(Pseudo {}),
vec![Value::Register, Value::Immediate],
),
// Memory
// Arithmetic, Logic, Shift
"add" => (
Kind::R(R {
funct7: to_bits(0b0000000),
rb: to_bits(0),
ra: to_bits(0),
funct3: to_bits(0b000),
rd: to_bits(0),
opcode: to_bits(0b0110011),
}),
vec![Value::Register, Value::Register, Value::Register],
),
"addi" => (
Kind::I(I {
imm: to_bits(0),
ra: to_bits(0),
funct3: to_bits(0b000),
rd: to_bits(0),
opcode: to_bits(0b0010011),
}),
vec![Value::Register, Value::Register, Value::Immediate],
),
_ => unimplemented!(),
}
}
/// Order: rd, ra, rb, rc
pub fn with_reg_args((kind, args): (Kind, Vec<Value>), regs: Vec<u32>) -> (Kind, Vec<Value>) {
let arity = args.len();
// The engine will have already checked that the arity is correct
debug_assert!(arity == regs.len());
match kind {
Kind::Pseudo(_) => (kind, args),
Kind::R(r) => (
Kind::R(R {
funct7: r.funct7,
rb: to_bits(regs[2]),
ra: to_bits(regs[1]),
funct3: r.funct3,
rd: to_bits(regs[0]),
opcode: r.opcode,
}),
args,
),
Kind::R4(r4) => (
Kind::R4(R4 {
rc: to_bits(regs[3]),
funct2: r4.funct2,
rb: to_bits(regs[2]),
ra: to_bits(regs[1]),
funct3: r4.funct3,
rd: to_bits(regs[0]),
opcode: r4.opcode,
}),
args,
),
Kind::I(i) => (
Kind::I(I {
imm: i.imm,
ra: to_bits(regs[1]),
funct3: i.funct3,
rd: to_bits(regs[0]),
opcode: i.opcode,
}),
args,
),
Kind::I2(i2) => (
Kind::I2(I2 {
funct6: i2.funct6,
imm: i2.imm,
ra: to_bits(regs[1]),
funct3: i2.funct3,
rd: to_bits(regs[0]),
opcode: i2.opcode,
}),
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,
),
}
}
fn to_bits<const N: usize>(val: u32) -> [bool; N] {
let mut bits = [false; N];
for i in 0..N {
bits[i] = (val >> i) & 1 == 1;
}
bits
}
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
}

View file

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

View file

@ -7,7 +7,11 @@ use codespan_reporting::{
Config, Config,
}, },
}; };
use riscv_interpreter::{env::Env, parser::parse}; use riscv_interpreter::{
env::Env,
instructions::{instruction, with_reg_args},
parser::parse,
};
fn main() -> anyhow::Result<()> { fn main() -> anyhow::Result<()> {
let writer = StandardStream::stderr(ColorChoice::Always); let writer = StandardStream::stderr(ColorChoice::Always);
@ -18,33 +22,47 @@ fn main() -> anyhow::Result<()> {
let env = Env::new(); let env = Env::new();
match parse(&env, &input) { // match parse(&env, &input) {
Ok(tokens) => { // Ok(tokens) => {
println!("{:#?} -> {:#?}", input, tokens); // println!("{:#?} -> {:#?}", input, tokens);
} // }
Err(errs) => { // Err(errs) => {
for err in errs { // for err in errs {
let start = err.1.start; // let start = err.1.start;
let end = err.1.end + 1; // let end = err.1.end + 1;
let diagnostic = Diagnostic::error() // let diagnostic = Diagnostic::error()
.with_message("Syntax Error") // .with_message("Syntax Error")
.with_labels(vec![ // .with_labels(vec![
Label::primary((), start..end).with_message(err.0.to_string()) // Label::primary((), start..end).with_message(err.0.to_string())
]) // ])
.with_notes({ // .with_notes({
let mut notes = Vec::new(); // let mut notes = Vec::new();
if let Some(note) = err.3 { // if let Some(note) = err.3 {
notes.push(note); // notes.push(note);
} // }
notes.push(err.0.note()); // notes.push(err.0.note());
notes // notes
}); // });
term::emit(&mut writer.lock(), &config, &file, &diagnostic).unwrap(); // term::emit(&mut writer.lock(), &config, &file, &diagnostic).unwrap();
} // }
} // }
}; // };
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
);
Ok(()) Ok(())
} }