aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bin.rs38
-rw-r--r--src/disasm.rs2
-rw-r--r--src/lib.rs2
-rw-r--r--src/memory.rs49
-rw-r--r--src/mos6502.rs31
-rw-r--r--src/ppu.rs47
6 files changed, 102 insertions, 67 deletions
diff --git a/src/bin.rs b/src/bin.rs
index a66b430..8ced9d7 100644
--- a/src/bin.rs
+++ b/src/bin.rs
@@ -1,17 +1,9 @@
extern crate core;
-mod memory;
-mod mos6502;
-mod ppu;
-mod cartridge;
-mod mapper;
-mod controller;
use std::fs::File;
use std::io::Read;
use core::cell::RefCell;
use core::intrinsics::transmute;
-use cartridge::*;
-use controller::stdctl;
use std::time::{Instant, Duration};
use std::thread::sleep;
@@ -23,6 +15,20 @@ use sdl2::pixels::PixelFormatEnum;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
+mod memory;
+#[macro_use] mod mos6502;
+mod ppu;
+mod cartridge;
+mod mapper;
+mod controller;
+mod disasm;
+
+use mos6502::CPU;
+use ppu::PPU;
+use memory::{CPUMemory, PPUMemory};
+use cartridge::{BankType, MirrorType, Cartridge};
+use controller::stdctl;
+
const PIXEL_SIZE: u32 = 2;
const RGB_COLORS: [u32; 64] = [
0x666666, 0x002a88, 0x1412a7, 0x3b00a4, 0x5c007e, 0x6e0040, 0x6c0600, 0x561d00,
@@ -289,17 +295,15 @@ fn main() {
};
let mt = m.get_cart().get_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);
+ let mut cpu = CPU::new(CPUMemory::new(&mapper, Some(&p1ctl), None));
+ let mut ppu = PPU::new(PPUMemory::new(&mapper, mt), &mut win);
+ let cpu_ptr = &mut cpu as *mut CPU;
+ cpu.mem.bus.attach(cpu_ptr, &mut ppu);
+ cpu.start();
loop {
- cpu.step();
while cpu.cycle > 0 {
- if ppu.tick() || ppu.tick() || ppu.tick() {
- cpu.trigger_delayed_nmi()
- }
- cpu.cycle -= 1;
+ cpu.mem.ppu_tick()
}
+ cpu.step();
}
}
diff --git a/src/disasm.rs b/src/disasm.rs
index c9b3696..22b71c6 100644
--- a/src/disasm.rs
+++ b/src/disasm.rs
@@ -1,4 +1,4 @@
-use mos6502::{make_optable, make_addrtable};
+#![allow(dead_code)]
mod disops {
make_optable!(OPS, &str);
diff --git a/src/lib.rs b/src/lib.rs
index 18ec0a0..266f8a6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,6 +1,6 @@
#![no_std]
mod memory;
-mod mos6502;
+#[macro_use] mod mos6502;
mod ppu;
mod cartridge;
mod mapper;
diff --git a/src/memory.rs b/src/memory.rs
index fb07ad5..0c07329 100644
--- a/src/memory.rs
+++ b/src/memory.rs
@@ -11,39 +11,64 @@ pub trait VMem {
fn write(&mut self, addr: u16, data: u8);
}
+pub struct Bus<'a> {
+ cpu: *mut CPU<'a>,
+ ppu: *mut PPU<'a>,
+}
+
+impl<'a> Bus<'a> {
+ pub fn new() -> Self {
+ Bus {ppu: null_mut(),
+ cpu: null_mut()}
+ }
+
+ pub fn attach(&mut self, cpu: *mut CPU<'a>, ppu: *mut PPU<'a>) {
+ self.ppu = ppu;
+ self.cpu = cpu;
+ }
+
+ #[inline(always)] fn get_cpu(&self) -> &'a mut CPU<'a> {unsafe{&mut *self.cpu}}
+ #[inline(always)] fn get_ppu(&self) -> &'a mut PPU<'a> {unsafe{&mut *self.ppu}}
+}
+
pub struct CPUMemory<'a> {
sram: [u8; 2048],
- ppu: *mut PPU<'a>,
- cpu: *mut CPU<'a>,
+ pub bus: Bus<'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>,
+ pub fn new(
mapper: &'a RefCell<&'a mut VMem>,
ctl1: Option<&'a Controller>,
ctl2: Option<&'a Controller>) -> Self {
CPUMemory{sram: [0; 2048],
- cpu: null_mut(),
- ppu: ppu,
+ bus: Bus::new(),
mapper, ctl1, ctl2}
}
- pub fn init(&mut self, cpu: *mut CPU<'a>) {
- self.cpu = cpu;
+ pub fn ppu_tick(&self) {
+ let cpu = self.bus.get_cpu();
+ let ppu = self.bus.get_ppu();
+ if ppu.tick() || ppu.tick() || ppu.tick() {
+ cpu.trigger_nmi();
+ }
+ cpu.cycle -= 1;
}
}
impl<'a> VMem for CPUMemory<'a> {
fn read(&self, addr: u16) -> u8 {
+ self.ppu_tick();
+ let cpu = self.bus.get_cpu();
+ let ppu = self.bus.get_ppu();
if addr < 0x2000 {
self.sram[(addr & 0x07ff) as usize]
} else if addr < 0x4000 {
- let ppu = unsafe {&mut *self.ppu};
match addr & 0x7 {
- 0x2 => ppu.read_status(),
+ 0x2 => ppu.read_status(cpu),
0x4 => ppu.read_oamdata(),
0x7 => ppu.read_data(),
_ => 0
@@ -62,8 +87,9 @@ impl<'a> VMem for CPUMemory<'a> {
}
fn write(&mut self, addr: u16, data: u8) {
- let ppu = unsafe {&mut *self.ppu};
- let cpu = unsafe {&mut *self.cpu};
+ self.ppu_tick();
+ let cpu = self.bus.get_cpu();
+ let ppu = self.bus.get_ppu();
if addr < 0x2000 {
self.sram[(addr & 0x07ff) as usize] = data;
} else if addr < 0x4000 {
@@ -76,6 +102,7 @@ impl<'a> VMem for CPUMemory<'a> {
} /* toggle NMI flag can generate multiple ints */
},
0x1 => ppu.write_mask(data),
+ 0x2 => (),
0x3 => ppu.write_oamaddr(data),
0x4 => ppu.write_oamdata(data),
0x5 => ppu.write_scroll(data),
diff --git a/src/mos6502.rs b/src/mos6502.rs
index f279a2a..9428171 100644
--- a/src/mos6502.rs
+++ b/src/mos6502.rs
@@ -3,6 +3,8 @@
use memory::{CPUMemory, VMem};
pub const CPU_FREQ: u32 = 1789773;
+
+#[macro_export]
macro_rules! make_optable {
($x:ident, $t: ty) => (pub const $x: [$t; 0x100] = [
/* 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf */
@@ -25,6 +27,7 @@ macro_rules! make_optable {
];);
}
+#[macro_export]
macro_rules! make_addrtable {
($x:ident, $t: ty) => (pub const $x: [$t; 0x100] = [
nil, xin, nil, xin, zpg, zpg, zpg, zpg, nil, imm, acc, imm, abs, abs, abs, abs,
@@ -564,13 +567,13 @@ mod addr {
}
fn xin(cpu: &mut CPU) -> u8 {
- cpu.ea = read16wrap!(cpu.mem,
- cpu.mem.read(cpu.opr)
- .wrapping_add(cpu.x) as u16) as u16; 0
+ let addr = cpu.mem.read(cpu.opr).wrapping_add(cpu.x) as u16;
+ cpu.ea = read16wrap!(cpu.mem, addr) as u16; 0
}
fn iny(cpu: &mut CPU) -> u8 {
- let base = read16wrap!(cpu.mem, cpu.mem.read(cpu.opr) as u16);
+ let addr = cpu.mem.read(cpu.opr) as u16;
+ let base = read16wrap!(cpu.mem, addr);
let sum = (base & 0xff) + (cpu.y as u16);
cpu.ea = (base & 0xff00).wrapping_add(sum);
(sum >> 8) as u8 /* boundary cross if carry */
@@ -609,13 +612,13 @@ macro_rules! make_int {
fn $f(&mut self) {
let pc = self.pc;
let sp = self.sp;
+ self.cycle += 7;
self.mem.write(stack_addr!(sp, 0), (pc >> 8) as u8);
self.mem.write(stack_addr!(sp, 1), pc as u8);
self.mem.write(stack_addr!(sp, 2), self.status);
self.sp = sp.wrapping_sub(3);
self.pc = read16!(self.mem, $v as u16);
self.status |= INT_FLAG;
- self.cycle += 7;
});
}
@@ -627,7 +630,7 @@ impl<'a> CPU<'a> {
#[inline(always)] pub fn get_neg(&self) -> u8 { (self.status >> 7) & 1 }
pub fn new(mem: CPUMemory<'a>) -> Self {
- let pc = read16!(mem, RESET_VECTOR as u16);
+ let pc = 0;
/* nes power up state */
let a = 0;
let x = 0;
@@ -644,6 +647,11 @@ impl<'a> CPU<'a> {
mem}
}
+ pub fn start(&mut self) {
+ self.cycle = 2;
+ self.pc = read16!(self.mem, RESET_VECTOR as u16);
+ }
+
make_int!(nmi, NMI_VECTOR);
make_int!(irq, IRQ_VECTOR);
@@ -657,9 +665,11 @@ impl<'a> CPU<'a> {
_ => ()
}
}
+ self.cycle += 1;
let pc = self.pc;
let opcode = self.mem.read(pc) as usize;
/*
+ use disasm;
let len = INST_LENGTH[opcode];
let mut code = vec![0; len as usize];
for i in 0..len as u16 {
@@ -675,10 +685,10 @@ impl<'a> CPU<'a> {
self.pc = pc.wrapping_add(INST_LENGTH[opcode] as u16);
/* get effective address based on addressing mode */
self.acc = false;
- let e = addr::ADDR_MODES[opcode](self) * INST_EXTRA_CYCLE[opcode];
+ self.cycle += INST_CYCLE[opcode] as u32 - 1;
+ self.cycle += (addr::ADDR_MODES[opcode](self) * INST_EXTRA_CYCLE[opcode]) as u32;
/* execute the inst */
ops::OPS[opcode](self);
- self.cycle += (INST_CYCLE[opcode] + e) as u32;
//(self.cycle - cycle0) as u8
}
@@ -699,6 +709,11 @@ impl<'a> CPU<'a> {
}
#[inline(always)]
+ pub fn suppress_nmi(&mut self) {
+ self.int = None;
+ }
+
+ #[inline(always)]
pub fn trigger_delayed_nmi(&mut self) {
self.int = Some(IntType::DelayedNMI);
}
diff --git a/src/ppu.rs b/src/ppu.rs
index 0fe1836..095e3e1 100644
--- a/src/ppu.rs
+++ b/src/ppu.rs
@@ -50,7 +50,7 @@ pub struct PPU<'a> {
sp_cnt: [u8; 8],
pub vblank: bool,
buffered_read: u8,
- early_read: Option<bool>,
+ early_read: bool,
/* IO */
mem: PPUMemory<'a>,
scr: &'a mut Screen,
@@ -71,14 +71,14 @@ impl<'a> PPU<'a> {
}
#[inline]
- pub fn read_status(&mut self) -> u8 {
+ pub fn read_status(&mut self, cpu: &mut CPU) -> u8 {
let res = (self.ppustatus & !0x1fu8) | (self.reg & 0x1f);
self.ppustatus &= !PPU::FLAG_VBLANK;
self.w = false;
if self.scanline == 241 {
match self.cycle {
- 1 => self.early_read = Some(true), /* read before cycle 1 */
- 2 | 3 => self.early_read = Some(false), /* read on cycle 1 and 2 */
+ 1 => self.early_read = true, /* read before cycle 1 */
+ 2 | 3 => cpu.suppress_nmi(),
_ => ()
}
}
@@ -175,6 +175,9 @@ impl<'a> PPU<'a> {
pub fn write_oamdma(&mut self, data: u8, cpu: &mut CPU) {
self.reg = data;
let mut addr = (data as u16) << 8;
+ cpu.cycle += 1;
+ cpu.cycle += cpu.cycle & 1;
+ cpu.cycle += 512;
unsafe {
let oam_raw = transmute::<&mut[Sprite; 64], &mut[u8; 256]>(&mut self.oam);
for _ in 0..0x100 {
@@ -183,9 +186,6 @@ impl<'a> PPU<'a> {
self.oamaddr = self.oamaddr.wrapping_add(1);
}
}
- cpu.cycle += 1;
- cpu.cycle += cpu.cycle & 1;
- cpu.cycle += 512;
}
#[inline(always)] fn get_spritesize(&self) -> u8 {(self.ppuctl >> 5) & 1}
@@ -449,8 +449,8 @@ impl<'a> PPU<'a> {
let ppustatus = 0xa0;
let oamaddr = 0x00;
let buffered_read = 0x00;
- let cycle = 0;
- let scanline = 261;
+ let cycle = 340;
+ let scanline = 240;
PPU {
scanline,
ppuctl,
@@ -469,7 +469,7 @@ impl<'a> PPU<'a> {
sp_cnt: [0; 8],
vblank: false,
buffered_read,
- early_read: None,
+ early_read: false,
mem, scr
}
}
@@ -546,26 +546,15 @@ impl<'a> PPU<'a> {
}
} else {
if !rendering { self.bg_pixel = 0 }
- if self.scanline == 241 {
- match cycle {
- 1 => {
- match self.early_read {
- Some(true) => (),
- _ => self.ppustatus |= PPU::FLAG_VBLANK
- }
- self.vblank = true;
- self.scr.render();
- self.cycle = 2;
- return false
- },
- 3 => {
- let b = self.early_read.is_none();
- self.early_read = None;
- self.cycle = 4;
- return b && self.try_nmi()
- },
- _ => ()
+ if self.scanline == 241 && self.cycle == 1 {
+ if !self.early_read {
+ self.ppustatus |= PPU::FLAG_VBLANK
}
+ self.early_read = false;
+ self.vblank = true;
+ self.scr.render();
+ self.cycle = 2;
+ return self.try_nmi()
}
}
if pre_line && cycle == 1 {