Files
riscy-rust/src/ext/i/mod.rs
2023-07-19 00:48:21 +01:00

241 lines
6.5 KiB
Rust

use std::usize;
use bits::match_mask;
use enum_dispatch::*;
use strum::EnumIter;
use super::encoding::{GenInstruction, Instruction};
use crate::cpu;
use crate::ext::encoding::ImmediateMode;
use crate::helpers::sext;
use crate::system::rv32;
// FOR BRANCH INSTRUCTIONS ITS IMPERATIVE TO REMEMBER
// THAT WE INCREMENT PC AFTER THE EXECUTION
#[derive(Default, Copy, Clone)]
pub struct LUI; // Load Upper Immediate
// Load the immedate mode value into the MSB of rd
// The last 12 bits of rd should be 0
impl Instruction for LUI {
fn name(&self) -> &'static str {
"LUI"
}
fn match_inst(&self, inst: rv32::Word) -> bool {
match_mask!(inst, "xxxxxxxxxxxxxxxxxxxxxxxxx0110111")
}
fn step(&self, inst: GenInstruction, state: &mut cpu::CPUState) {
println!("VM > Executing LUI");
let inst = unsafe { inst.U };
let val = inst.full_imm() << 12;
state.x[inst.rd() as usize] = val;
}
}
#[derive(Default, Copy, Clone)]
pub struct AUIPC; // Add Upper Immedate to PC
// Set rd to the immediate mode value + pc
impl Instruction for AUIPC {
fn name(&self) -> &'static str {
"AUIPC"
}
fn match_inst(&self, inst: rv32::Word) -> bool {
match_mask!(inst, "xxxxxxxxxxxxxxxxxxxxxxxxx0010111")
}
fn step(&self, inst: GenInstruction, state: &mut cpu::CPUState) {
println!("VM > Executing AUIPC");
let inst = unsafe { inst.U };
let val = inst.full_imm() << 12;
let pc_add = state.pc.wrapping_add(val);
state.x[inst.rd() as usize] = pc_add;
}
}
#[derive(Default, Copy, Clone)]
pub struct JAL; // Jump and Link
// Set pc to offset (imm) + pc
// Set rd to the old pc + 4
impl Instruction for JAL {
fn name(&self) -> &'static str {
"JAL"
}
fn match_inst(&self, inst: rv32::Word) -> bool {
match_mask!(inst, "xxxxxxxxxxxxxxxxxxxxxxxxx1101111")
}
fn step(&self, inst: GenInstruction, state: &mut cpu::CPUState) {
println!("VM > Executing JAL");
let inst = unsafe { inst.J };
let offset = sext(inst.full_imm() << 1, 32);
let pc = offset.wrapping_add(state.pc);
state.x[inst.rd() as usize] = state.pc + rv32::WORD as u32;
state.pc = pc - 4;
}
}
#[derive(Default, Copy, Clone)]
pub struct JALR; // JAL but R type offset encoding
// Add imm to rs1 then make it even (LSB = 0)
// Set the PC to the contents of rd
// Set rd to the old pc + 4
impl Instruction for JALR {
fn name(&self) -> &'static str {
"JALR"
}
fn match_inst(&self, inst: rv32::Word) -> bool {
match_mask!(inst, "xxxxxxxxxxxxxxxxx000xxxxx1100111")
}
fn step(&self, inst: GenInstruction, state: &mut cpu::CPUState) {
println!("VM > Executing JALR");
let inst = unsafe { inst.I };
let offset = sext(inst.full_imm(), 32);
let pc = offset.wrapping_add(state.x[inst.rs1() as usize]);
state.x[inst.rd() as usize] = state.pc + rv32::WORD as u32;
state.pc = pc - 4;
}
}
#[derive(Default, Copy, Clone)]
pub struct BRANCH; // Thisis is the first time we write a catchall
// instruction, this will match BEQ, BNE, BLT,
// BGE, BLTU, BEGE
impl Instruction for BRANCH {
fn name(&self) -> &'static str {
"BEQ, BNE, BLT, BGE, BLTU, BGEU"
}
fn match_inst(&self, inst: rv32::Word) -> bool {
match_mask!(inst, "xxxxxxxxxxxxxxxxxxxxxxxxx1100011")
}
fn step(&self, inst: GenInstruction, state: &mut cpu::CPUState) {
println!("VM > Executing BEQ, BNE, BLT, BGE, BLTU, BGEU");
let inst = unsafe { inst.B };
let offset = state.pc + (inst.sext_imm() << 1) - 4;
match inst.funct3() {
0b000 => {
if inst.rs1() == inst.rs2() {
state.pc = offset
}
}
0b001 => {
if inst.rs1() != inst.rs2() {
state.pc = offset
}
}
0b100 => {
if inst.rs1() < inst.rs2() {
state.pc = offset
}
}
0b101 => {
if inst.rs1() >= inst.rs2() {
state.pc = offset
}
}
0b110 => {
if (inst.rs1() as u32) < (inst.rs2() as u32) {
state.pc = offset
}
}
0b111 => {
if (inst.rs1() as u32) >= (inst.rs2() as u32) {
state.pc = offset
}
}
_ => state.trap = 3,
}
}
}
#[derive(Default, Copy, Clone)]
pub struct Load;
impl Instruction for Load {
fn name(&self) -> &'static str {
"LOAD"
}
fn match_inst(&self,inst:rv32::Word) -> bool {
match_mask!(inst, "xxxxxxxxxxxxxxxxxxxxxxxxx0000011")
}
fn step(&self,inst:GenInstruction,state: &mut cpu::CPUState) {
}
}
#[derive(Default, Copy, Clone)]
pub struct Store;
impl Instruction for Store {
fn name(&self) -> &'static str {
"STORE"
}
fn match_inst(&self,inst:rv32::Word) -> bool {
match_mask!(inst, "xxxxxxxxxxxxxxxxxxxxxxxxx0100011")
}
}
#[derive(Default, Copy, Clone)]
pub struct ADDI;
impl Instruction for ADDI {
fn name(&self) -> &'static str {
"ADDI"
}
fn match_inst(&self, inst: rv32::Word) -> bool {
match_mask!(inst, "xxxxxxxxxxxxxxxxx000xxxxx0010011")
}
fn step(&self, inst: GenInstruction, state: &mut cpu::CPUState) {
println!("VM > Executing ADDI");
let inst = unsafe { inst.I };
state.x[inst.rd() as usize] = state.x[inst.rs1() as usize].wrapping_add(inst.sext_imm())
}
}
#[derive(Default, Copy, Clone)]
pub struct ADD;
impl Instruction for ADD {
fn name(&self) -> &'static str {
"ADD"
}
fn match_inst(&self, inst: rv32::Word) -> bool {
match_mask!(inst, "0000000xxxxxxxxxx000xxxxx0110011")
}
fn step(&self, inst: GenInstruction, state: &mut cpu::CPUState) {
println!("VM > Executing ADD");
let inst = unsafe { inst.R };
state.x[inst.rd() as usize] =
state.x[inst.rs1() as usize].wrapping_add(state.x[inst.rs2() as usize]);
}
}
#[enum_dispatch(Instruction)]
#[derive(EnumIter)]
pub enum ExtensionI {
LUI(LUI),
AUIPC(AUIPC),
JAL(JAL),
JALR(JALR),
BRANCH(BRANCH),
LOAD(BRANCH),
STORE(STORE),
ADDI(ADDI),
ADD(ADD),
}