Commit 5898cb38 authored by Arthur Carlsson's avatar Arthur Carlsson

First decoding of instruction

parent 2616c5b0
Pipeline #5203328 passed with stage
in 2 minutes and 1 second
use types::Word;
use mem::PhysicalAddr;
use mem::{VirtualAddr, PhysicalAddr};
use super::instruction::Instruction;
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: PhysicalAddr
pc_reg: VirtualAddr,
gp_reg: [u8; 32],
status_reg: StatusReg
}
impl Cpu {
pub fn new() -> Cpu {
Cpu {
pc_reg: 0
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) -> Option<Word>>(&self, instr_fn: T) -> Result<Instruction, String> {
pub fn next_instruction<T: Fn(PhysicalAddr) -> Result<Word, String>>(&self, instr_fn: T) -> Result<Instruction, String> {
self.instruction(self.pc_reg, instr_fn)
}
fn instruction<T: Fn(PhysicalAddr) -> Option<Word>>(&self, addr: PhysicalAddr, instr_fn: T) -> Result<Instruction, String> {
match instr_fn(addr) {
_ => Err(format!("Unknown instruction: {:#X}", addr))
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;
#[derive(Debug, PartialEq)]
pub enum Instruction {
IType { opcode: Opcode, rs: u8, rt: u8, imm: u16 }
}
#[derive(Debug, PartialEq)]
pub enum Opcode {
LUI
}
pub trait ExecuteInstruction {
fn execute_instruction(&mut self, instr: &Instruction);
}
pub fn decode_instruction(word: Word) -> Result<Instruction, String> {
match word >> 26 {
0b001111 => Ok(decode_itype_instruction(Opcode::LUI, word)),
_ => Err(format!("Unknown instruction: {}", word))
}
}
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
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_arne() {
assert_eq!(Ok(Instruction::IType { opcode: Opcode::LUI, rs: 0, rt: 9, imm: 0x3400 }), decode_instruction(0x3c093400));
}
}
......@@ -18,11 +18,11 @@ impl<T> MMap<T> {
}
}
pub fn map_addr(&self, addr: PhysicalAddr) -> Option<T> {
self.entries.iter()
.map(|e| e.map_addr(addr))
.find(|e| e.is_some())
.map(|e| e.unwrap())
pub fn map_addr(&self, addr: PhysicalAddr) -> Result<T, String> {
match self.entries.iter().map(|e| e.map_addr(addr)).find(|e| e.is_some()).map(|e| e.unwrap()) {
Some(addr) => Ok(addr),
None => Err(format!("Could not match address: {}", addr))
}
}
}
......@@ -55,23 +55,23 @@ mod tests {
#[test]
fn test_read_word() {
assert_eq!(Some(MyAddr::A(6)), mmap().map_addr(1240));
assert_eq!(Ok(MyAddr::A(6)), mmap().map_addr(1240));
}
#[test]
fn test_read_word_no_match() {
assert_eq!(None, mmap().map_addr(11000));
assert!(mmap().map_addr(11000).is_err());
}
#[test]
fn test_read_word_address_map() {
assert_eq!(Some(MyAddr::A(1)), mmap().map_addr(1235));
assert_eq!(Ok(MyAddr::A(1)), mmap().map_addr(1235));
}
#[test]
fn test_read_word_edge() {
assert_eq!(None, mmap().map_addr(5678));
assert_eq!(Some(MyAddr::A(0)), mmap().map_addr(1234));
assert!(mmap().map_addr(5678).is_err());
assert_eq!(Ok(MyAddr::A(0)), mmap().map_addr(1234));
}
}
......@@ -19,7 +19,7 @@ impl Bus {
}
}
pub fn map_addr(&self, addr: PhysicalAddr) -> Option<Addr> {
pub fn map_addr(&self, addr: PhysicalAddr) -> Result<Addr, String> {
self.mem_map.map_addr(addr)
}
}
......@@ -35,15 +35,15 @@ impl<'a> N64<'a> {
match self.cpu.next_instruction(|addr| self.read_word(addr)) {
Err(s) => println!("Error: {}", s),
Ok(instr) => {
println!("Instruction: {:?}", instr)
}
};
}
fn read_word(&self, addr: PhysicalAddr) -> Option<Word> {
self.bus.map_addr(addr).map(|a| match a {
Addr::PifRom(pa) => self.pif_rom.read_word(pa),
Addr::CartDom1(pa) => self.cart.unwrap().read_word(pa)
})
fn read_word(&self, addr: PhysicalAddr) -> Result<Word, String> {
match self.bus.map_addr(addr)? {
Addr::PifRom(pa) => Ok(self.pif_rom.read_word(pa)),
Addr::CartDom1(pa) => Ok(self.cart.unwrap().read_word(pa))
}
}
}
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