Fix mem_offset being off by 4, streamlined some helpers, more op impls
This commit is contained in:
parent
96202c0d1a
commit
6d81417701
7 changed files with 131 additions and 56 deletions
58
src/env.rs
58
src/env.rs
|
@ -18,7 +18,8 @@ pub enum Variables {
|
||||||
pub struct Env {
|
pub struct Env {
|
||||||
register_alias: HashMap<String, usize>,
|
register_alias: HashMap<String, usize>,
|
||||||
labels: HashMap<String, u32>,
|
labels: HashMap<String, u32>,
|
||||||
registers: [u32; 32],
|
pub registers: [u32; 32],
|
||||||
|
pub fregisters: [f32; 32],
|
||||||
pub prev_stacks: Vec<Vec<u32>>,
|
pub prev_stacks: Vec<Vec<u32>>,
|
||||||
pub stack: Vec<u32>, // TODO: Find the actual size of the stack
|
pub stack: Vec<u32>, // TODO: Find the actual size of the stack
|
||||||
pub instructions: Vec<u32>,
|
pub instructions: Vec<u32>,
|
||||||
|
@ -29,6 +30,7 @@ impl Env {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
// alias -> xN
|
// alias -> xN
|
||||||
let register_alias = [
|
let register_alias = [
|
||||||
|
// Integer regs
|
||||||
("zero", 0),
|
("zero", 0),
|
||||||
("ra", 1),
|
("ra", 1),
|
||||||
("sp", 2),
|
("sp", 2),
|
||||||
|
@ -62,6 +64,39 @@ impl Env {
|
||||||
("t4", 29),
|
("t4", 29),
|
||||||
("t5", 30),
|
("t5", 30),
|
||||||
("t6", 31),
|
("t6", 31),
|
||||||
|
// Floating point regs
|
||||||
|
("ft0", 0),
|
||||||
|
("ft1", 1),
|
||||||
|
("ft2", 2),
|
||||||
|
("ft3", 3),
|
||||||
|
("ft4", 4),
|
||||||
|
("ft5", 5),
|
||||||
|
("ft6", 6),
|
||||||
|
("ft7", 7),
|
||||||
|
("fs0", 8),
|
||||||
|
("fs1", 9),
|
||||||
|
("fa0", 10),
|
||||||
|
("fa1", 11),
|
||||||
|
("fa2", 12),
|
||||||
|
("fa3", 13),
|
||||||
|
("fa4", 14),
|
||||||
|
("fa5", 15),
|
||||||
|
("fa6", 16),
|
||||||
|
("fa7", 17),
|
||||||
|
("fs2", 18),
|
||||||
|
("fs3", 19),
|
||||||
|
("fs4", 20),
|
||||||
|
("fs5", 21),
|
||||||
|
("fs6", 22),
|
||||||
|
("fs7", 23),
|
||||||
|
("fs8", 24),
|
||||||
|
("fs9", 25),
|
||||||
|
("fs10", 26),
|
||||||
|
("fs11", 27),
|
||||||
|
("ft8", 28),
|
||||||
|
("ft9", 29),
|
||||||
|
("ft10", 30),
|
||||||
|
("ft11", 31),
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(k, v)| (k.to_string(), v.to_owned()))
|
.map(|(k, v)| (k.to_string(), v.to_owned()))
|
||||||
|
@ -71,6 +106,7 @@ impl Env {
|
||||||
register_alias,
|
register_alias,
|
||||||
labels: HashMap::new(),
|
labels: HashMap::new(),
|
||||||
registers: [0; 32],
|
registers: [0; 32],
|
||||||
|
fregisters: [0.0; 32],
|
||||||
prev_stacks: Vec::new(),
|
prev_stacks: Vec::new(),
|
||||||
stack: Vec::from([0; 1024]), // 1024 * 64 = 64 KiB stack
|
stack: Vec::from([0; 1024]), // 1024 * 64 = 64 KiB stack
|
||||||
instructions: Vec::new(),
|
instructions: Vec::new(),
|
||||||
|
@ -99,6 +135,22 @@ impl Env {
|
||||||
self.register_alias.get(reg).copied()
|
self.register_alias.get(reg).copied()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn set_fregister(&mut self, reg: usize, value: f32) {
|
||||||
|
self.fregisters[reg] = value;
|
||||||
|
}
|
||||||
|
pub fn get_fregister(&self, reg: usize) -> f32 {
|
||||||
|
self.fregisters[reg]
|
||||||
|
}
|
||||||
|
pub fn str_to_fregister(&self, reg: &str) -> Option<usize> {
|
||||||
|
if reg.starts_with("f") && !reg[1..].starts_with("0") {
|
||||||
|
match reg[1..].parse::<usize>() {
|
||||||
|
Ok(n) if n < 32 => Some(n),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.register_alias.get(reg).copied()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_label(&mut self, label: &str, value: u32) {
|
pub fn add_label(&mut self, label: &str, value: u32) {
|
||||||
self.labels.insert(label.to_string(), value);
|
self.labels.insert(label.to_string(), value);
|
||||||
|
@ -250,7 +302,7 @@ impl Env {
|
||||||
Token::Op(name, _) => {
|
Token::Op(name, _) => {
|
||||||
if let Some((kind, args)) = instruction(&name) {
|
if let Some((kind, args)) = instruction(&name) {
|
||||||
if let Kind::Pseudo(_) = kind {
|
if let Kind::Pseudo(_) = kind {
|
||||||
tokens[id].1.mem_offset = i + 4;
|
tokens[id].1.mem_offset = i;
|
||||||
handle_pseudo((kind, args), 0, vec![0; 4])
|
handle_pseudo((kind, args), 0, vec![0; 4])
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|_| i += 4);
|
.for_each(|_| i += 4);
|
||||||
|
@ -276,7 +328,7 @@ impl Env {
|
||||||
&mut self,
|
&mut self,
|
||||||
(op, loc): (Token, Loc),
|
(op, loc): (Token, Loc),
|
||||||
) -> Result<(), (RuntimeErr, Loc, Option<String>)> {
|
) -> Result<(), (RuntimeErr, Loc, Option<String>)> {
|
||||||
let (i, args) = if let Token::Op(name, args) = op {
|
let (_i, _args) = if let Token::Op(name, args) = op {
|
||||||
if let Some(i) = instruction(&name) {
|
if let Some(i) = instruction(&name) {
|
||||||
(i, args.clone())
|
(i, args.clone())
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -10,27 +10,28 @@ fn addi(env: &mut Env, rd: usize, ra: usize, imm: u32) {
|
||||||
env.set_register(rd, env.get_register(ra) + imm);
|
env.set_register(rd, env.get_register(ra) + imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// xor rd, ra, rb
|
||||||
|
fn xor(env: &mut Env, rd: usize, ra: usize, rb: usize) {
|
||||||
|
env.set_register(rd, env.get_register(ra) ^ env.get_register(rb));
|
||||||
|
}
|
||||||
|
|
||||||
/// jal rd, imm
|
/// jal rd, imm
|
||||||
fn jal(env: &mut Env, rd: usize, imm: u32) {
|
fn jal(env: &mut Env, rd: usize, imm: u32) {
|
||||||
env.set_register(rd, env.pc);
|
env.set_register(rd, env.pc);
|
||||||
env.pc += imm;
|
env.pc += imm;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn to_u32<const N: usize>(bits: &[bool; N]) -> u32 {
|
/// fmadd.s fd, fa, fb, fc
|
||||||
let mut val = 0;
|
fn fmadd_s(env: &mut Env, fd: usize, fa: usize, fb: usize, fc: usize) {
|
||||||
for i in 0..N {
|
env.set_fregister(fd, env.get_fregister(fa) * env.get_fregister(fb) + env.get_fregister(fc));
|
||||||
if bits[i] {
|
|
||||||
val |= 1 << i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_instruction(env: &mut Env, kind: Kind) {
|
pub fn run_instruction(env: &mut Env, kind: Kind) {
|
||||||
let mut regs = kind.get_regs().unwrap();
|
let mut regs = kind.get_regs().unwrap();
|
||||||
// Ensure all four registers have a value
|
// Ensure all four registers have a value
|
||||||
regs.extend([0].repeat(4 - regs.len()));
|
regs.extend([0].repeat(4 - regs.len()));
|
||||||
let (rd, ra, rb, _rc) = (regs[0], regs[1], regs[2], regs[3]);
|
let (rd, ra, rb) = (regs[0], regs[1], regs[2]);
|
||||||
|
let (fd, fa, fb, fc) = (regs[0], regs[1], regs[2], regs[3]);
|
||||||
let imm = kind.get_imm().unwrap();
|
let imm = kind.get_imm().unwrap();
|
||||||
let opcode = kind.get_opcode().unwrap();
|
let opcode = kind.get_opcode().unwrap();
|
||||||
|
|
||||||
|
@ -41,6 +42,15 @@ pub fn run_instruction(env: &mut Env, kind: Kind) {
|
||||||
0b0010011 => {
|
0b0010011 => {
|
||||||
addi(env, rd, ra, imm)
|
addi(env, rd, ra, imm)
|
||||||
}
|
}
|
||||||
|
0b0110011 => {
|
||||||
|
xor(env, rd, ra, rb)
|
||||||
|
}
|
||||||
|
0b1101111 => {
|
||||||
|
jal(env, rd, imm)
|
||||||
|
}
|
||||||
|
0b1000011 => {
|
||||||
|
fmadd_s(env, fd, fa, fb, fc)
|
||||||
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use colored::Colorize;
|
||||||
|
|
||||||
use crate::env::Env;
|
use crate::env::Env;
|
||||||
|
|
||||||
pub fn info(env: &Env, op: &str, args: Vec<String>) -> Vec<String> {
|
pub fn info(_env: &Env, op: &str, args: Vec<String>) -> Vec<String> {
|
||||||
match op {
|
match op {
|
||||||
"nop" => vec!["Do nothing - wait 1 cycle".to_string()],
|
"nop" => vec!["Do nothing - wait 1 cycle".to_string()],
|
||||||
"li" => vec![format!("load {} into the register {}", args[1], args[0])],
|
"li" => vec![format!("load {} into the register {}", args[1], args[0])],
|
||||||
|
|
|
@ -6,11 +6,8 @@ pub mod kind {
|
||||||
|
|
||||||
use bitfield::bitfield;
|
use bitfield::bitfield;
|
||||||
|
|
||||||
use crate::instructions::{instruction, to_u32};
|
/// will be converted by the engine to real instructions
|
||||||
|
#[derive(Debug)]
|
||||||
use super::{to_bits, to_reg};
|
|
||||||
|
|
||||||
/// will be converted by the engine to a real instruction
|
|
||||||
pub struct Pseudo(pub &'static str);
|
pub struct Pseudo(pub &'static str);
|
||||||
|
|
||||||
bitfield! {
|
bitfield! {
|
||||||
|
@ -108,6 +105,7 @@ pub mod kind {
|
||||||
pub opcode, set_opcode: 6, 0;
|
pub opcode, set_opcode: 6, 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum Kind {
|
pub enum Kind {
|
||||||
Pseudo(Pseudo),
|
Pseudo(Pseudo),
|
||||||
R(R),
|
R(R),
|
||||||
|
@ -530,7 +528,7 @@ pub fn with((kind, args): (Kind, Vec<Arg>), imm: u32, regs: Vec<usize>) -> (Kind
|
||||||
b.set_imm_12(to_bits::<1>(imm >> 12)[0]);
|
b.set_imm_12(to_bits::<1>(imm >> 12)[0]);
|
||||||
b.set_imm_11(to_bits::<1>(imm >> 11)[0]);
|
b.set_imm_11(to_bits::<1>(imm >> 11)[0]);
|
||||||
b.set_imm_10_5(imm >> 5);
|
b.set_imm_10_5(imm >> 5);
|
||||||
b.set_imm_4_1(imm);
|
b.set_imm_4_1(imm >> 1);
|
||||||
(Kind::B(b), args)
|
(Kind::B(b), args)
|
||||||
}
|
}
|
||||||
Kind::U(mut u) => {
|
Kind::U(mut u) => {
|
||||||
|
@ -617,21 +615,3 @@ const fn to_bits<const N: usize>(val: u32) -> [bool; N] {
|
||||||
}
|
}
|
||||||
bits
|
bits
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn reg_bits<const N: usize>(reg: usize) -> [bool; N] {
|
|
||||||
to_bits(reg as u32)
|
|
||||||
}
|
|
||||||
|
|
||||||
const 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
|
|
||||||
}
|
|
||||||
|
|
||||||
const fn to_reg<const N: usize>(bits: &[bool; N]) -> usize {
|
|
||||||
to_u32(bits) as usize
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
#![feature(effects)]
|
#![feature(effects)]
|
||||||
|
|
||||||
pub mod colorizer;
|
// pub mod colorizer;
|
||||||
pub mod env;
|
pub mod env;
|
||||||
pub mod err;
|
pub mod err;
|
||||||
pub mod execution;
|
pub mod execution;
|
||||||
|
|
14
src/main.rs
14
src/main.rs
|
@ -7,8 +7,12 @@ use codespan_reporting::{
|
||||||
Config,
|
Config,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use itertools::Itertools;
|
||||||
use riscv_interpreter::{
|
use riscv_interpreter::{
|
||||||
env::Env, execution::run_instruction, info::info, instructions::{instruction, kind::Kind}, parser::{parse, Token}
|
env::Env,
|
||||||
|
execution::run_instruction,
|
||||||
|
instructions::kind::Kind,
|
||||||
|
parser::{parse, Token},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
|
@ -33,7 +37,7 @@ fn main() -> anyhow::Result<()> {
|
||||||
let token = token.clone();
|
let token = token.clone();
|
||||||
|
|
||||||
match token.clone() {
|
match token.clone() {
|
||||||
Token::Op(name, _) => match env.assemble_op((token, loc.clone())) {
|
Token::Op(..) => match env.assemble_op((token, loc.clone())) {
|
||||||
Ok(op) => {
|
Ok(op) => {
|
||||||
let mut formatted = format!(
|
let mut formatted = format!(
|
||||||
"{:<1$} {3:02x}: {2:032b}",
|
"{:<1$} {3:02x}: {2:032b}",
|
||||||
|
@ -119,11 +123,7 @@ fn main() -> anyhow::Result<()> {
|
||||||
for op in ops {
|
for op in ops {
|
||||||
run_instruction(&mut env, op.0);
|
run_instruction(&mut env, op.0);
|
||||||
|
|
||||||
println!(
|
println!("{}\n{}", op.1, env.registers.iter().enumerate().map(|(i, r)| format!("x{:<1$} {2:032b}", i.to_string() + ":", 3, r)).join("\n"));
|
||||||
"{:<1$} <{2:02x}>",
|
|
||||||
op.1,
|
|
||||||
32,
|
|
||||||
env.get_register(10));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
55
src/tests.rs
55
src/tests.rs
|
@ -2,11 +2,10 @@
|
||||||
/// Test values come from Ripes
|
/// Test values come from Ripes
|
||||||
use crate::{
|
use crate::{
|
||||||
env::Env,
|
env::Env,
|
||||||
instructions::{get_instruction, with},
|
instructions::{get_instruction, handle_pseudo, with},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore = "TODO"]
|
|
||||||
fn nop() {
|
fn nop() {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
{
|
{
|
||||||
|
@ -18,20 +17,53 @@ fn nop() {
|
||||||
// nop
|
// nop
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
u32::from_str_radix(
|
u32::from_str_radix(
|
||||||
&with(
|
&handle_pseudo(
|
||||||
get_instruction("nop"),
|
get_instruction("nop"),
|
||||||
0, // imm
|
0, // imm
|
||||||
vec![]
|
vec![]
|
||||||
)
|
)[0]
|
||||||
.0
|
.0
|
||||||
.to_string(),
|
.to_string(),
|
||||||
2
|
2
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
0b00000000000000000000000000010011u32
|
0b00000000000000000000000000010011
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn li() {
|
||||||
|
let env = Env::new();
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
{
|
||||||
|
// li (pseudo) -> Myriad Sequence (in this case, both addi and lui)
|
||||||
|
// 1 -> lui
|
||||||
|
// U-Type
|
||||||
|
// | imm20 | rd | opcode
|
||||||
|
// 00000000000000001101 01010 0110111
|
||||||
|
// 00000000000000001101 01010 0110111
|
||||||
|
// 2 -> addi
|
||||||
|
// I-Type
|
||||||
|
// | imm12 | ra |f3 | rd | opcode
|
||||||
|
// 000000101001 01010 000 01010 0010011
|
||||||
|
// 000000101001 01010 000 01010 0010011
|
||||||
|
};
|
||||||
|
// li a0 53289
|
||||||
|
assert!(handle_pseudo(
|
||||||
|
get_instruction("li"),
|
||||||
|
53289,
|
||||||
|
vec![env.str_to_register("a0").unwrap()]
|
||||||
|
)
|
||||||
|
.into_iter()
|
||||||
|
.map(|i| u32::from_str_radix(dbg!(&i.0.to_string()), 2).unwrap())
|
||||||
|
.eq([
|
||||||
|
0b00000000000000001101010100110111,
|
||||||
|
0b00000010100101010000010100010011
|
||||||
|
]
|
||||||
|
.into_iter()));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn lui() {
|
fn lui() {
|
||||||
let env = Env::new();
|
let env = Env::new();
|
||||||
|
@ -56,7 +88,7 @@ fn lui() {
|
||||||
2
|
2
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
0b00000011010100101001010100110111u32
|
0b00000011010100101001010100110111
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +109,7 @@ fn sb() {
|
||||||
get_instruction("sb"),
|
get_instruction("sb"),
|
||||||
-4i32 as u32, // imm
|
-4i32 as u32, // imm
|
||||||
vec![
|
vec![
|
||||||
0, // rd
|
0, // rd
|
||||||
env.str_to_register("sp").unwrap(), // ra
|
env.str_to_register("sp").unwrap(), // ra
|
||||||
env.str_to_register("t5").unwrap() // rb
|
env.str_to_register("t5").unwrap() // rb
|
||||||
],
|
],
|
||||||
|
@ -87,7 +119,7 @@ fn sb() {
|
||||||
2
|
2
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
0b11111111111000010000111000100011u32
|
0b11111111111000010000111000100011
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +150,7 @@ fn add() {
|
||||||
2
|
2
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
0b00000000101101010000010100110011u32
|
0b00000000101101010000010100110011
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +182,7 @@ fn addi() {
|
||||||
2
|
2
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
0b00000000000101010000010100010011u32
|
0b00000000000101010000010100010011
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,6 +196,7 @@ fn beq() {
|
||||||
// | imm7 | rb | ra |f3 |imm5 | opcode
|
// | imm7 | rb | ra |f3 |imm5 | opcode
|
||||||
// 0000000 01011 01010 000 00100 1100011
|
// 0000000 01011 01010 000 00100 1100011
|
||||||
// 0000000 01011 01010 000 00100 1100011 (Ripes)
|
// 0000000 01011 01010 000 00100 1100011 (Ripes)
|
||||||
|
// 0000000 01011 01010 000 01000 1100011
|
||||||
};
|
};
|
||||||
// beq a0 a1 4
|
// beq a0 a1 4
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -182,6 +215,6 @@ fn beq() {
|
||||||
2
|
2
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
0b00000000101101010000001001100011u32
|
0b00000000101101010000001001100011
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue