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 {
|
||||
register_alias: HashMap<String, usize>,
|
||||
labels: HashMap<String, u32>,
|
||||
registers: [u32; 32],
|
||||
pub registers: [u32; 32],
|
||||
pub fregisters: [f32; 32],
|
||||
pub prev_stacks: Vec<Vec<u32>>,
|
||||
pub stack: Vec<u32>, // TODO: Find the actual size of the stack
|
||||
pub instructions: Vec<u32>,
|
||||
|
@ -29,6 +30,7 @@ impl Env {
|
|||
pub fn new() -> Self {
|
||||
// alias -> xN
|
||||
let register_alias = [
|
||||
// Integer regs
|
||||
("zero", 0),
|
||||
("ra", 1),
|
||||
("sp", 2),
|
||||
|
@ -62,6 +64,39 @@ impl Env {
|
|||
("t4", 29),
|
||||
("t5", 30),
|
||||
("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()
|
||||
.map(|(k, v)| (k.to_string(), v.to_owned()))
|
||||
|
@ -71,6 +106,7 @@ impl Env {
|
|||
register_alias,
|
||||
labels: HashMap::new(),
|
||||
registers: [0; 32],
|
||||
fregisters: [0.0; 32],
|
||||
prev_stacks: Vec::new(),
|
||||
stack: Vec::from([0; 1024]), // 1024 * 64 = 64 KiB stack
|
||||
instructions: Vec::new(),
|
||||
|
@ -99,6 +135,22 @@ impl Env {
|
|||
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) {
|
||||
self.labels.insert(label.to_string(), value);
|
||||
|
@ -250,7 +302,7 @@ impl Env {
|
|||
Token::Op(name, _) => {
|
||||
if let Some((kind, args)) = instruction(&name) {
|
||||
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])
|
||||
.into_iter()
|
||||
.for_each(|_| i += 4);
|
||||
|
@ -276,7 +328,7 @@ impl Env {
|
|||
&mut self,
|
||||
(op, loc): (Token, Loc),
|
||||
) -> 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) {
|
||||
(i, args.clone())
|
||||
} 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);
|
||||
}
|
||||
|
||||
/// 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
|
||||
fn jal(env: &mut Env, rd: usize, imm: u32) {
|
||||
env.set_register(rd, env.pc);
|
||||
env.pc += imm;
|
||||
}
|
||||
|
||||
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
|
||||
/// fmadd.s fd, fa, fb, fc
|
||||
fn fmadd_s(env: &mut Env, fd: usize, fa: usize, fb: usize, fc: usize) {
|
||||
env.set_fregister(fd, env.get_fregister(fa) * env.get_fregister(fb) + env.get_fregister(fc));
|
||||
}
|
||||
|
||||
pub fn run_instruction(env: &mut Env, kind: Kind) {
|
||||
let mut regs = kind.get_regs().unwrap();
|
||||
// Ensure all four registers have a value
|
||||
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 opcode = kind.get_opcode().unwrap();
|
||||
|
||||
|
@ -41,6 +42,15 @@ pub fn run_instruction(env: &mut Env, kind: Kind) {
|
|||
0b0010011 => {
|
||||
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!(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use colored::Colorize;
|
|||
|
||||
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 {
|
||||
"nop" => vec!["Do nothing - wait 1 cycle".to_string()],
|
||||
"li" => vec![format!("load {} into the register {}", args[1], args[0])],
|
||||
|
|
|
@ -6,11 +6,8 @@ pub mod kind {
|
|||
|
||||
use bitfield::bitfield;
|
||||
|
||||
use crate::instructions::{instruction, to_u32};
|
||||
|
||||
use super::{to_bits, to_reg};
|
||||
|
||||
/// will be converted by the engine to a real instruction
|
||||
/// will be converted by the engine to real instructions
|
||||
#[derive(Debug)]
|
||||
pub struct Pseudo(pub &'static str);
|
||||
|
||||
bitfield! {
|
||||
|
@ -108,6 +105,7 @@ pub mod kind {
|
|||
pub opcode, set_opcode: 6, 0;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Kind {
|
||||
Pseudo(Pseudo),
|
||||
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_11(to_bits::<1>(imm >> 11)[0]);
|
||||
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::U(mut u) => {
|
||||
|
@ -617,21 +615,3 @@ const fn to_bits<const N: usize>(val: u32) -> [bool; N] {
|
|||
}
|
||||
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(effects)]
|
||||
|
||||
pub mod colorizer;
|
||||
// pub mod colorizer;
|
||||
pub mod env;
|
||||
pub mod err;
|
||||
pub mod execution;
|
||||
|
|
14
src/main.rs
14
src/main.rs
|
@ -7,8 +7,12 @@ use codespan_reporting::{
|
|||
Config,
|
||||
},
|
||||
};
|
||||
use itertools::Itertools;
|
||||
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<()> {
|
||||
|
@ -33,7 +37,7 @@ fn main() -> anyhow::Result<()> {
|
|||
let token = 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) => {
|
||||
let mut formatted = format!(
|
||||
"{:<1$} {3:02x}: {2:032b}",
|
||||
|
@ -119,11 +123,7 @@ fn main() -> anyhow::Result<()> {
|
|||
for op in ops {
|
||||
run_instruction(&mut env, op.0);
|
||||
|
||||
println!(
|
||||
"{:<1$} <{2:02x}>",
|
||||
op.1,
|
||||
32,
|
||||
env.get_register(10));
|
||||
println!("{}\n{}", op.1, env.registers.iter().enumerate().map(|(i, r)| format!("x{:<1$} {2:032b}", i.to_string() + ":", 3, r)).join("\n"));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
55
src/tests.rs
55
src/tests.rs
|
@ -2,11 +2,10 @@
|
|||
/// Test values come from Ripes
|
||||
use crate::{
|
||||
env::Env,
|
||||
instructions::{get_instruction, with},
|
||||
instructions::{get_instruction, handle_pseudo, with},
|
||||
};
|
||||
|
||||
#[test]
|
||||
#[ignore = "TODO"]
|
||||
fn nop() {
|
||||
#[rustfmt::skip]
|
||||
{
|
||||
|
@ -18,20 +17,53 @@ fn nop() {
|
|||
// nop
|
||||
assert_eq!(
|
||||
u32::from_str_radix(
|
||||
&with(
|
||||
&handle_pseudo(
|
||||
get_instruction("nop"),
|
||||
0, // imm
|
||||
vec![]
|
||||
)
|
||||
)[0]
|
||||
.0
|
||||
.to_string(),
|
||||
2
|
||||
)
|
||||
.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]
|
||||
fn lui() {
|
||||
let env = Env::new();
|
||||
|
@ -56,7 +88,7 @@ fn lui() {
|
|||
2
|
||||
)
|
||||
.unwrap(),
|
||||
0b00000011010100101001010100110111u32
|
||||
0b00000011010100101001010100110111
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -77,7 +109,7 @@ fn sb() {
|
|||
get_instruction("sb"),
|
||||
-4i32 as u32, // imm
|
||||
vec![
|
||||
0, // rd
|
||||
0, // rd
|
||||
env.str_to_register("sp").unwrap(), // ra
|
||||
env.str_to_register("t5").unwrap() // rb
|
||||
],
|
||||
|
@ -87,7 +119,7 @@ fn sb() {
|
|||
2
|
||||
)
|
||||
.unwrap(),
|
||||
0b11111111111000010000111000100011u32
|
||||
0b11111111111000010000111000100011
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -118,7 +150,7 @@ fn add() {
|
|||
2
|
||||
)
|
||||
.unwrap(),
|
||||
0b00000000101101010000010100110011u32
|
||||
0b00000000101101010000010100110011
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -150,7 +182,7 @@ fn addi() {
|
|||
2
|
||||
)
|
||||
.unwrap(),
|
||||
0b00000000000101010000010100010011u32
|
||||
0b00000000000101010000010100010011
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -164,6 +196,7 @@ fn beq() {
|
|||
// | imm7 | rb | ra |f3 |imm5 | opcode
|
||||
// 0000000 01011 01010 000 00100 1100011
|
||||
// 0000000 01011 01010 000 00100 1100011 (Ripes)
|
||||
// 0000000 01011 01010 000 01000 1100011
|
||||
};
|
||||
// beq a0 a1 4
|
||||
assert_eq!(
|
||||
|
@ -182,6 +215,6 @@ fn beq() {
|
|||
2
|
||||
)
|
||||
.unwrap(),
|
||||
0b00000000101101010000001001100011u32
|
||||
0b00000000101101010000001001100011
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue