laying some foundation
This commit is contained in:
@@ -0,0 +1,12 @@
|
|||||||
|
pub mod cpu;
|
||||||
|
pub mod instruction;
|
||||||
|
pub mod interpreter;
|
||||||
|
pub mod mem;
|
||||||
|
pub mod registers;
|
||||||
|
|
||||||
|
pub struct Core {}
|
||||||
|
|
||||||
|
impl Core {
|
||||||
|
pub fn stop(&mut self) {}
|
||||||
|
pub fn reset(&mut self) {}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
use crate::core::{instruction::Instruction, mem::Memory, registers::Registers};
|
||||||
|
|
||||||
|
pub enum CpuType {
|
||||||
|
Interpreter,
|
||||||
|
CachedInterpreter,
|
||||||
|
DynamicRecompiler,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Cpu {
|
||||||
|
fn get_type() -> CpuType;
|
||||||
|
fn get_regs(&mut self) -> &mut Registers;
|
||||||
|
fn fetch(&self, _: &Memory, _: u64) -> Option<Instruction> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fetch_then_advance(&mut self, _: &Memory) -> Option<Instruction> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
fn execute(&mut self, mem: &Memory) -> Result<u32, String>;
|
||||||
|
fn advance(&mut self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
fn decode(&mut self, instr: Instruction) -> Result<(), String>;
|
||||||
|
fn reset(&mut self);
|
||||||
|
fn should_service_interrupt(&self) -> bool;
|
||||||
|
fn update_compare_interrupt(&mut self);
|
||||||
|
}
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
use proc_bitfield::bitfield;
|
||||||
|
|
||||||
|
bitfield! {
|
||||||
|
pub struct Instruction(pub u32): Debug, FromStorage, IntoStorage, DerefStorage {
|
||||||
|
pub special: u8 @ 0..6,
|
||||||
|
pub regimm: u8 @ 16..21,
|
||||||
|
pub rt: u8 @ 16..21,
|
||||||
|
pub cop_rt: u8 @ 16..21,
|
||||||
|
pub rs: u8 @ 21..26,
|
||||||
|
pub cop_rs: u8 @ 21..26,
|
||||||
|
pub opcode: u8 @ 26..32,
|
||||||
|
pub imm: u16 @ 0..16,
|
||||||
|
pub target: u32 @ 0..26,
|
||||||
|
pub funct: u8 @ 0..6,
|
||||||
|
pub sa: u8 @ 6..11,
|
||||||
|
pub rd: u8 @ 11..16,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BranchType {
|
||||||
|
Pure,
|
||||||
|
Likely,
|
||||||
|
Link,
|
||||||
|
LinkLikely,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Instruction {
|
||||||
|
fn get_branch(self) -> Option<BranchType> {
|
||||||
|
match self.opcode() {
|
||||||
|
Instruction::BEQ | Instruction::BNE | Instruction::BLEZ | Instruction::BGTZ => {
|
||||||
|
Some(BranchType::Pure)
|
||||||
|
}
|
||||||
|
Instruction::BEQL | Instruction::BNEL | Instruction::BLEZL | Instruction::BGTZL => {
|
||||||
|
Some(BranchType::Likely)
|
||||||
|
}
|
||||||
|
Instruction::REGIMM => match self.regimm() {
|
||||||
|
Instruction::BLTZ | Instruction::BGEZ => Some(BranchType::Pure),
|
||||||
|
Instruction::BLTZAL | Instruction::BGEZAL => Some(BranchType::Link),
|
||||||
|
Instruction::BLTZL | Instruction::BGEZL => Some(BranchType::Likely),
|
||||||
|
Instruction::BLTZALL | Instruction::BGEZALL => Some(BranchType::LinkLikely),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
Instruction::COP1 => {
|
||||||
|
if self.cop_rs() == 8 {
|
||||||
|
match self.cop_rt() {
|
||||||
|
0 | 1 => Some(BranchType::Pure),
|
||||||
|
2 | 3 => Some(BranchType::Likely),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const SPECIAL: u8 = 0b000000;
|
||||||
|
const REGIMM: u8 = 0b000001;
|
||||||
|
const J: u8 = 0b000010;
|
||||||
|
const JAL: u8 = 0b000011;
|
||||||
|
const BEQ: u8 = 0b000100;
|
||||||
|
const BNE: u8 = 0b000101;
|
||||||
|
const BLEZ: u8 = 0b000110;
|
||||||
|
const BGTZ: u8 = 0b000111;
|
||||||
|
const ADDI: u8 = 0b001000;
|
||||||
|
const ADDIU: u8 = 0b001001;
|
||||||
|
const SLTI: u8 = 0b001010;
|
||||||
|
const SLTIU: u8 = 0b001011;
|
||||||
|
const ANDI: u8 = 0b001100;
|
||||||
|
const ORI: u8 = 0b001101;
|
||||||
|
const XORI: u8 = 0b001110;
|
||||||
|
const LUI: u8 = 0b001111;
|
||||||
|
const COP0: u8 = 0b010000;
|
||||||
|
const COP1: u8 = 0b010001;
|
||||||
|
const COP2: u8 = 0b010010;
|
||||||
|
const BEQL: u8 = 0b010100;
|
||||||
|
const BNEL: u8 = 0b010101;
|
||||||
|
const BLEZL: u8 = 0b010110;
|
||||||
|
const BGTZL: u8 = 0b010111;
|
||||||
|
const DADDI: u8 = 0b011000;
|
||||||
|
const DADDIU: u8 = 0b011001;
|
||||||
|
const LDL: u8 = 0b011010;
|
||||||
|
const LDR: u8 = 0b011011;
|
||||||
|
const LB: u8 = 0b100000;
|
||||||
|
const LH: u8 = 0b100001;
|
||||||
|
const LWL: u8 = 0b100010;
|
||||||
|
const LW: u8 = 0b100011;
|
||||||
|
const LBU: u8 = 0b100100;
|
||||||
|
const LHU: u8 = 0b100101;
|
||||||
|
const LWR: u8 = 0b100110;
|
||||||
|
const LWU: u8 = 0b100111;
|
||||||
|
const SB: u8 = 0b101000;
|
||||||
|
const SH: u8 = 0b101001;
|
||||||
|
const SWL: u8 = 0b101010;
|
||||||
|
const SW: u8 = 0b101011;
|
||||||
|
const SDL: u8 = 0b101100;
|
||||||
|
const SDR: u8 = 0b101101;
|
||||||
|
const SWR: u8 = 0b101110;
|
||||||
|
const CACHE: u8 = 0b101111;
|
||||||
|
const LL: u8 = 0b110000;
|
||||||
|
const LWC1: u8 = 0b110001;
|
||||||
|
const LWC2: u8 = 0b110010;
|
||||||
|
const LLD: u8 = 0b110100;
|
||||||
|
const LDC1: u8 = 0b110101;
|
||||||
|
const LDC2: u8 = 0b110110;
|
||||||
|
const LD: u8 = 0b110111;
|
||||||
|
const SC: u8 = 0b111000;
|
||||||
|
const SWC1: u8 = 0b111001;
|
||||||
|
const SWC2: u8 = 0b111010;
|
||||||
|
const SCD: u8 = 0b111100;
|
||||||
|
const SDC1: u8 = 0b111101;
|
||||||
|
const SDC2: u8 = 0b111110;
|
||||||
|
const SD: u8 = 0b111111;
|
||||||
|
// special
|
||||||
|
const SLL: u8 = 0b000000;
|
||||||
|
const SRL: u8 = 0b000010;
|
||||||
|
const SRA: u8 = 0b000011;
|
||||||
|
const SLLV: u8 = 0b000100;
|
||||||
|
const SRLV: u8 = 0b000110;
|
||||||
|
const SRAV: u8 = 0b000111;
|
||||||
|
const JR: u8 = 0b001000;
|
||||||
|
const JALR: u8 = 0b001001;
|
||||||
|
const SYSCALL: u8 = 0b001100;
|
||||||
|
const BREAK: u8 = 0b001101;
|
||||||
|
const SYNC: u8 = 0b001111;
|
||||||
|
const MFHI: u8 = 0b010000;
|
||||||
|
const MTHI: u8 = 0b010001;
|
||||||
|
const MFLO: u8 = 0b010010;
|
||||||
|
const MTLO: u8 = 0b010011;
|
||||||
|
const DSLLV: u8 = 0b010100;
|
||||||
|
const DSRLV: u8 = 0b010110;
|
||||||
|
const DSRAV: u8 = 0b010111;
|
||||||
|
const MULT: u8 = 0b011000;
|
||||||
|
const MULTU: u8 = 0b011001;
|
||||||
|
const DIV: u8 = 0b011010;
|
||||||
|
const DIVU: u8 = 0b011011;
|
||||||
|
const DMULT: u8 = 0b011100;
|
||||||
|
const DMULTU: u8 = 0b011101;
|
||||||
|
const DDIV: u8 = 0b011110;
|
||||||
|
const DDIVU: u8 = 0b011111;
|
||||||
|
const ADD: u8 = 0b100000;
|
||||||
|
const ADDU: u8 = 0b100001;
|
||||||
|
const SUB: u8 = 0b100010;
|
||||||
|
const SUBU: u8 = 0b100011;
|
||||||
|
const AND: u8 = 0b100100;
|
||||||
|
const OR: u8 = 0b100101;
|
||||||
|
const XOR: u8 = 0b100110;
|
||||||
|
const NOR: u8 = 0b100111;
|
||||||
|
const SLT: u8 = 0b101010;
|
||||||
|
const SLTU: u8 = 0b101011;
|
||||||
|
const DADD: u8 = 0b101100;
|
||||||
|
const DADDU: u8 = 0b101101;
|
||||||
|
const DSUB: u8 = 0b101110;
|
||||||
|
const DSUBU: u8 = 0b101111;
|
||||||
|
const TGE: u8 = 0b110000;
|
||||||
|
const TGEU: u8 = 0b110001;
|
||||||
|
const TLT: u8 = 0b110010;
|
||||||
|
const TLTU: u8 = 0b110011;
|
||||||
|
const TEQ: u8 = 0b110100;
|
||||||
|
const TNE: u8 = 0b110110;
|
||||||
|
const DSLL: u8 = 0b111000;
|
||||||
|
const DSRL: u8 = 0b111010;
|
||||||
|
const DSRA: u8 = 0b111011;
|
||||||
|
const DSLL32: u8 = 0b111100;
|
||||||
|
const DSRL32: u8 = 0b111110;
|
||||||
|
const DSRA32: u8 = 0b111111;
|
||||||
|
// regimm
|
||||||
|
const BLTZ: u8 = 0b00000;
|
||||||
|
const BGEZ: u8 = 0b00001;
|
||||||
|
const BLTZL: u8 = 0b00010;
|
||||||
|
const BGEZL: u8 = 0b00011;
|
||||||
|
const TGEI: u8 = 0b01000;
|
||||||
|
const TGEIU: u8 = 0b01001;
|
||||||
|
const TLTI: u8 = 0b01010;
|
||||||
|
const TLTIU: u8 = 0b01011;
|
||||||
|
const TEQI: u8 = 0b01100;
|
||||||
|
const TNEI: u8 = 0b01110;
|
||||||
|
const BLTZAL: u8 = 0b10000;
|
||||||
|
const BGEZAL: u8 = 0b10001;
|
||||||
|
const BLTZALL: u8 = 0b10010;
|
||||||
|
const BGEZALL: u8 = 0b10011;
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
use crate::{
|
||||||
|
core::{
|
||||||
|
cpu::{Cpu, CpuType::*},
|
||||||
|
instruction::Instruction,
|
||||||
|
mem::Memory,
|
||||||
|
registers::Registers,
|
||||||
|
},
|
||||||
|
utils::access::is_address_error,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Interpreter {
|
||||||
|
regs: Registers,
|
||||||
|
delay_slot: bool,
|
||||||
|
prev_delay_slot: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cpu for Interpreter {
|
||||||
|
fn get_type() -> super::cpu::CpuType {
|
||||||
|
Interpreter
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_regs(&mut self) -> &mut Registers {
|
||||||
|
&mut self.regs
|
||||||
|
}
|
||||||
|
|
||||||
|
fn should_service_interrupt(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_compare_interrupt(&mut self) {
|
||||||
|
todo!("update_compare_interrupt")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fetch(&self, _mem: &Memory, _vaddr: u64) -> Option<Instruction> {
|
||||||
|
todo!("translate vaddr to paddr and if it fails, throw the exception and return None");
|
||||||
|
// Some(mem.read<u32>(paddr).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fetch_then_advance(&mut self, mem: &Memory) -> Option<Instruction> {
|
||||||
|
self.update_compare_interrupt();
|
||||||
|
|
||||||
|
self.prev_delay_slot = self.delay_slot;
|
||||||
|
self.delay_slot = false;
|
||||||
|
|
||||||
|
if is_address_error(&self.regs, 0b11, self.regs.curr_pc) {
|
||||||
|
todo!("is_address_error ? then throw exception and return None");
|
||||||
|
}
|
||||||
|
|
||||||
|
let instr = self.fetch(mem, self.regs.curr_pc as u64)?;
|
||||||
|
|
||||||
|
if self.should_service_interrupt() {
|
||||||
|
todo!("should_service_interrupt ? then throw exception and return None");
|
||||||
|
}
|
||||||
|
|
||||||
|
self.regs.old_pc = self.regs.curr_pc;
|
||||||
|
self.regs.curr_pc = self.regs.next_pc;
|
||||||
|
self.regs.next_pc += 4;
|
||||||
|
|
||||||
|
Some(instr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute(&mut self, mem: &Memory) -> Result<u32, String> {
|
||||||
|
if let Some(instr) = self.fetch_then_advance(mem) {
|
||||||
|
self.decode(instr)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decode(&mut self, instr: Instruction) -> Result<(), String> {
|
||||||
|
todo!("decode")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset(&mut self) {
|
||||||
|
todo!("reset")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
pub struct Memory {}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
pub struct Registers {
|
||||||
|
pub gpr: [i64; 32],
|
||||||
|
pub old_pc: i64,
|
||||||
|
pub curr_pc: i64,
|
||||||
|
pub next_pc: i64,
|
||||||
|
pub hi: i64,
|
||||||
|
pub lo: i64,
|
||||||
|
pub constant_regs: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Registers {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
gpr: [0; 32],
|
||||||
|
old_pc: 0,
|
||||||
|
curr_pc: 0,
|
||||||
|
next_pc: 0,
|
||||||
|
hi: 0,
|
||||||
|
lo: 0,
|
||||||
|
constant_regs: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_pc<T>(&mut self, value: T)
|
||||||
|
where
|
||||||
|
i64: From<T>,
|
||||||
|
{
|
||||||
|
self.old_pc = self.curr_pc;
|
||||||
|
self.curr_pc = value.into();
|
||||||
|
self.next_pc = self.curr_pc + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read<T>(&self, idx: usize) -> T
|
||||||
|
where
|
||||||
|
T: From<i64>,
|
||||||
|
{
|
||||||
|
self.gpr[idx].into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write<T>(&mut self, idx: usize, value: T)
|
||||||
|
where
|
||||||
|
i64: From<T>,
|
||||||
|
{
|
||||||
|
if idx == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.constant_regs |= 1 << idx;
|
||||||
|
self.gpr[idx] = value.into();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1 +1,5 @@
|
|||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
pub mod core;
|
||||||
|
pub mod scheduler;
|
||||||
|
pub mod utils;
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
use crate::core::registers::Registers;
|
||||||
|
|
||||||
|
pub fn is_address_error(_regs: &Registers, mask: u8, vaddr: i64) -> bool {
|
||||||
|
vaddr & mask as i64 != 0
|
||||||
|
// || (!regs.cop0.is64BitAddressing && s32(vaddr) != vaddr)
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
pub mod access;
|
||||||
Reference in New Issue
Block a user