aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cartridge.rs25
-rw-r--r--src/main.rs128
-rw-r--r--src/mapper.rs84
-rw-r--r--src/memory.rs102
-rw-r--r--src/ppu.rs8
5 files changed, 172 insertions, 175 deletions
diff --git a/src/cartridge.rs b/src/cartridge.rs
index b8d2b68..0d21a42 100644
--- a/src/cartridge.rs
+++ b/src/cartridge.rs
@@ -1,5 +1,4 @@
#![allow(dead_code)]
-use core::cell::RefCell;
#[derive(Copy, Clone)]
pub enum MirrorType {
@@ -17,33 +16,31 @@ pub enum BankType {
}
pub struct Cartridge {
- chr_rom: RefCell<Vec<u8>>,
- prg_rom: RefCell<Vec<u8>>,
- sram: RefCell<Vec<u8>>,
+ chr_rom: Vec<u8>,
+ prg_rom: Vec<u8>,
+ sram: Vec<u8>,
pub mirror_type: MirrorType
}
impl Cartridge {
pub fn get_size(&self, kind: BankType) -> usize {
match kind {
- BankType::PrgRom => self.prg_rom.borrow().len(),
- BankType::ChrRom => self.chr_rom.borrow().len(),
- BankType::Sram => self.sram.borrow().len()
+ BankType::PrgRom => self.prg_rom.len(),
+ BankType::ChrRom => self.chr_rom.len(),
+ BankType::Sram => self.sram.len()
}
}
- pub fn get_bank(&self, base: usize, size: usize, kind: BankType) -> *mut [u8] {
+ pub fn get_bank(&mut self, base: usize, size: usize, kind: BankType) -> *mut [u8] {
&mut (match kind {
- BankType::PrgRom => self.prg_rom.borrow_mut(),
- BankType::ChrRom => self.chr_rom.borrow_mut(),
- BankType::Sram => self.sram.borrow_mut(),
+ BankType::PrgRom => &mut self.prg_rom,
+ BankType::ChrRom => &mut self.chr_rom,
+ BankType::Sram => &mut self.sram,
})[base..base + size]
}
pub fn new(chr_rom: Vec<u8>,
prg_rom: Vec<u8>,
sram: Vec<u8>,
mirror_type: MirrorType) -> Self {
- Cartridge{chr_rom: RefCell::new(chr_rom),
- prg_rom: RefCell::new(prg_rom),
- sram: RefCell::new(sram), mirror_type}
+ Cartridge{chr_rom, prg_rom, sram, mirror_type}
}
}
diff --git a/src/main.rs b/src/main.rs
index 45bece5..6a350ff 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -8,7 +8,7 @@ mod controller;
use std::fs::File;
use std::io::Read;
-use core::cell::{Cell, RefCell, UnsafeCell};
+use core::cell::RefCell;
use core::intrinsics::transmute;
use cartridge::*;
use controller::stdctl::{Joystick, Button};
@@ -43,15 +43,15 @@ const WIN_WIDTH: u32 = PIX_WIDTH as u32 * PIXEL_SIZE;
const WIN_HEIGHT: u32 = PIX_HEIGHT as u32 * PIXEL_SIZE;
struct SDLWindow<'a> {
- canvas: UnsafeCell<sdl2::render::WindowCanvas>,
- events: UnsafeCell<sdl2::EventPump>,
- frame_buffer: UnsafeCell<[u8; FB_SIZE]>,
- texture: UnsafeCell<sdl2::render::Texture>,
- timer: Cell<Instant>,
+ canvas: sdl2::render::WindowCanvas,
+ events: sdl2::EventPump,
+ frame_buffer: [u8; FB_SIZE],
+ texture: sdl2::render::Texture,
+ timer: Instant,
duration_per_frame: Duration,
- p1_button_states: UnsafeCell<[bool; 8]>,
+ p1_button_states: [bool; 8],
p1_ctl: &'a Joystick,
- p1_keymap: UnsafeCell<[Button; 256]>,
+ p1_keymap: [Button; 256],
}
macro_rules! gen_keymap {
@@ -81,41 +81,42 @@ impl<'a> SDLWindow<'a> {
canvas.set_draw_color(Color::RGB(255, 255, 255));
canvas.clear();
canvas.present();
- let res = SDLWindow {
- canvas: UnsafeCell::new(canvas),
- events: UnsafeCell::new(sdl_context.event_pump().unwrap()),
- frame_buffer: UnsafeCell::new([0; FB_SIZE]),
- texture: UnsafeCell::new(texture_creator.create_texture_streaming(
- PixelFormatEnum::RGB24, WIN_WIDTH, WIN_HEIGHT).unwrap()),
- timer: Cell::new(Instant::now()),
+ let mut res = SDLWindow {
+ canvas,
+ events: sdl_context.event_pump().unwrap(),
+ frame_buffer: [0; FB_SIZE],
+ texture: texture_creator.create_texture_streaming(
+ PixelFormatEnum::RGB24, WIN_WIDTH, WIN_HEIGHT).unwrap(),
+ timer: Instant::now(),
duration_per_frame: Duration::from_millis(1000 / 60),
- p1_button_states: UnsafeCell::new([false; 8]),
- p1_ctl, p1_keymap: UnsafeCell::new([Button::Null; 256])
+ p1_button_states: [false; 8],
+ p1_ctl, p1_keymap: [Button::Null; 256]
};
- let keymap = unsafe{&mut *res.p1_keymap.get()};
- gen_keymap!(keymap, [I, Button::Up,
- K, Button::Down,
- J, Button::Left,
- L, Button::Right,
- Z, Button::A,
- X, Button::B,
- Return, Button::Start,
- S, Button::Select,
- Up, Button::Up,
- Down, Button::Down,
- Left, Button::Left,
- Right, Button::Right
- ]);
+ {
+ let keymap = &mut res.p1_keymap;
+ gen_keymap!(keymap, [I, Button::Up,
+ K, Button::Down,
+ J, Button::Left,
+ L, Button::Right,
+ Z, Button::A,
+ X, Button::B,
+ Return, Button::Start,
+ S, Button::Select,
+ Up, Button::Up,
+ Down, Button::Down,
+ Left, Button::Left,
+ Right, Button::Right
+ ]);
+ }
res
}
#[inline]
- fn poll(&self) -> bool {
+ fn poll(&mut self) -> bool {
use Keycode::*;
- let p1_button_states = unsafe {&mut *self.p1_button_states.get()};
- let p1_keymap = unsafe {&mut *self.p1_keymap.get()};
- let events = unsafe {&mut *self.events.get()};
- for event in events.poll_iter() {
+ let p1_button_states = &mut self.p1_button_states;
+ let p1_keymap = &self.p1_keymap;
+ for event in self.events.poll_iter() {
match event {
Event::Quit {..} | Event::KeyDown { keycode: Some(Escape), .. } => {
return true;
@@ -152,35 +153,30 @@ fn get_rgb(color: u8) -> (u8, u8, u8) {
}
impl<'a> ppu::Screen for SDLWindow<'a> {
- fn put(&self, x: u8, y: u8, color: u8) {
- unsafe {
- let (r, g, b) = get_rgb(color);
- let mut base = ((y as u32 * PIXEL_SIZE) as usize * FB_PITCH) +
- (x as u32 * 3 * PIXEL_SIZE) as usize;
+ fn put(&mut self, x: u8, y: u8, color: u8) {
+ let (r, g, b) = get_rgb(color);
+ let mut base = ((y as u32 * PIXEL_SIZE) as usize * FB_PITCH) +
+ (x as u32 * 3 * PIXEL_SIZE) as usize;
+ for _ in 0..PIXEL_SIZE {
+ let slice = &mut self.frame_buffer[base..base + 3 * PIXEL_SIZE as usize];
+ let mut j = 0;
for _ in 0..PIXEL_SIZE {
- let slice = &mut (*self.frame_buffer.get())[base..base + 3 * PIXEL_SIZE as usize];
- let mut j = 0;
- for _ in 0..PIXEL_SIZE {
- slice[j] = r;
- slice[j + 1] = g;
- slice[j + 2] = b;
- j += 3;
- }
- base += FB_PITCH;
+ slice[j] = r;
+ slice[j + 1] = g;
+ slice[j + 2] = b;
+ j += 3;
}
+ base += FB_PITCH;
}
}
- fn render(&self) {
- let canvas = unsafe{&mut *self.canvas.get()};
- let fb = unsafe{&*self.frame_buffer.get()};
- let texture = unsafe{&mut *self.texture.get()};
- texture.update(None, fb, FB_PITCH).unwrap();
- canvas.clear();
- canvas.copy(&texture, None, Some(Rect::new(0, 0, WIN_WIDTH, WIN_HEIGHT))).unwrap();
- canvas.present();
+ fn render(&mut self) {
+ self.texture.update(None, &self.frame_buffer, FB_PITCH).unwrap();
+ self.canvas.clear();
+ self.canvas.copy(&self.texture, None, Some(Rect::new(0, 0, WIN_WIDTH, WIN_HEIGHT))).unwrap();
+ self.canvas.present();
if self.poll() {std::process::exit(0);}
- let e = self.timer.get().elapsed();
+ let e = self.timer.elapsed();
if self.duration_per_frame > e {
let diff = self.duration_per_frame - e;
sleep(diff);
@@ -188,7 +184,7 @@ impl<'a> ppu::Screen for SDLWindow<'a> {
} else {
//println!("{} slower", (e - duration_per_frame).subsec_nanos() as f64 / 1e6);
}
- self.timer.set(Instant::now());
+ self.timer = Instant::now();
//canvas.set_draw_color(Color::RGB(128, 128, 128));
}
}
@@ -262,15 +258,15 @@ fn main() {
}
}
*/
- let cart = cartridge::Cartridge::new(chr_rom, prg_rom, sram, mirror);
let p1ctl = Joystick::new();
- let win = SDLWindow::new(&p1ctl);
- let mapper = match mapper_id {
- 0 | 2 => mapper::Mapper2::new(&cart),
+ let mut win = SDLWindow::new(&p1ctl);
+ let mut m = match mapper_id {
+ 0 | 2 => mapper::Mapper2::new(cartridge::Cartridge::new(chr_rom, prg_rom, sram, mirror)),
_ => panic!("unsupported mapper {}", mapper_id)
};
-
- let mut ppu = ppu::PPU::new(memory::PPUMemory::new(&mapper, &cart), &win);
+ let mt = m.get_cart().mirror_type;
+ let mapper = RefCell::new(&mut m as &mut memory::VMem);
+ let mut ppu = ppu::PPU::new(memory::PPUMemory::new(&mapper, mt), &mut win);
let mut cpu = mos6502::CPU::new(memory::CPUMemory::new(&mut ppu, &mapper, Some(&p1ctl), None));
let ptr = &mut cpu as *mut mos6502::CPU;
cpu.mem.init(ptr);
diff --git a/src/mapper.rs b/src/mapper.rs
index 210b59f..fc02ed2 100644
--- a/src/mapper.rs
+++ b/src/mapper.rs
@@ -1,64 +1,72 @@
#![allow(dead_code)]
+extern crate core;
use memory::VMem;
use cartridge::{Cartridge, BankType};
-use core::cell::UnsafeCell;
pub struct Mapper2<'a> {
- cart: &'a Cartridge,
- prg_bank1: UnsafeCell<&'a [u8]>,
- prg_bank2: UnsafeCell<&'a [u8]>,
- chr_bank: UnsafeCell<&'a mut [u8]>,
- sram: UnsafeCell<&'a mut [u8]>,
+ cart: Cartridge,
+ prg_bank1: &'a [u8],
+ prg_bank2: &'a [u8],
+ chr_bank: &'a mut [u8],
+ sram: &'a mut [u8],
prg_nbank: usize
}
impl<'a> VMem for Mapper2<'a> {
fn read(&self, addr: u16) -> u8 {
let addr = addr as usize;
- unsafe {
- if addr < 0x2000 { /* 0x2000 size bank */
- (*self.chr_bank.get())[addr]
- } else if addr >= 0xc000 { /* 0x4000 size bank */
- (*self.prg_bank2.get())[addr - 0xc000]
- } else if addr >= 0x8000 { /* 0x4000 size bank */
- (*self.prg_bank1.get())[addr - 0x8000]
- } else if addr >= 0x6000 {
- (*self.sram.get())[addr - 0x6000]
- } else {
- panic!("unmapped address: 0x{:04x}", addr)
- }
+ if addr < 0x2000 { /* 0x2000 size bank */
+ self.chr_bank[addr]
+ } else if addr >= 0xc000 { /* 0x4000 size bank */
+ self.prg_bank2[addr - 0xc000]
+ } else if addr >= 0x8000 { /* 0x4000 size bank */
+ self.prg_bank1[addr - 0x8000]
+ } else if addr >= 0x6000 {
+ self.sram[addr - 0x6000]
+ } else {
+ panic!("unmapped address: 0x{:04x}", addr)
}
}
- fn write(&self, addr: u16, data: u8) {
+ fn write(&mut self, addr: u16, data: u8) {
let addr = addr as usize;
- unsafe {
- if addr < 0x2000 {
- (*self.chr_bank.get())[addr] = data;
- } else if addr >= 0x8000 {
- (*self.prg_bank1.get()) =
- &*self.cart.get_bank(((data as usize) % self.prg_nbank) << 14,
- 0x4000,
- BankType::PrgRom);
- } else if addr >= 0x6000 {
- (*self.sram.get())[addr - 0x6000] = data;
- } else {
- panic!("invalid write to address: 0x{:04x}", addr);
+ if addr < 0x2000 {
+ self.chr_bank[addr] = data;
+ } else if addr >= 0x8000 {
+ self.prg_bank1 = unsafe {
+ &*self.cart.get_bank(((data as usize) % self.prg_nbank) << 14,
+ 0x4000,
+ BankType::PrgRom)
}
+ } else if addr >= 0x6000 {
+ self.sram[addr - 0x6000] = data
+ } else {
+ panic!("invalid write to address: 0x{:04x}", addr);
}
}
}
impl<'a> Mapper2<'a> {
- pub fn new(cart: &'a Cartridge) -> Self {
+ pub fn new(cart: Cartridge) -> Self {
unsafe {
let nbank = cart.get_size(BankType::PrgRom) >> 14;
- Mapper2{cart,
- prg_bank1: UnsafeCell::new(&*cart.get_bank(0, 0x4000, BankType::PrgRom)),
- prg_bank2: UnsafeCell::new(&*cart.get_bank((nbank - 1) << 14, 0x4000, BankType::PrgRom)),
- chr_bank: UnsafeCell::new(&mut *cart.get_bank(0, 0x2000, BankType::ChrRom)),
- sram: UnsafeCell::new(&mut *cart.get_bank(0, 0x2000, BankType::Sram)),
- prg_nbank: nbank}
+ let null = core::mem::uninitialized();
+ let mut m = Mapper2{cart,
+ prg_nbank: nbank,
+ prg_bank1: null,
+ prg_bank2: null,
+ chr_bank: core::mem::uninitialized(),
+ sram: core::mem::uninitialized()};
+ {
+ let c = &mut m.cart;
+ m.prg_bank1 = &*c.get_bank(0, 0x4000, BankType::PrgRom);
+ m.prg_bank2 = &*c.get_bank((nbank - 1) << 14, 0x4000, BankType::PrgRom);
+ m.chr_bank = &mut *c.get_bank(0, 0x2000, BankType::ChrRom);
+ m.sram = &mut *c.get_bank(0, 0x2000, BankType::Sram);
+ }
+ m
}
}
+
+ pub fn get_cart(&self) -> &Cartridge {&self.cart}
}
diff --git a/src/memory.rs b/src/memory.rs
index f8b6632..6a62678 100644
--- a/src/memory.rs
+++ b/src/memory.rs
@@ -1,47 +1,47 @@
#![allow(dead_code)]
use ppu::PPU;
use mos6502::CPU;
-use cartridge::{MirrorType, Cartridge};
+use cartridge::MirrorType;
use controller::Controller;
-use core::cell::{UnsafeCell, Cell};
+use core::cell::RefCell;
use core::ptr::null_mut;
pub trait VMem {
fn read(&self, addr: u16) -> u8;
- fn write(&self, addr: u16, data: u8);
+ fn write(&mut self, addr: u16, data: u8);
}
pub struct CPUMemory<'a> {
- sram: UnsafeCell<[u8; 2048]>,
- ppu: Cell<*mut PPU<'a>>,
- cpu: Cell<*mut CPU<'a>>,
- mapper: &'a VMem,
+ sram: [u8; 2048],
+ ppu: *mut PPU<'a>,
+ cpu: *mut CPU<'a>,
+ mapper: &'a RefCell<&'a mut VMem>,
ctl1: Option<&'a Controller>,
ctl2: Option<&'a Controller>
}
impl<'a> CPUMemory<'a> {
pub fn new(ppu: &mut PPU<'a>,
- mapper: &'a VMem,
+ mapper: &'a RefCell<&'a mut VMem>,
ctl1: Option<&'a Controller>,
ctl2: Option<&'a Controller>) -> Self {
- CPUMemory{sram: UnsafeCell::new([0; 2048]),
- cpu: Cell::new(null_mut()),
- ppu: Cell::new(ppu),
+ CPUMemory{sram: [0; 2048],
+ cpu: null_mut(),
+ ppu: ppu,
mapper, ctl1, ctl2}
}
- pub fn init(&self, cpu: *mut CPU<'a>) {
- self.cpu.set(cpu);
+ pub fn init(&mut self, cpu: *mut CPU<'a>) {
+ self.cpu = cpu;
}
}
impl<'a> VMem for CPUMemory<'a> {
fn read(&self, addr: u16) -> u8 {
if addr < 0x2000 {
- unsafe{(*self.sram.get())[(addr & 0x07ff) as usize]}
+ self.sram[(addr & 0x07ff) as usize]
} else if addr < 0x4000 {
- let ppu = unsafe {&mut *self.ppu.get()};
+ let ppu = unsafe {&mut *self.ppu};
match addr & 0x7 {
0x2 => ppu.read_status(),
0x4 => ppu.read_oamdata(),
@@ -57,15 +57,15 @@ impl<'a> VMem for CPUMemory<'a> {
} else if addr < 0x6000 {
0
} else {
- self.mapper.read(addr)
+ self.mapper.borrow().read(addr)
}
}
- fn write(&self, addr: u16, data: u8) {
- let ppu = unsafe {&mut *self.ppu.get()};
- let cpu = unsafe {&mut *self.cpu.get()};
+ fn write(&mut self, addr: u16, data: u8) {
+ let ppu = unsafe {&mut *self.ppu};
+ let cpu = unsafe {&mut *self.cpu};
if addr < 0x2000 {
- unsafe{(*self.sram.get())[(addr & 0x07ff) as usize] = data;}
+ self.sram[(addr & 0x07ff) as usize] = data;
} else if addr < 0x4000 {
match addr & 0x7 {
0x0 => {
@@ -94,38 +94,36 @@ impl<'a> VMem for CPUMemory<'a> {
}
} else if addr < 0x6000 {
} else {
- self.mapper.write(addr, data)
+ self.mapper.borrow_mut().write(addr, data)
}
}
}
pub struct PPUMemory<'a> {
- nametable: UnsafeCell<[u8; 0x800]>,
- palette: UnsafeCell<[u8; 0x20]>,
- cart: &'a Cartridge,
- mapper: &'a VMem,
+ nametable: [u8; 0x800],
+ palette: [u8; 0x20],
+ mirror_type: MirrorType,
+ mapper: &'a RefCell<&'a mut VMem>,
}
impl<'a> PPUMemory<'a> {
- pub fn new(mapper: &'a VMem,
- cart: &'a Cartridge) -> Self {
+ pub fn new(mapper: &'a RefCell<&'a mut VMem>,
+ mirror_type: MirrorType) -> Self {
PPUMemory{
- nametable: UnsafeCell::new([0; 0x800]),
- palette: UnsafeCell::new([0; 0x20]),
- cart,
+ nametable: [0; 0x800],
+ palette: [0; 0x20],
+ mirror_type,
mapper}
}
pub fn dump(&self) {
- unsafe {
- for (i, v) in (*self.palette.get()).iter().enumerate() {
- print!("{:02x} ", *v);
- if (i & 0x7) == 0x7 {println!("@{:02x}", i)}
- }
- for (i, v) in (*self.nametable.get()).iter().enumerate() {
- print!("{:02x} ", *v);
- if (i & 0x1f) == 0x1f {println!("@{:02x}", i)}
- }
+ for (i, v) in self.palette.iter().enumerate() {
+ print!("{:02x} ", *v);
+ if (i & 0x7) == 0x7 {println!("@{:02x}", i)}
+ }
+ for (i, v) in self.nametable.iter().enumerate() {
+ print!("{:02x} ", *v);
+ if (i & 0x1f) == 0x1f {println!("@{:02x}", i)}
}
}
}
@@ -155,34 +153,32 @@ fn get_mirror_palette(addr: u16) -> u16 {
impl<'a> PPUMemory<'a> {
#[inline(always)]
pub fn read_nametable(&self, addr: u16) -> u8 {
- let kind = self.cart.mirror_type;
- unsafe {(*self.nametable.get())[(get_mirror_addr(kind, addr) & 0x7ff) as usize]}
+ self.nametable[(get_mirror_addr(self.mirror_type, addr) & 0x7ff) as usize]
}
#[inline(always)]
- pub fn read_palette(&self, addr: u16) -> u8 { unsafe {
- (*self.palette.get())[get_mirror_palette(addr) as usize]
- }}
+ pub fn read_palette(&self, addr: u16) -> u8 {
+ self.palette[get_mirror_palette(addr) as usize]
+ }
#[inline(always)]
- pub fn write_nametable(&self, addr: u16, data: u8) {
- let kind = self.cart.mirror_type;
- unsafe {(*self.nametable.get())[(get_mirror_addr(kind, addr) & 0x7ff) as usize] = data}
+ pub fn write_nametable(&mut self, addr: u16, data: u8) {
+ self.nametable[(get_mirror_addr(self.mirror_type, addr) & 0x7ff) as usize] = data
}
#[inline(always)]
- pub fn write_palette(&self, addr: u16, data: u8) { unsafe {
- (*self.palette.get())[get_mirror_palette(addr) as usize] = data;
- }}
+ pub fn write_palette(&mut self, addr: u16, data: u8) {
+ self.palette[get_mirror_palette(addr) as usize] = data
+ }
#[inline(always)]
pub fn read_mapper(&self, addr: u16) -> u8 {
- self.mapper.read(addr)
+ self.mapper.borrow().read(addr)
}
#[inline(always)]
fn write_mapper(&self, addr: u16, data: u8) {
- self.mapper.write(addr, data);
+ self.mapper.borrow_mut().write(addr, data);
}
}
@@ -200,7 +196,7 @@ impl<'a> VMem for PPUMemory<'a> {
}
}
- fn write(&self, mut addr: u16, data: u8) {
+ fn write(&mut self, mut addr: u16, data: u8) {
addr &= 0x3fff;
if addr < 0x2000 {
self.write_mapper(addr, data);
diff --git a/src/ppu.rs b/src/ppu.rs
index 928fe7f..0fe1836 100644
--- a/src/ppu.rs
+++ b/src/ppu.rs
@@ -5,8 +5,8 @@ use core::intrinsics::transmute;
pub trait Screen {
#[inline(always)]
- fn put(&self, x: u8, y: u8, color: u8);
- fn render(&self);
+ fn put(&mut self, x: u8, y: u8, color: u8);
+ fn render(&mut self);
}
#[repr(C, packed)]
@@ -53,7 +53,7 @@ pub struct PPU<'a> {
early_read: Option<bool>,
/* IO */
mem: PPUMemory<'a>,
- scr: &'a Screen,
+ scr: &'a mut Screen,
}
impl<'a> PPU<'a> {
@@ -443,7 +443,7 @@ impl<'a> PPU<'a> {
}));
}
- pub fn new(mem: PPUMemory<'a>, scr: &'a Screen) -> Self {
+ pub fn new(mem: PPUMemory<'a>, scr: &'a mut Screen) -> Self {
let ppuctl = 0x00;
let ppumask = 0x00;
let ppustatus = 0xa0;