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

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

View file

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

View file

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

View file

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

View file

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

View file

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