Commit 65376d14 authored by Arthur Carlsson's avatar Arthur Carlsson

Added alot of CPU and memory management code

parent 2370da93
Pipeline #5189406 failed with stage
in 2 minutes and 24 seconds
use types::Word;
use mem::PhysicalAddr;
use super::instruction::Instruction;
pub struct Cpu {
pc_reg: PhysicalAddr
}
impl Cpu {
pub fn new() -> Cpu {
Cpu {
pc_reg: 0
}
}
pub fn power_on_reset(&mut self) {
self.pc_reg = 0xffff_ffff_bfc0_0000;
}
pub fn next_instruction<T: Fn(PhysicalAddr) -> Option<Word>>(&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))
}
}
}
pub enum Instruction {
}
pub trait ExecuteInstruction {
fn execute_instruction(&mut self, instr: &Instruction);
}
mod cpu;
mod instruction;
pub use self::cpu::Cpu;
......@@ -4,6 +4,8 @@ mod types;
mod rom;
mod pif_rom;
pub mod n64;
pub mod cpu;
pub mod mem;
pub use types::Word;
pub use pif_rom::PifRom;
......@@ -7,7 +7,7 @@ use std::path::Path;
use clap::{App, Arg};
use rustn64::PifRom;
use rustn64::n64::Cart;
use rustn64::n64;
fn main() {
let matches = App::new("RustN64")
......@@ -31,10 +31,18 @@ fn main() {
let pif = read_bin(matches.value_of("PIF").unwrap());
let rom = read_bin(matches.value_of("ROM").unwrap());
PifRom::new(pif);
let cart = Cart::new(rom);
let pif_rom = PifRom::new(pif);
let cart = n64::Cart::new(rom);
println!("Running {}", cart.title())
println!("Running {}", cart.title());
let mut n64 = n64::N64::new(pif_rom);
n64.insert_cart(&cart);
n64.power_on();
loop {
n64.step();
}
}
fn read_bin<P: AsRef<Path>>(path: P) -> Vec<u8> {
......
use std::ops::Range;
pub type PhysicalAddr = u64;
pub type VirtualAddr = u64;
pub struct MMap<T> {
addr_space: Range<PhysicalAddr>,
func: Box<Fn(PhysicalAddr) -> T>
}
impl<T> MMap<T> {
pub fn new(addr_space: Range<PhysicalAddr>, func: Box<Fn(PhysicalAddr) -> T>) -> MMap<T> {
MMap {
addr_space: addr_space,
func: func
}
}
pub fn map_addr(&self, addr: PhysicalAddr) -> Option<T> {
if self.addr_space.start <= addr && addr < self.addr_space.end {
Some((self.func)(addr - self.addr_space.start))
} else {
None
}
}
}
use mem::{PhysicalAddr, MMap};
pub enum Addr {
PifRom(PhysicalAddr),
CartDom1(PhysicalAddr)
}
pub struct Bus {
mem_map: Vec<MMap<Addr>>
}
impl Bus {
pub fn new() -> Bus {
Bus {
mem_map: vec![
MMap::new(0x1fc0_0000..0x1fc0_07bf, Box::new(Addr::PifRom)),
MMap::new(0x1000_0000..0x1fc0_0000, Box::new(Addr::CartDom1))
]
}
}
pub fn map_addr(&self, addr: PhysicalAddr) -> Option<Addr> {
self.mem_map.iter()
.map(|mm| mm.map_addr(addr))
.find(|mm| mm.is_some())
.map(|mm| mm.unwrap())
}
}
#[cfg(test)]
mod tests {
use super::*;
use mem::MMap;
#[test]
fn test_read_word() {
let bus = Bus::new(vec![
MMap::new(1234..5678, Box::new(|_| 1))
]);
assert_eq!(Some(1), bus.read_word(4678))
}
#[test]
fn test_read_word_no_match() {
let bus = Bus::new(vec![
MMap::new(1234..5678, Box::new(|_| 1))
]);
assert_eq!(None, bus.read_word(9123))
}
#[test]
fn test_read_word_address_map() {
let bus = Bus::new(vec![
MMap::new(1234..5678, Box::new(|addr| addr as u32))
]);
assert_eq!(Some(1), bus.read_word(1235))
}
#[test]
fn test_read_word_edge() {
let bus = Bus::new(vec![
MMap::new(1234..5678, Box::new(|_| 1))
]);
assert_eq!(None, bus.read_word(5678));
assert_eq!(Some(1), bus.read_word(1234));
}
}
use byteorder::BigEndian;
use rom::Rom;
use types::Word;
use mem::{VirtualAddr};
pub struct Cart {
rom: Rom<BigEndian>
......@@ -10,7 +11,7 @@ impl Cart {
pub fn new(buf: Vec<u8>) -> Cart {
let mut rom = Rom::new(buf);
match rom.nth(0) {
match rom[0] {
0x37 => rom.byte_swap(),
0x40 => rom.endian_swap(),
_ => ()
......@@ -25,3 +26,9 @@ impl Cart {
self.rom.read_ascii_string(0x0020, 20)
}
}
impl Cart {
pub fn read_word(&self, addr: VirtualAddr) -> Word {
self.rom.read_word(addr as usize)
}
}
mod cart;
mod n64;
mod bus;
pub use self::cart::Cart;
pub use self::n64::N64;
use cpu::Cpu;
use mem::PhysicalAddr;
use pif_rom::PifRom;
use types::Word;
use super::bus::{Bus, Addr};
use super::cart::Cart;
pub struct N64<'a> {
cpu: Cpu,
bus: Bus,
pif_rom: PifRom,
cart: Option<&'a Cart>
}
impl<'a> N64<'a> {
pub fn new(pif_rom: PifRom) -> N64<'a> {
N64 {
cpu: Cpu::new(),
bus: Bus::new(),
pif_rom: pif_rom,
cart: None
}
}
pub fn insert_cart(&mut self, cart: &'a Cart) {
self.cart = Some(cart)
}
pub fn power_on(&mut self) {
self.cpu.power_on_reset()
}
pub fn step(&mut self) {
match self.cpu.next_instruction(|addr| self.read_word(addr)) {
Err(s) => println!("Error: {}", s),
Ok(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)
})
}
}
......@@ -2,6 +2,7 @@ use byteorder::BigEndian;
use rom::Rom;
use types::Word;
use mem::{VirtualAddr};
pub struct PifRom {
rom: Rom<BigEndian>
......@@ -13,8 +14,10 @@ impl PifRom {
rom: Rom::new(rom)
}
}
}
pub fn read_word(&self, i: u32) -> Word {
self.rom.read_word(i as usize)
impl PifRom {
pub fn read_word(&self, addr: VirtualAddr) -> Word {
self.rom.read_word(addr as usize)
}
}
......@@ -25,10 +25,6 @@ impl<T: ByteOrder> Rom<T> {
String::from_utf8_lossy(&self.buf[addr..addr+count]).trim_right_matches('\0').to_string()
}
pub fn nth(&self, addr: usize) -> u8 {
self.buf[addr]
}
pub fn byte_swap(&mut self) {
for addr in 0..self.buf.len() / 2 {
let x1 = self.buf[2*addr];
......
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