Full encoding supported, add tests, start encoding the parsed code
This commit is contained in:
parent
4509218b49
commit
f0b5be8c63
8 changed files with 342 additions and 173 deletions
95
src/env.rs
95
src/env.rs
|
@ -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!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
11
src/err.rs
11
src/err.rs
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -2,3 +2,4 @@ pub mod env;
|
|||
pub mod err;
|
||||
pub mod instructions;
|
||||
pub mod parser;
|
||||
pub mod tests;
|
||||
|
|
93
src/main.rs
93
src/main.rs
|
@ -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(())
|
||||
}
|
||||
|
|
|
@ -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
159
src/tests.rs
Normal 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
5
test.s
|
@ -1 +1,4 @@
|
|||
x0 li 8(x0)
|
||||
a:
|
||||
addi a0 zero 1
|
||||
addi a1 zero 2
|
||||
add a2 a1 a0
|
||||
|
|
Loading…
Reference in a new issue