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 crate::{err::RuntimeErr, parser::{Loc, Token}};
#[derive(Debug)]
pub struct Env {
pub register_alias: HashMap<String, usize>,
labels: HashMap<String, usize>,
registers: [i64; 32],
pub stack: Vec<i64>, // TODO: Find the size of the stack
pub instructions: Vec<u32>,
}
impl Env {
@ -54,6 +57,7 @@ impl Env {
labels: HashMap::new(),
registers: [0; 32],
stack: Vec::new(),
instructions: Vec::new(),
}
}
@ -81,7 +85,9 @@ impl Env {
}
}
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) {
@ -91,4 +97,13 @@ impl Env {
pub fn get_label(&self, label: &str) -> Option<usize> {
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(true) => "add '(' before the register name".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(),
}
}

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 err;
pub mod instructions;
pub mod parser;

View file

@ -7,7 +7,11 @@ use codespan_reporting::{
Config,
},
};
use riscv_interpreter::{env::Env, parser::parse};
use riscv_interpreter::{
env::Env,
instructions::{instruction, with_reg_args},
parser::parse,
};
fn main() -> anyhow::Result<()> {
let writer = StandardStream::stderr(ColorChoice::Always);
@ -18,33 +22,47 @@ 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();
// }
// }
// };
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(())
}