Commit 2b8187e7 authored by Arthur Carlsson's avatar Arthur Carlsson

In the middle of a refactor

parent 24a709d0
Pipeline #7312112 passed with stage
in 11 minutes and 18 seconds
use types::Word;
use mem::{VirtualAddr, PhysicalAddr};
use super::instruction::{Instruction, decode_instruction};
bitflags! {
flags StatusReg: u32 {
const IE = 0b00000001,
const EXL = 0b00000010,
const ERL = 0b00000100,
const KSU = 0b00011000,
const UX = 0b00100000,
const SX = 0b01000000,
const KX = 0b10000000 // 32 bit (0) or 64 bit (1) mode
}
}
impl StatusReg {
fn virt_to_phys_addr_active(self) -> bool {
((self & KSU).bits == 0
|| self & EXL == EXL
|| self & ERL == ERL)
&& self & KX == KX
}
}
pub struct Cpu {
pc_reg: VirtualAddr,
gp_reg: [u8; 32],
status_reg: StatusReg
}
impl Cpu {
pub fn new() -> Cpu {
Cpu {
pc_reg: 0,
gp_reg: [0; 32],
status_reg: StatusReg::empty()
}
}
pub fn power_on_reset(&mut self) {
self.pc_reg = 0xffff_ffff_bfc0_0000;
self.status_reg = ERL | KX;
}
pub fn next_instruction<T: Fn(PhysicalAddr) -> Result<Word, String>>(&self, instr_fn: T) -> Result<Instruction, String> {
self.instruction(self.pc_reg, instr_fn)
}
pub fn execute_instruction(&mut self, instr: &Instruction) {
self.pc_reg += 4;
}
fn instruction<T: Fn(PhysicalAddr) -> Result<Word, String>>(&self, addr: PhysicalAddr, instr_fn: T) -> Result<Instruction, String> {
decode_instruction(instr_fn(self.virt_to_phys_addr(addr))?)
}
fn virt_to_phys_addr(&self, vaddr: VirtualAddr) -> PhysicalAddr {
if !self.status_reg.virt_to_phys_addr_active() {
return vaddr;
}
match vaddr >> 32 {
// ckseg
0xffff_ffff => vaddr & 0x0000_0000_1fff_ffff,
_ => vaddr
}
}
}
#[cfg(tests)]
mod tests {
use super::*;
#[test]
fn test_power_on_reset_read() {
let mut cpu = Cpu::new();
cpu.power_on_reset();
let instr = cpu.next_instruction(|a| a);
// assert_eq!(, );
}
}
use types::Word;
use super::mem::Mem;
#[derive(Debug, PartialEq)]
pub enum Instruction {
IType { opcode: Opcode, rs: u8, rt: u8, imm: u16 },
COPz { cpno: u8, copz_opcode: COPzOpcode }
}
#[derive(Debug, PartialEq)]
pub enum Opcode {
LUI,
DADDI,
ORI,
LW,
ANDI,
BEQL,
ADDIU
}
// NAMN, HANDLER, DISASSEMBER, OPCODE
#[derive(Debug, PartialEq)]
pub enum COPzOpcode {
MT { rt: u8, rd: u8 }
}
pub fn decode_instruction(word: Word) -> Result<Instruction, String> {
match word >> 26 {
0b001111 => Ok(decode_itype_instruction(Opcode::LUI, word)),
0b011000 => Ok(decode_itype_instruction(Opcode::DADDI, word)),
0b001101 => Ok(decode_itype_instruction(Opcode::ORI, word)),
0b100011 => Ok(decode_itype_instruction(Opcode::LW, word)),
0b001100 => Ok(decode_itype_instruction(Opcode::ANDI, word)),
0b010100 => Ok(decode_itype_instruction(Opcode::BEQL, word)),
0b001001 => Ok(decode_itype_instruction(Opcode::ADDIU, word)),
0b010000 | 0b010001 | 0b010010 => decode_copz_instruction(word),
_ => Err(format!("Unknown instruction: {:#X}", word))
}
}
struct Opcode(u32, Box<Fn(u32, &Mem)>);
fn decode_itype_instruction(opcode: Opcode, word: Word) -> Instruction {
Instruction::IType {
opcode: opcode,
rs: 0,
rt: ((word >> 16) & 0b11111) as u8,
imm: (word & 0xffff) as u16
}
struct OpcodeTable {
opcodes: Vec<Opcode>
}
fn decode_copz_instruction(word: Word) -> Result<Instruction, String> {
let cpno = ((word << 28) & 0b11) as u8;
let copz_opcode = match (word >> 21) & 0b11111 {
0b00100 => Some(COPzOpcode::MT { rt: ((word >> 16) & 0b11111) as u8, rd: ((word >> 11) & 0b11111) as u8 }),
_ => None
};
match copz_opcode {
Some(opcode) => Ok(Instruction::COPz { cpno: cpno, copz_opcode: opcode }),
None => Err(format!("Unknown COPz instruction: {:#X}", word))
impl OpcodeTable {
fn new() -> OpcodeTable {
OpcodeTable {
opcodes: vec![
Opcode(0x0000, Box::new(|opcode, mem| println!("asd")))
]
}
}
}
#[cfg(test)]
mod tests {
use cpu::reg::GPR;
use super::*;
#[test]
fn test_decode_itype() {
assert_eq!(Ok(Instruction::IType { opcode: Opcode::LUI, rs: 0, rt: GPR::T1 as u8, imm: 0x3400 }), decode_instruction(0x3c093400));
fn decode(&self, instr: u32) -> &Opcode {
&self.opcodes.iter().find(|opcode| (opcode.0 & instr) == opcode.0).unwrap()
}
#[test]
fn test_decode_copz() {
assert_eq!(Ok(Instruction::COPz { cpno: 0, copz_opcode: COPzOpcode::MT { rt: GPR::T1 as u8, rd: 12 } }), decode_instruction(0x40896000));
}
}
pub trait Mem {
fn read_word(&self, addr: u32) -> u32;
fn write_byte(&mut self, addr: u32, data: u8);
}
mod cpu;
mod instruction;
mod reg;
mod mem;
pub use self::cpu::Cpu;
//pub use mem::Mem;
......@@ -32,13 +32,6 @@ impl<'a> N64<'a> {
}
pub fn step(&mut self) {
match self.cpu.next_instruction(|addr| self.read_word(addr)) {
Err(s) => panic!(s),
Ok(instr) => {
println!("Instruction: {:?}", instr);
self.cpu.execute_instruction(&instr)
}
};
}
fn read_word(&self, addr: PhysicalAddr) -> Result<Word, String> {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment