Start being able to encode instructions
This commit is contained in:
parent
5939a1c89b
commit
746d33b0b9
5 changed files with 438 additions and 28 deletions
17
src/env.rs
17
src/env.rs
|
@ -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!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
376
src/instructions.rs
Normal 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
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
pub mod env;
|
||||
pub mod err;
|
||||
pub mod instructions;
|
||||
pub mod parser;
|
||||
|
|
70
src/main.rs
70
src/main.rs
|
@ -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(())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue