aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml1
-rw-r--r--src/cartridge.rs37
-rw-r--r--src/main.rs175
-rw-r--r--src/mapper.rs55
-rw-r--r--src/memory.rs86
-rw-r--r--src/mos6502.rs75
-rw-r--r--src/ppu.rs96
7 files changed, 358 insertions, 167 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 9f9157d..9718582 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,3 +4,4 @@ version = "0.1.0"
authors = ["Determinant <[email protected]>"]
[dependencies]
+sdl2 = "0.31"
diff --git a/src/cartridge.rs b/src/cartridge.rs
index f96c234..b8d2b68 100644
--- a/src/cartridge.rs
+++ b/src/cartridge.rs
@@ -1,3 +1,4 @@
+#![allow(dead_code)]
use core::cell::RefCell;
#[derive(Copy, Clone)]
@@ -16,23 +17,33 @@ pub enum BankType {
}
pub struct Cartridge {
- chr_rom: [u8; 8192],
- prg_rom: RefCell<[u8; 8192]>,
- sram: [u8; 8192],
+ chr_rom: RefCell<Vec<u8>>,
+ prg_rom: RefCell<Vec<u8>>,
+ sram: RefCell<Vec<u8>>,
pub mirror_type: MirrorType
}
impl Cartridge {
- pub fn get_bank_num(&self, kind: BankType) -> usize {0}
- pub fn get_bank(&self, idx: usize, kind: BankType) -> *mut [u8] {
- &mut *self.prg_rom.borrow_mut()
- }
- pub fn new() -> Self {
- Cartridge {
- chr_rom: [0; 8192],
- prg_rom: RefCell::new([0; 8192]),
- sram: [0; 8192],
- mirror_type: MirrorType::Horizontal
+ 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()
}
}
+ pub fn get_bank(&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(),
+ })[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}
+ }
}
diff --git a/src/main.rs b/src/main.rs
index 447fa85..cd39d39 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -4,24 +4,181 @@ mod mos6502;
mod ppu;
mod cartridge;
mod mapper;
-use core::ptr::null_mut;
+
+use std::fs::File;
+use std::io::Read;
+use core::cell::RefCell;
+use core::intrinsics::transmute;
+use cartridge::*;
+
+
+extern crate sdl2;
+
+use sdl2::pixels::Color;
+use sdl2::rect::Rect;
struct Window {
+ buff: RefCell<[[u8; 256]; 240]>
}
impl ppu::Screen for Window {
- fn put(&mut self, x: u8, y: u8, color: u8) {
- println!("put color 0x{:02x} at ({}, {})", color, x, y);
+ fn put(&self, x: u8, y: u8, color: u8) {
+ self.buff.borrow_mut()[y as usize][x as usize] = color;
}
fn render(&self) {
- println!("a frame has been redrawn");
+ println!("a frame has been redrawn:");
+ for r in self.buff.borrow().iter() {
+ for c in r.iter() {
+ print!("{:02x}", c);
+ }
+ println!("");
+ }
+ }
+}
+
+struct SDLWindow {
+ canvas: RefCell<sdl2::render::WindowCanvas>
+}
+
+impl SDLWindow {
+ fn new() -> Self {
+ let sdl_context = sdl2::init().unwrap();
+ let video_subsystem = sdl_context.video().unwrap();
+ let window = video_subsystem.window("rust-sdl2 demo: Video", 256 * PIXEL_SIZE, 240 * PIXEL_SIZE)
+ .position_centered()
+ .opengl()
+ .build()
+ .unwrap();
+ let mut canvas = window.into_canvas().build().unwrap();
+ canvas.set_draw_color(Color::RGB(255, 255, 255));
+ canvas.clear();
+ canvas.present();
+ SDLWindow {
+ canvas: RefCell::new(canvas)
+ }
}
}
+const PIXEL_SIZE: u32 = 2;
+const COLORS: [u32; 64] = [
+ 0x666666, 0x002A88, 0x1412A7, 0x3B00A4, 0x5C007E, 0x6E0040, 0x6C0600, 0x561D00,
+ 0x333500, 0x0B4800, 0x005200, 0x004F08, 0x00404D, 0x000000, 0x000000, 0x000000,
+ 0xADADAD, 0x155FD9, 0x4240FF, 0x7527FE, 0xA01ACC, 0xB71E7B, 0xB53120, 0x994E00,
+ 0x6B6D00, 0x388700, 0x0C9300, 0x008F32, 0x007C8D, 0x000000, 0x000000, 0x000000,
+ 0xFFFEFF, 0x64B0FF, 0x9290FF, 0xC676FF, 0xF36AFF, 0xFE6ECC, 0xFE8170, 0xEA9E22,
+ 0xBCBE00, 0x88D800, 0x5CE430, 0x45E082, 0x48CDDE, 0x4F4F4F, 0x000000, 0x000000,
+ 0xFFFEFF, 0xC0DFFF, 0xD3D2FF, 0xE8C8FF, 0xFBC2FF, 0xFEC4EA, 0xFECCC5, 0xF7D8A5,
+ 0xE4E594, 0xCFEF96, 0xBDF4AB, 0xB3F3CC, 0xB5EBF2, 0xB8B8B8, 0x000000, 0x000000,
+];
+
+fn get_rgb(color: u8) -> Color {
+ let c = COLORS[color as usize];
+ Color::RGB((c >> 16) as u8, ((c >> 8) & 0xff) as u8, (c & 0xff) as u8)
+}
+
+impl ppu::Screen for SDLWindow {
+ fn put(&self, x: u8, y: u8, color: u8) {
+ let mut canvas = self.canvas.borrow_mut();
+ println!("put {} at {}, {}", color, x, y);
+ canvas.set_draw_color(get_rgb(color));
+ canvas.draw_rect(Rect::new((x as u32 * PIXEL_SIZE) as i32,
+ (y as u32 * PIXEL_SIZE) as i32,
+ PIXEL_SIZE, PIXEL_SIZE));
+ }
+
+ fn render(&self) {
+ let mut canvas = self.canvas.borrow_mut();
+ canvas.present();
+ canvas.clear();
+ }
+}
+
+#[repr(C, packed)]
+struct INesHeader {
+ magic: [u8; 4],
+ prg_rom_nbanks: u8,
+ chr_rom_nbanks: u8,
+ flags6: u8,
+ flags7: u8,
+ prg_ram_nbanks: u8,
+ flags9: u8,
+ flags10: u8,
+ padding: [u8; 5]
+}
+
fn main() {
- //let mut ppu = ppu::PPU::new(
- let mut cart = cartridge::Cartridge::new();
- let mut mapper = mapper::Mapper2::new(&mut cart);
- let mut mem = memory::CPUMemory::new(null_mut(), null_mut(), &mut mapper);
- let cpu = mos6502::CPU::new(&mut mem);
+ let fname = std::env::args().nth(1).unwrap();
+ let mut file = File::open(fname).unwrap();
+ let mut rheader = [0; 16];
+ println!("read {}", file.read(&mut rheader[..]).unwrap());
+ let header = unsafe{transmute::<[u8; 16], INesHeader>(rheader)};
+ let mirror = match ((header.flags6 >> 2) & 2) | (header.flags6 & 1) {
+ 0 => MirrorType::Horizontal,
+ 1 => MirrorType::Vertical,
+ 2 => MirrorType::Single0,
+ 3 => MirrorType::Single1,
+ _ => MirrorType::Four,
+ };
+ let mapper_id = (header.flags7 & 0xf0) | (header.flags6 >> 4);
+ println!("maigc:{} prg:{} chr:{} mirror:{} mapper:{}",
+ std::str::from_utf8(&header.magic).unwrap(),
+ header.prg_rom_nbanks,
+ header.chr_rom_nbanks,
+ mirror as u8,
+ mapper_id);
+ if header.flags6 & 0x04 == 0x04 {
+ let mut trainer: [u8; 512] = unsafe{std::mem::uninitialized()};
+ file.read(&mut trainer[..]);
+ println!("skipping trainer");
+ }
+
+ let prg_len = header.prg_rom_nbanks as usize * 0x4000;
+ let mut chr_len = header.chr_rom_nbanks as usize * 0x2000;
+ if chr_len == 0 {
+ chr_len = 0x2000;
+ }
+ let mut prg_rom = Vec::<u8>::with_capacity(prg_len);
+ let mut chr_rom = Vec::<u8>::with_capacity(chr_len);
+ unsafe {
+ prg_rom.set_len(prg_len);
+ chr_rom.set_len(chr_len);
+ }
+ let sram = vec![0; 0x4000];
+ println!("read prg {}", file.read(&mut prg_rom[..]).unwrap());
+ for (i, v) in prg_rom.iter().enumerate() {
+ print!("{:02x} ", v);
+ if i & 15 == 15 {
+ println!(" {:04x}", i);
+ }
+ }
+ println!("read chr {}", file.read(&mut chr_rom[..]).unwrap());
+ for (i, v) in chr_rom.iter().enumerate() {
+ print!("{:02x} ", v);
+ if i & 15 == 15 {
+ println!("");
+ }
+ }
+ let cart = cartridge::Cartridge::new(chr_rom, prg_rom, sram, mirror);
+ //let win = Window {buff: RefCell::new([[0; 256]; 240])};
+ let win = SDLWindow::new();
+ let mapper = mapper::Mapper2::new(&cart);
+ let pmem = memory::PPUMemory::new(&mapper, &cart);
+ let mem = memory::CPUMemory::new(&mapper);
+ let mut ppu = ppu::PPU::new(&pmem, &win);
+ let mut cpu = mos6502::CPU::new(&mem);
+ mem.init(&mut cpu, &mut ppu);
+
+ loop {
+ cpu.step();
+ //println!("cpu at 0x{:04x}", cpu.get_pc());
+ while cpu.cycle > 0 {
+ for _ in 0..3 {
+ if ppu.tick() {
+ println!("triggering nmi");
+ cpu.trigger_nmi();
+ }
+ }
+ cpu.cycle -= 1;
+ }
+ }
}
diff --git a/src/mapper.rs b/src/mapper.rs
index 7522454..c54acb4 100644
--- a/src/mapper.rs
+++ b/src/mapper.rs
@@ -1,40 +1,44 @@
#![allow(dead_code)]
use memory::VMem;
use cartridge::{Cartridge, BankType};
+use core::cell::RefCell;
+
pub struct Mapper2<'a> {
cart: &'a Cartridge,
- prg_bank1: &'a [u8],
- prg_bank2: &'a [u8],
- chr_bank: &'a mut [u8],
- sram: &'a mut [u8],
- bank_num: usize
+ prg_bank1: RefCell<&'a [u8]>,
+ prg_bank2: RefCell<&'a [u8]>,
+ chr_bank: RefCell<&'a mut [u8]>,
+ sram: RefCell<&'a mut [u8]>,
+ prg_nbank: usize
}
impl<'a> VMem for Mapper2<'a> {
fn read(&self, addr: u16) -> u8 {
let addr = addr as usize;
- if addr < 0x2000 {
- self.chr_bank[addr]
- } else if addr >= 0xc000 {
- self.prg_bank2[addr - 0xc000]
- } else if addr >= 0x8000 {
- self.prg_bank1[addr - 0x8000]
+ if addr < 0x2000 { /* 0x2000 size bank */
+ self.chr_bank.borrow()[addr]
+ } else if addr >= 0xc000 { /* 0x4000 size bank */
+ self.prg_bank2.borrow()[addr - 0xc000]
+ } else if addr >= 0x8000 { /* 0x4000 size bank */
+ self.prg_bank1.borrow()[addr - 0x8000]
} else if addr >= 0x6000 {
- self.sram[addr - 0x6000]
+ self.sram.borrow()[addr - 0x6000]
} else {
panic!("unmapped address: 0x{:04x}", addr)
}
}
- fn write(&mut self, addr: u16, data: u8) {
+ fn write(&self, addr: u16, data: u8) {
let addr = addr as usize;
if addr < 0x2000 {
- self.chr_bank[addr] = data;
+ self.chr_bank.borrow_mut()[addr] = data;
} else if addr >= 0x8000 {
- self.prg_bank1 = unsafe {&*self.cart.get_bank(
- data as usize % self.bank_num, BankType::PrgRom)};
+ (*self.prg_bank1.borrow_mut()) = unsafe {
+ &*self.cart.get_bank(((data as usize) % self.prg_nbank) << 14,
+ 0x4000,
+ BankType::PrgRom)};
} else if addr >= 0x6000 {
- self.sram[addr - 0x6000] = data;
+ self.sram.borrow_mut()[addr - 0x6000] = data;
} else {
panic!("invalid write to address: 0x{:04x}", addr);
}
@@ -42,15 +46,16 @@ impl<'a> VMem for Mapper2<'a> {
}
impl<'a> Mapper2<'a> {
- pub fn new(cart: &'a mut Cartridge) -> Self {
- let bank_num = cart.get_bank_num(BankType::PrgRom);
+ pub fn new(cart: *const Cartridge) -> Self {
unsafe {
- Mapper2{cart,
- prg_bank1: &*cart.get_bank(0, BankType::PrgRom),
- prg_bank2: &*cart.get_bank(bank_num - 1, BankType::PrgRom),
- chr_bank: &mut *cart.get_bank(0, BankType::ChrRom),
- sram: &mut *cart.get_bank(0, BankType::Sram),
- bank_num}
+ let cart = &*cart;
+ let nbank = cart.get_size(BankType::PrgRom) >> 14;
+ Mapper2{cart: &cart,
+ prg_bank1: RefCell::new(&*cart.get_bank(0, 0x4000, BankType::PrgRom)),
+ prg_bank2: RefCell::new(&*cart.get_bank((nbank - 1) << 14, 0x4000, BankType::PrgRom)),
+ chr_bank: RefCell::new(&mut *cart.get_bank(0, 0x2000, BankType::ChrRom)),
+ sram: RefCell::new(&mut *cart.get_bank(0, 0x2000, BankType::Sram)),
+ prg_nbank: nbank}
}
}
}
diff --git a/src/memory.rs b/src/memory.rs
index f506a86..9b5f322 100644
--- a/src/memory.rs
+++ b/src/memory.rs
@@ -1,44 +1,52 @@
+#![allow(dead_code)]
use ppu::PPU;
use mos6502::CPU;
use cartridge::{MirrorType, Cartridge};
-use core::cell::{RefCell, RefMut};
+use core::cell::{RefCell, Cell};
+use core::ptr::null_mut;
pub trait VMem {
fn read(&self, addr: u16) -> u8;
- fn write(&mut self, addr: u16, data: u8);
+ fn write(&self, addr: u16, data: u8);
}
pub struct CPUMemory<'a> {
- internal: [u8; 2048],
- ppu: *mut PPU<'a>,
- cpu: *mut CPU<'a>,
- mapper: &'a mut VMem
+ sram: RefCell<[u8; 2048]>,
+ ppu: Cell<*mut PPU<'a>>,
+ cpu: Cell<*mut CPU<'a>>,
+ mapper: &'a VMem
}
impl<'a> CPUMemory<'a> {
- pub fn new(cpu: *mut CPU<'a>,
- ppu: *mut PPU<'a>,
- mapper: &'a mut VMem) -> Self {
- CPUMemory{internal: [0; 2048],
- cpu, ppu,
+ pub fn new(mapper: &'a VMem) -> Self {
+ CPUMemory{sram: RefCell::new([0; 2048]),
+ cpu: Cell::new(null_mut()),
+ ppu: Cell::new(null_mut()),
mapper}
}
+
+ pub fn init(&self,
+ cpu: *mut CPU<'a>,
+ ppu: *mut PPU<'a>) {
+ self.cpu.set(cpu);
+ self.ppu.set(ppu);
+ }
}
impl<'a> VMem for CPUMemory<'a> {
fn read(&self, addr: u16) -> u8 {
match addr {
_ => if addr < 0x2000 {
- self.internal[(addr & 0x07ff) as usize]
+ self.sram.borrow()[(addr & 0x07ff) as usize]
} else if addr < 0x4000 {
- let ppu = unsafe {&mut *self.ppu};
+ let ppu = unsafe {&mut *self.ppu.get()};
match addr & 0x7 {
0x2 => ppu.read_status(),
0x4 => ppu.read_oamdata(),
0x7 => ppu.read_data(),
- _ => panic!("invalid ppu reg read access at 0x{:04x}", addr)
+ _ => 0
}
- } else if addr < 0x4020 {
+ } else if addr < 0x6000 {
println!("feeding dummy data for 0x{:04x}", addr);
0
} else {
@@ -46,11 +54,11 @@ 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};
+ fn write(&self, addr: u16, data: u8) {
+ let ppu = unsafe {&mut *self.ppu.get()};
+ let cpu = unsafe {&mut *self.cpu.get()};
if addr < 0x2000 {
- self.internal[(addr & 0x07ff) as usize] = data;
+ self.sram.borrow_mut()[(addr & 0x07ff) as usize] = data;
} else if addr < 0x4000 {
match addr & 0x7 {
0x0 => ppu.write_ctl(data),
@@ -67,6 +75,7 @@ impl<'a> VMem for CPUMemory<'a> {
0x4014 => ppu.write_oamdma(data, cpu),
_ => println!("ignore writing for 0x{:04x}", addr)
}
+ } else if addr < 0x6000 {
} else {
self.mapper.write(addr, data)
}
@@ -74,20 +83,20 @@ impl<'a> VMem for CPUMemory<'a> {
}
pub struct PPUMemory<'a> {
- pattern_table: [u8; 0x2000],
- nametable: [u8; 0x1000],
- palette: [u8; 0x20],
+ pattern_table: RefCell<[u8; 0x2000]>,
+ nametable: RefCell<[u8; 0x1000]>,
+ palette: RefCell<[u8; 0x20]>,
cart: &'a Cartridge,
- mapper: &'a mut VMem,
+ mapper: &'a VMem,
}
impl<'a> PPUMemory<'a> {
- pub fn new(mapper: &'a mut VMem,
+ pub fn new(mapper: &'a VMem,
cart: &'a Cartridge) -> Self {
PPUMemory{
- pattern_table: [0; 0x2000],
- nametable: [0; 0x1000],
- palette: [0; 0x20],
+ pattern_table: RefCell::new([0; 0x2000]),
+ nametable: RefCell::new([0; 0x1000]),
+ palette: RefCell::new([0; 0x20]),
cart,
mapper}
}
@@ -115,31 +124,36 @@ fn mirror_palette(addr: u16) -> u16 {
}
impl<'a> VMem for PPUMemory<'a> {
- fn read(&self, addr: u16) -> u8 {
+ fn read(&self, mut addr: u16) -> u8 {
+ addr &= 0x3fff;
if addr < 0x2000 {
- //self.pattern_table[addr as usize]
self.mapper.read(addr)
} else if addr < 0x3f00 {
let kind = self.cart.mirror_type;
- self.nametable[(get_mirror_addr(kind, addr) & 0x07ff) as usize]
+ self.nametable.borrow()
+ [(get_mirror_addr(kind, addr) & 0x07ff) as usize]
} else if addr < 0x4000 {
- self.palette[mirror_palette(addr & 0x1f) as usize]
+ self.palette.borrow()
+ [mirror_palette(addr & 0x1f) as usize]
} else {
panic!("invalid ppu read access at 0x{:04x}", addr)
}
}
- fn write(&mut self, addr: u16, data: u8) {
+ fn write(&self, mut addr: u16, data: u8) {
+ addr &= 0x3fff;
+ println!("writing 0x{:02x} to 0x{:04x}", data, addr);
if addr < 0x2000 {
- //self.pattern_table[addr as usize] = data
self.mapper.write(addr, data)
} else if addr < 0x3f00 {
let kind = self.cart.mirror_type;
- self.nametable[(get_mirror_addr(kind, addr) & 0x07ff) as usize] = data
+ self.nametable.borrow_mut()
+ [(get_mirror_addr(kind, addr) & 0x07ff) as usize] = data
} else if addr < 0x4000 {
- self.palette[mirror_palette(addr & 0x1f) as usize] = data
+ self.palette.borrow_mut()
+ [mirror_palette(addr & 0x1f) as usize] = data
} else {
- panic!("invalid ppu read access at 0x{:04x}", addr)
+ panic!("invalid ppu write access at 0x{:04x}", addr)
}
}
diff --git a/src/mos6502.rs b/src/mos6502.rs
index 58ac217..c439700 100644
--- a/src/mos6502.rs
+++ b/src/mos6502.rs
@@ -132,7 +132,7 @@ pub mod disasm {
format!("${:02x}, y", code.next().unwrap())
}
fn rel(code: T) -> String {
- let b = *code.next().unwrap() as i8;
+ let b = *code.next().unwrap() as i8 as i16;
if b >= 0 {
format!("+${:02x}, x", b)
} else {
@@ -229,10 +229,9 @@ mod ops {
let opr1 = cpu.a as u16;
let opr2 = match cpu.addr_mode {
AddrMode::Immediate => cpu.imm_val,
- AddrMode::Accumulator => cpu.a,
- AddrMode::EffAddr => cpu.mem.read(cpu.ea)
+ _ => cpu.mem.read(cpu.ea)
} as u16;
- let res = opr1 + opr2 + cpu.get_carry() as u16;
+ let res = opr1 + opr2 + (cpu.get_carry() as u16);
let mut status = cpu.status & !(CARRY_FLAG | ZERO_FLAG | OVER_FLAG | NEG_FLAG);
cpu.a = res as u8;
status |= (res > 0xff) as u8; /* carry flag */
@@ -248,10 +247,9 @@ mod ops {
let opr1 = cpu.a as u16;
let opr2 = match cpu.addr_mode {
AddrMode::Immediate => cpu.imm_val,
- AddrMode::Accumulator => cpu.a,
- AddrMode::EffAddr => cpu.mem.read(cpu.ea)
+ _ => cpu.mem.read(cpu.ea)
} as u16;
- let res = opr1 + (0xff - opr2) + cpu.get_carry() as u16;
+ let res = opr1 + (0xff - opr2) + (cpu.get_carry() as u16);
let mut status = cpu.status & !(CARRY_FLAG | ZERO_FLAG | OVER_FLAG | NEG_FLAG);
cpu.a = res as u8;
status |= (res > 0xff) as u8; /* carry flag */
@@ -269,9 +267,9 @@ mod ops {
AddrMode::Immediate => cpu.imm_val,
_ => cpu.mem.read(cpu.ea)
} as u16;
- let res = opr1 - opr2;
+ let res = opr1.wrapping_sub(opr2);
let mut status = cpu.status & !(CARRY_FLAG | ZERO_FLAG | NEG_FLAG);
- status |= (res < 0x100) as u8; /* carry flag */
+ status |= (res < 0x100) as u8; /* if opr1 >= opr2 */
check_zero!(status, res);
check_neg!(status, res);
cpu.status = status;
@@ -286,16 +284,16 @@ mod ops {
macro_rules! make_delta {
($f: ident, $d: expr) => (
fn $f(cpu: &mut CPU) {
- let res = cpu.mem.read(cpu.ea) as u16 + $d;
+ let res = cpu.mem.read(cpu.ea).wrapping_add($d);
let mut status = cpu.status & !(ZERO_FLAG | NEG_FLAG);
- cpu.mem.write(cpu.ea, res as u8);
+ cpu.mem.write(cpu.ea, res);
check_zero!(status, res);
check_neg!(status, res);
cpu.status = status;
});
($f: ident, $d: expr, $r: ident) => (
fn $f(cpu: &mut CPU) {
- let res = cpu.$r as u16 + $d;
+ let res = cpu.$r.wrapping_add($d);
let mut status = cpu.status & !(ZERO_FLAG | NEG_FLAG);
cpu.$r = res as u8;
check_zero!(status, res);
@@ -514,8 +512,11 @@ mod ops {
macro_rules! make_ld {
($f: ident, $r: ident) => (fn $f(cpu: &mut CPU) {
let mut status = cpu.status & !(ZERO_FLAG | NEG_FLAG);
- let res = cpu.mem.read(cpu.ea);
- cpu.a = res;
+ let res = match cpu.addr_mode {
+ AddrMode::Immediate => cpu.imm_val,
+ _ => cpu.mem.read(cpu.ea)
+ };
+ cpu.$r = res;
check_zero!(status, res);
check_neg!(status, res);
cpu.status = status;
@@ -612,20 +613,20 @@ mod addr {
fn zpx(cpu: &mut CPU) {
cpu.addr_mode = AddrMode::EffAddr;
cpu.ea = (cpu.mem.read(cpu.opr)
- .wrapping_add(cpu.x)) as u16;
+ .wrapping_add(cpu.x)) as u16;
}
fn zpy(cpu: &mut CPU) {
cpu.addr_mode = AddrMode::EffAddr;
cpu.ea = (cpu.mem.read(cpu.opr)
- .wrapping_add(cpu.y)) as u16;
+ .wrapping_add(cpu.y)) as u16;
}
fn rel(cpu: &mut CPU) {
cpu.addr_mode = AddrMode::EffAddr;
let base = cpu.pc;
let offset = cpu.mem.read(cpu.opr) as i8 as i16;
- let sum = (base & 0xff) + offset as u16;
+ let sum = ((base & 0xff) as i16 + offset) as u16;
cpu.ea = (base & 0xff00).wrapping_add(sum);
cpu.cycle += (sum >> 8) as u32;
}
@@ -638,7 +639,7 @@ mod addr {
fn abx(cpu: &mut CPU) {
cpu.addr_mode = AddrMode::EffAddr;
let base = read16!(cpu.mem, cpu.opr);
- let sum = (base & 0xff) + cpu.x as u16;
+ let sum = (base & 0xff) + (cpu.x as u16);
cpu.ea = (base & 0xff00).wrapping_add(sum);
cpu.cycle += (sum >> 8) as u32; /* boundary cross if carry */
}
@@ -646,7 +647,7 @@ mod addr {
fn aby(cpu: &mut CPU) {
cpu.addr_mode = AddrMode::EffAddr;
let base = read16!(cpu.mem, cpu.opr);
- let sum = (base & 0xff) + cpu.y as u16;
+ let sum = (base & 0xff) + (cpu.y as u16);
cpu.ea = (base & 0xff00).wrapping_add(sum);
cpu.cycle += (sum >> 8) as u32; /* boundary cross if carry */
}
@@ -659,17 +660,15 @@ mod addr {
fn xin(cpu: &mut CPU) {
cpu.addr_mode = AddrMode::EffAddr;
- let addr = cpu.mem.read(
- cpu.mem.read(cpu.opr)
- .wrapping_add(cpu.x) as u16) as u16;
- cpu.ea = read16!(cpu.mem, addr);
+ cpu.ea = read16!(cpu.mem,
+ cpu.mem.read(cpu.opr)
+ .wrapping_add(cpu.x) as u16) as u16;
}
fn iny(cpu: &mut CPU) {
cpu.addr_mode = AddrMode::EffAddr;
- let addr = cpu.mem.read(cpu.mem.read(cpu.opr) as u16) as u16;
- let base = read16!(cpu.mem, addr);
- let sum = (base & 0xff) + cpu.y as u16;
+ let base = read16!(cpu.mem, cpu.mem.read(cpu.opr) as u16);
+ let sum = (base & 0xff) + (cpu.y as u16);
cpu.ea = (base & 0xff00).wrapping_add(sum);
cpu.cycle += (sum >> 8) as u32; /* boundary cross if carry */
}
@@ -703,7 +702,7 @@ pub struct CPU<'a> {
imm_val: u8,
pub cycle: u32,
int: Option<IntType>,
- pub mem: &'a mut VMem
+ pub mem: &'a VMem
}
macro_rules! make_int {
@@ -728,7 +727,7 @@ impl<'a> CPU<'a> {
#[inline(always)] pub fn get_over(&self) -> u8 { (self.status >> 6) & 1 }
#[inline(always)] pub fn get_neg(&self) -> u8 { (self.status >> 7) & 1 }
- pub fn new(mem: &'a mut VMem) -> Self {
+ pub fn new(mem: &'a VMem) -> Self {
let pc = read16!(mem, RESET_VECTOR as u16);
/* nes power up state */
let a = 0;
@@ -750,14 +749,21 @@ impl<'a> CPU<'a> {
make_int!(irq, IRQ_VECTOR);
pub fn step(&mut self) {
- let pc = self.pc;
match self.int {
Some(IntType::NMI) => self.nmi(),
Some(IntType::IRQ) => self.irq(),
_ => ()
}
self.int = None;
+ let pc = self.pc;
let opcode = self.mem.read(pc) as usize;
+ let len = INST_LENGTH[opcode];
+ let mut code = vec![0; len as usize];
+ for i in 0..len as u16 {
+ code[i as usize] = self.mem.read(pc + i);
+ }
+ println!("0x{:04x} {} a:{} x:{} y:{}",
+ pc, disasm::parse(opcode as u8, &code[1..]), self.a, self.x, self.y);
/* update opr pointing to operands of current inst */
self.opr = pc.wrapping_add(1);
/* update program counter pointing to next inst */
@@ -769,16 +775,7 @@ impl<'a> CPU<'a> {
self.cycle += INST_CYCLE[opcode] as u32;
}
- pub fn powerup(&mut self) {
- self.pc = read16!(self.mem, RESET_VECTOR as u16);
- /* nes power up state */
- self.a = 0;
- self.x = 0;
- self.y = 0;
- self.sp = 0xfd;
- self.status = 0x34;
- self.cycle = 0;
- }
+ pub fn get_pc(&self) -> u16 { self.pc }
pub fn reset(&mut self) {
self.pc = read16!(self.mem, RESET_VECTOR as u16);
diff --git a/src/ppu.rs b/src/ppu.rs
index 6aea1fc..dd3d01e 100644
--- a/src/ppu.rs
+++ b/src/ppu.rs
@@ -4,7 +4,7 @@ use mos6502::CPU;
use core::intrinsics::transmute;
pub trait Screen {
- fn put(&mut self, x: u8, y: u8, color: u8);
+ fn put(&self, x: u8, y: u8, color: u8);
fn render(&self);
}
@@ -18,9 +18,6 @@ struct Sprite {
}
pub struct PPU<'a> {
- /* internal srams */
- nametable_ram: [u8; 2048],
- palette_ram: [u8; 32],
scanline: u16,
/* registers */
ppuctl: u8,
@@ -38,7 +35,7 @@ pub struct PPU<'a> {
/* rendering regs & latches */
/* background registers */
bg_bitmap: [u16; 2],
- bg_palette: [u8; 2],
+ bg_palette: [u16; 2],
/* background latches */
bg_nt: u8,
bg_attr: u8,
@@ -53,8 +50,8 @@ pub struct PPU<'a> {
rendering: bool,
buffered_read: u8,
/* IO */
- mem: &'a mut VMem,
- scr: &'a mut Screen,
+ mem: &'a VMem,
+ scr: &'a Screen,
}
impl<'a> PPU<'a> {
@@ -196,7 +193,7 @@ impl<'a> PPU<'a> {
/* 0x-??0 */
((self.bg_nt as u16) << 4) |
/* 0x---? (0 - 7) */
- (self.v >> 12) | 0x0);
+ ((self.v >> 12) & 7) | 0x0);
}
#[inline(always)]
@@ -206,7 +203,7 @@ impl<'a> PPU<'a> {
/* 0x-??0 */
((self.bg_nt as u16) << 4) |
/* 0x---? (8 - f) */
- (self.v >> 12) | 0x8);
+ ((self.v >> 12) & 7) | 0x8);
}
#[inline(always)]
@@ -214,21 +211,25 @@ impl<'a> PPU<'a> {
/* load the tile bitmap to high 8 bits of bitmap,
* assume the high 8 bits are zeros */
assert!(self.bg_bitmap[0] >> 8 == 0 &&
- self.bg_bitmap[1] >> 8 == 0);
- self.bg_bitmap[0] |= (self.bg_bit_low as u16) << 8;
- self.bg_bitmap[1] |= (self.bg_bit_high as u16) << 8;
- self.bg_palette[0] |= (self.bg_attr & 1) * 0xff;
- self.bg_palette[1] |= ((self.bg_attr >> 1) & 1) * 0xff;
+ self.bg_bitmap[1] >> 8 == 0 &&
+ self.bg_palette[0] >> 8 == 0 &&
+ self.bg_palette[1] >> 8 == 0);
+ self.bg_bitmap[0] |= (PPU::reverse_byte(self.bg_bit_low) as u16) << 8;
+ self.bg_bitmap[1] |= (PPU::reverse_byte(self.bg_bit_high) as u16) << 8;
+ self.bg_palette[0] |= (self.bg_attr & 1) as u16 * 0xff00;
+ self.bg_palette[1] |= ((self.bg_attr >> 1) & 1) as u16 * 0xff00;
}
#[inline(always)]
fn shift_sprites(&mut self) {
for (i, c) in self.sp_cnt.iter_mut().enumerate() {
+ if self.oam2[i].y == 0xff { break }
let c0 = *c;
match c0 {
0 => {
- self.sp_bitmap[i][0] >>= 1;
- self.sp_bitmap[i][1] >>= 1;
+ let t = &mut self.sp_bitmap[i];
+ t[0] = t[0].wrapping_shr(1);
+ t[1] = t[1].wrapping_shr(1);
},
_ => *c = c0 - 1
}
@@ -237,10 +238,12 @@ impl<'a> PPU<'a> {
#[inline(always)]
fn shift_bgtile(&mut self, d: u8) {
- self.bg_bitmap[0] >>= d;
- self.bg_bitmap[1] >>= d;
- self.bg_palette[0] >>= d;
- self.bg_palette[1] >>= d;
+ let t1 = &mut self.bg_bitmap;
+ let t2 = &mut self.bg_palette;
+ t1[0] = t1[0].wrapping_shr(d as u32);
+ t1[1] = t1[1].wrapping_shr(d as u32);
+ t2[0] = t2[0].wrapping_shr(d as u32);
+ t2[1] = t2[1].wrapping_shr(d as u32);
}
#[inline(always)]
@@ -260,12 +263,12 @@ impl<'a> PPU<'a> {
false => self.v += 0x1000, /* fine y < 7 */
true => {
self.v &= !0x7000u16; /* fine y <- 0 */
- self.v = (self.v & !0x03e0u16) |
- (match (self.v & 0x03e0) >> 5 {
+ let y = match (self.v & 0x03e0) >> 5 {
29 => {self.v ^= 0x0800; 0}, /* at bottom of scanline */
31 => 0, /* do not switch nt */
y => y + 1
- }) << 5;
+ };
+ self.v = (self.v & !0x03e0u16) | (y << 5);
}
}
}
@@ -333,25 +336,26 @@ impl<'a> PPU<'a> {
fn fetch_sprite(&mut self) {
/* we use scanline here because s.y is the (actual y) - 1 */
- for (i, v) in self.oam2.iter().enumerate() {
- let vflip = (v.attr & 0x80) == 0x80;
- let y0 = self.scanline - v.y as u16;
+ for (i, s) in self.oam2.iter().enumerate() {
+ if s.y == 0xff { break }
+ let vflip = (s.attr & 0x80) == 0x80;
+ let y0 = self.scanline - s.y as u16;
let (ptable, tidx, y) = match self.get_spritesize() {
0 => {
let y = if vflip {7 - y0 as u8} else {y0 as u8};
- ((self.ppuctl as u16 & 0x08) << 9, v.tile, y)
+ ((self.ppuctl as u16 & 0x08) << 9, s.tile, y)
},
_ => {
let y = if vflip {15 - y0 as u8} else {y0 as u8};
- ((v.tile as u16 & 1) << 12,
- (v.tile & !1u8) | (y >> 3),
+ ((s.tile as u16 & 1) << 12,
+ (s.tile & !1u8) | (y >> 3),
y & 0x7)
}
};
- self.sp_cnt[i] = v.x;
+ self.sp_cnt[i] = s.x;
let mut low = self.mem.read(ptable | ((tidx as u16) << 4) | 0x0 | y as u16);
let mut high = self.mem.read(ptable | ((tidx as u16) << 4) | 0x8 | y as u16);
- if (v.attr & 0x40) == 0x40 {
+ if (s.attr & 0x40) != 0x40 {
low = PPU::reverse_byte(low);
high = PPU::reverse_byte(high);
}
@@ -375,6 +379,7 @@ impl<'a> PPU<'a> {
}
fn render_pixel(&mut self) {
+ println!("ppuctl:{} ppumask:{}", self.ppuctl, self.ppumask);
let x = self.cycle - 1;
let bg_pidx =
if x >= 8 || self.get_show_leftmost_bg() {self.get_bg_pidx()}
@@ -384,6 +389,7 @@ impl<'a> PPU<'a> {
let mut pri = 0x1;
if x >= 8 || self.get_show_leftmost_sp() {
for i in 0..8 {
+ if self.oam2[i].y == 0xff { break }
if self.sp_cnt[i] != 0 { continue; } /* not active */
match self.get_sp_pidx(i) {
0x0 => (),
@@ -401,7 +407,7 @@ impl<'a> PPU<'a> {
}
assert!(0 < self.cycle && self.cycle < 257);
assert!(self.scanline < 240);
- self.scr.put(self.cycle as u8 - 1,
+ self.scr.put((self.cycle - 1) as u8,
self.scanline as u8,
if (pri == 0 || bg_pidx == 0) && sp_pidx != 0 {
self.mem.read(0x3f10 |
@@ -415,7 +421,7 @@ impl<'a> PPU<'a> {
});
}
- pub fn new(mem: &'a mut VMem, scr: &'a mut Screen) -> Self {
+ pub fn new(mem: &'a VMem, scr: &'a Screen) -> Self {
let ppuctl = 0x00;
let ppumask = 0x00;
let ppustatus = 0xa0;
@@ -425,8 +431,6 @@ impl<'a> PPU<'a> {
let cycle = 370;
let scanline = 240;
PPU {
- nametable_ram: [0; 2048],
- palette_ram: [0; 32],
scanline,
ppuctl,
ppumask,
@@ -468,22 +472,24 @@ impl<'a> PPU<'a> {
let visible = self.scanline < 240;
let pre_render = self.scanline == 261;
self.rendering = pre_render || visible;
- if pre_render {
- if cycle == 1 {
- /* clear vblank, sprite zero hit & overflow */
- self.ppustatus &= !(PPU::FLAG_VBLANK |
- PPU::FLAG_SPRITE_ZERO | PPU::FLAG_OVERFLOW);
- } else if 279 < cycle && cycle < 305 {
- self.reset_y();
+ if self.rendering && (self.get_show_bg() || self.get_show_sp()) {
+ if pre_render {
+ if cycle == 1 {
+ /* clear vblank, sprite zero hit & overflow */
+ self.ppustatus &= !(PPU::FLAG_VBLANK |
+ PPU::FLAG_SPRITE_ZERO | PPU::FLAG_OVERFLOW);
+ } else if 279 < cycle && cycle < 305 {
+ self.reset_y();
+ }
}
- }
- if self.rendering {
let shifting = 0 < cycle && cycle < 257; /* 1..256 */
let fetch = shifting || (320 < cycle && cycle < 337);
if fetch { /* 1..256 and 321..336 */
match cycle & 0x7 {
1 => {
- self.load_bgtile();
+ if shifting {
+ self.load_bgtile();
+ }
self.fetch_nametable_byte();
},
3 => self.fetch_attrtable_byte(),