diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bin.rs | 38 | ||||
-rw-r--r-- | src/disasm.rs | 2 | ||||
-rw-r--r-- | src/lib.rs | 2 | ||||
-rw-r--r-- | src/memory.rs | 49 | ||||
-rw-r--r-- | src/mos6502.rs | 31 | ||||
-rw-r--r-- | src/ppu.rs | 47 |
6 files changed, 102 insertions, 67 deletions
@@ -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); @@ -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); } @@ -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 { |