Fix mem_offset being off by 4, streamlined some helpers, more op impls

This commit is contained in:
Lumi Kalt 2024-01-24 15:02:04 +00:00
parent 96202c0d1a
commit 6d81417701
7 changed files with 131 additions and 56 deletions

View file

@ -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 {

View file

@ -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!(),
} }
} }

View file

@ -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])],

View file

@ -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
}

View file

@ -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;

View file

@ -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(())

View file

@ -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
); );
} }