diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bin.rs | 28 | ||||
-rw-r--r-- | src/cartridge.rs | 3 | ||||
-rw-r--r-- | src/mapper.rs | 172 | ||||
-rw-r--r-- | src/memory.rs | 18 | ||||
-rw-r--r-- | src/mos6502.rs | 24 |
5 files changed, 203 insertions, 42 deletions
@@ -80,6 +80,7 @@ impl Cartridge for SimpleCart { })[base..base + size] } fn get_mirror_type(&self) -> MirrorType {self.mirror_type} + fn set_mirror_type(&mut self, mt: MirrorType) {self.mirror_type = mt} } struct SDLWindow<'a> { @@ -293,15 +294,16 @@ fn main() { } */ let p1ctl = stdctl::Joystick::new(); + let cart = SimpleCart::new(chr_rom, prg_rom, sram, mirror); let mut win = SDLWindow::new(&p1ctl); - let mut m = match mapper_id { - 0 | 2 => mapper::Mapper2::new(SimpleCart::new(chr_rom, prg_rom, sram, mirror)), + let mut m: Box<mapper::Mapper> = match mapper_id { + 0 | 2 => Box::new(mapper::Mapper2::new(cart)), + 1 => Box::new(mapper::Mapper1::new(cart)), _ => panic!("unsupported mapper {}", mapper_id) }; - let mt = m.get_cart().get_mirror_type(); - let mapper = RefCell::new(&mut m as &mut memory::VMem); + let mapper = RefCell::new(&mut (*m) as &mut mapper::Mapper); let mut cpu = CPU::new(CPUMemory::new(&mapper, Some(&p1ctl), None)); - let mut ppu = PPU::new(PPUMemory::new(&mapper, mt), &mut win); + let mut ppu = PPU::new(PPUMemory::new(&mapper), &mut win); let cpu_ptr = &mut cpu as *mut CPU; cpu.mem.bus.attach(cpu_ptr, &mut ppu); cpu.start(); @@ -309,6 +311,22 @@ fn main() { while cpu.cycle > 0 { cpu.mem.ppu_tick() } + /* + { + use disasm; + let pc = cpu.get_pc(); + let mem = cpu.get_mem(); + let opcode = mem.read(pc) as usize; + let len = mos6502::INST_LENGTH[opcode]; + let mut code = vec![0; len as usize]; + for i in 0..len as u16 { + code[i as usize] = mem.read(pc + i); + } + println!("0x{:04x} {} a:{:02x} x:{:02x} y:{:02x} s: {:02x} sp: {:02x}", + pc, disasm::parse(opcode as u8, &code[1..]), + cpu.get_a(), cpu.get_x(), cpu.get_y(), cpu.get_status(), cpu.get_sp()); + } + */ cpu.step(); } } diff --git a/src/cartridge.rs b/src/cartridge.rs index 524ef12..95085cd 100644 --- a/src/cartridge.rs +++ b/src/cartridge.rs @@ -18,5 +18,6 @@ pub enum BankType { pub trait Cartridge { fn get_size(&self, kind: BankType) -> usize; fn get_bank(&mut self, base: usize, size: usize, kind: BankType) -> *mut [u8]; - fn get_mirror_type(&self) -> MirrorType; + #[inline(always)] fn get_mirror_type(&self) -> MirrorType; + #[inline(always)] fn set_mirror_type(&mut self, mt: MirrorType); } diff --git a/src/mapper.rs b/src/mapper.rs index 583c452..e09419f 100644 --- a/src/mapper.rs +++ b/src/mapper.rs @@ -1,12 +1,161 @@ #![allow(dead_code)] extern crate core; use memory::VMem; -use cartridge::{Cartridge, BankType}; +use cartridge::{Cartridge, BankType, MirrorType}; + +pub trait Mapper : VMem { + fn get_cart(&self) -> &Cartridge; +} + +pub struct Mapper1<'a, C> where C: Cartridge { + cart: C, + prg_banks: [&'a [u8]; 2], + chr_banks: [&'a mut [u8]; 2], + sram: &'a mut [u8], + ctl_reg: u8, + load_reg: u8, + prg_nbank: usize, /* num of 16k PRG ROM banks */ + chr_nbank: usize /* num of 8k PRG ROM banks */ +} + +impl<'a, C> VMem for Mapper1<'a, C> where C: Cartridge { + fn read(&self, addr: u16) -> u8 { + let addr = addr as usize; + if addr < 0x2000 { /* 0x2000 size bank */ + self.chr_banks[(addr >> 12) & 1][addr & 0xfff] + } else if addr >= 0x8000 { /* 0x4000 size bank */ + self.prg_banks[(addr >> 14) & 1][addr & 0x3fff] + } else if addr >= 0x6000 { + self.sram[addr - 0x6000] + } else { + panic!("unmapped address: 0x{:04x}", addr) + } + } + + fn write(&mut self, addr: u16, data: u8) { + let addr = addr as usize; + if addr < 0x2000 { + self.chr_banks[(addr >> 12) & 1][addr & 0xfff] = data + } else if addr >= 0x8000 { + self.write_loadreg(addr as u16, data) + } else if addr >= 0x6000 { + self.sram[addr - 0x6000] = data + } else { + panic!("invalid write to address: 0x{:04x}", addr); + } + } +} + +impl<'a, C> Mapper1<'a, C> where C: Cartridge { + pub fn new(cart: C) -> Self { + unsafe { + let prg_nbank = cart.get_size(BankType::PrgRom) >> 14; + let chr_nbank = cart.get_size(BankType::ChrRom) >> 13; + let null = core::mem::uninitialized(); + let mut m = Mapper1{cart, + prg_nbank, + chr_nbank, + load_reg: 0x10, + ctl_reg: 0, + prg_banks: [null; 2], + chr_banks: [core::mem::uninitialized(), + core::mem::uninitialized()], + sram: core::mem::uninitialized()}; + { + let c = &mut m.cart; + m.prg_banks[0] = &*c.get_bank(0, 0x4000, BankType::PrgRom); + m.prg_banks[1] = &*c.get_bank(0x4000, 0x4000, BankType::PrgRom); + m.chr_banks[0] = &mut *c.get_bank(0, 0x1000, BankType::ChrRom); + m.chr_banks[1] = &mut *c.get_bank(0x1000, 0x1000, BankType::ChrRom); + m.sram = &mut *c.get_bank(0, 0x2000, BankType::Sram); + } + m + } + } + + fn write_loadreg(&mut self, addr: u16, data: u8) { + if data & 0x80 == 0x80 { + self.ctl_reg |= 0x0c; + self.load_reg = 0x10; + return + } + let triggered = self.load_reg & 1 == 1; + self.load_reg = (self.load_reg >> 1) | ((data & 1) << 4); + if triggered { unsafe { + let load_reg = self.load_reg; + match (addr >> 13) & 3 { + 0x0 => { + self.ctl_reg = load_reg; + self.cart.set_mirror_type(match load_reg & 3 { + 0x0 => MirrorType::Single0, + 0x1 => MirrorType::Single1, + 0x2 => MirrorType::Vertical, + _ => MirrorType::Horizontal + }); + }, + 0x1 => { + match (self.ctl_reg >> 4) & 1 { + 0x0 => { + let base = ((load_reg & 0xfe) as usize % self.chr_nbank) << 13; + self.chr_banks[0] = + &mut *self.cart.get_bank(base, 0x1000, BankType::ChrRom); + self.chr_banks[1] = + &mut *self.cart.get_bank(base + 0x1000, 0x1000, BankType::ChrRom) + }, + _ => + self.chr_banks[0] = &mut *self.cart.get_bank( + (load_reg as usize % (self.chr_nbank << 1)) << 12, + 0x1000, BankType::ChrRom) + } + }, + 0x2 => { + if (self.ctl_reg >> 4) & 1 == 1 { + self.chr_banks[1] = &mut *self.cart.get_bank( + (load_reg as usize % (self.chr_nbank << 1)) << 12, + 0x1000, BankType::ChrRom) + } + }, + 0x3 => { + let load_reg = load_reg & 0xf; + match (self.ctl_reg >> 2) & 3 { + 0x0 | 0x1 => { + let base = ((load_reg & 0xfe) as usize % (self.prg_nbank >> 1)) << 15; + self.prg_banks[0] = + &*self.cart.get_bank(base, 0x4000, BankType::PrgRom); + self.prg_banks[1] = + &*self.cart.get_bank(base + 0x4000, 0x4000, BankType::PrgRom) + }, + 0x2 => { + self.prg_banks[0] = &*self.cart.get_bank(0, 0x4000, BankType::PrgRom); + self.prg_banks[1] = &*self.cart.get_bank( + (load_reg as usize % self.prg_nbank) << 14, + 0x4000, BankType::PrgRom); + }, + 0x3 => { + self.prg_banks[0] = &*self.cart.get_bank( + (load_reg as usize % self.prg_nbank) << 14, + 0x4000, BankType::PrgRom); + self.prg_banks[1] = &*self.cart.get_bank( + (self.prg_nbank - 1) << 14, + 0x4000, BankType::PrgRom); + } + _ => () + } + }, + _ => () + } + self.load_reg = 0x10; + }} + } +} + +impl<'a, C> Mapper for Mapper1<'a, C> where C: Cartridge { + fn get_cart(&self) -> &Cartridge {&self.cart} +} pub struct Mapper2<'a, C> where C: Cartridge { cart: C, - prg_bank1: &'a [u8], - prg_bank2: &'a [u8], + prg_banks: [&'a [u8]; 2], chr_bank: &'a mut [u8], sram: &'a mut [u8], prg_nbank: usize @@ -17,10 +166,8 @@ impl<'a, C> VMem for Mapper2<'a, C> where C: Cartridge { let addr = addr as usize; 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] + self.prg_banks[(addr >> 14) & 1][addr & 0x3fff] } else if addr >= 0x6000 { self.sram[addr - 0x6000] } else { @@ -33,7 +180,7 @@ impl<'a, C> VMem for Mapper2<'a, C> where C: Cartridge { if addr < 0x2000 { self.chr_bank[addr] = data; } else if addr >= 0x8000 { - self.prg_bank1 = unsafe { + self.prg_banks[0] = unsafe { &*self.cart.get_bank(((data as usize) % self.prg_nbank) << 14, 0x4000, BankType::PrgRom) @@ -53,20 +200,21 @@ impl<'a, C> Mapper2<'a, C> where C: Cartridge { let null = core::mem::uninitialized(); let mut m = Mapper2{cart, prg_nbank: nbank, - prg_bank1: null, - prg_bank2: null, + prg_banks: [null; 2], 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.prg_banks[0] = &*c.get_bank(0, 0x4000, BankType::PrgRom); + m.prg_banks[1] = &*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} +impl<'a, C> Mapper for Mapper2<'a, C> where C: Cartridge { + fn get_cart(&self) -> &Cartridge {&self.cart} } diff --git a/src/memory.rs b/src/memory.rs index 0c07329..cfdf422 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -2,6 +2,7 @@ use ppu::PPU; use mos6502::CPU; use cartridge::MirrorType; +use mapper::Mapper; use controller::Controller; use core::cell::RefCell; use core::ptr::null_mut; @@ -34,14 +35,14 @@ impl<'a> Bus<'a> { pub struct CPUMemory<'a> { sram: [u8; 2048], pub bus: Bus<'a>, - mapper: &'a RefCell<&'a mut VMem>, + mapper: &'a RefCell<&'a mut Mapper>, ctl1: Option<&'a Controller>, ctl2: Option<&'a Controller> } impl<'a> CPUMemory<'a> { pub fn new( - mapper: &'a RefCell<&'a mut VMem>, + mapper: &'a RefCell<&'a mut Mapper>, ctl1: Option<&'a Controller>, ctl2: Option<&'a Controller>) -> Self { CPUMemory{sram: [0; 2048], @@ -129,17 +130,14 @@ impl<'a> VMem for CPUMemory<'a> { pub struct PPUMemory<'a> { nametable: [u8; 0x800], palette: [u8; 0x20], - mirror_type: MirrorType, - mapper: &'a RefCell<&'a mut VMem>, + mapper: &'a RefCell<&'a mut Mapper>, } impl<'a> PPUMemory<'a> { - pub fn new(mapper: &'a RefCell<&'a mut VMem>, - mirror_type: MirrorType) -> Self { + pub fn new(mapper: &'a RefCell<&'a mut Mapper>) -> Self { PPUMemory{ nametable: [0; 0x800], palette: [0; 0x20], - mirror_type, mapper} } } @@ -169,7 +167,8 @@ fn get_mirror_palette(addr: u16) -> u16 { impl<'a> PPUMemory<'a> { #[inline(always)] pub fn read_nametable(&self, addr: u16) -> u8 { - self.nametable[(get_mirror_addr(self.mirror_type, addr) & 0x7ff) as usize] + let mt = self.mapper.borrow().get_cart().get_mirror_type(); + self.nametable[(get_mirror_addr(mt, addr) & 0x7ff) as usize] } #[inline(always)] @@ -179,7 +178,8 @@ impl<'a> PPUMemory<'a> { #[inline(always)] pub fn write_nametable(&mut self, addr: u16, data: u8) { - self.nametable[(get_mirror_addr(self.mirror_type, addr) & 0x7ff) as usize] = data + let mt = self.mapper.borrow().get_cart().get_mirror_type(); + self.nametable[(get_mirror_addr(mt, addr) & 0x7ff) as usize] = data } #[inline(always)] diff --git a/src/mos6502.rs b/src/mos6502.rs index 9428171..6c5a140 100644 --- a/src/mos6502.rs +++ b/src/mos6502.rs @@ -48,7 +48,7 @@ macro_rules! make_addrtable { rel, iny, nil, iny, zpx, zpx, zpx, zpx, nil, aby, nil, aby, abx, abx, abx, abx, ];); } -const INST_LENGTH: [u8; 0x100] = [ +pub const INST_LENGTH: [u8; 0x100] = [ 1, 2, 0, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 2, 2, 0, 0, 2, 2, 2, 0, 1, 3, 1, 0, 3, 3, 3, 0, 3, 2, 0, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, @@ -623,6 +623,14 @@ macro_rules! make_int { } impl<'a> CPU<'a> { + #[inline(always)] pub fn get_a(&self) -> u8 { self.a } + #[inline(always)] pub fn get_x(&self) -> u8 { self.x } + #[inline(always)] pub fn get_y(&self) -> u8 { self.y } + #[inline(always)] pub fn get_status(&self) -> u8 { self.status } + #[inline(always)] pub fn get_sp(&self) -> u8 { self.sp } + #[inline(always)] pub fn get_mem(&self) -> &VMem{ &self.mem } + #[inline(always)] pub fn get_pc(&self) -> u16 { self.pc } + #[inline(always)] pub fn get_carry(&self) -> u8 { (self.status >> 0) & 1 } #[inline(always)] pub fn get_zero(&self) -> u8 { (self.status >> 1) & 1 } #[inline(always)] pub fn get_int(&self) -> u8 { (self.status >> 2) & 1 } @@ -668,17 +676,6 @@ 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 { - code[i as usize] = self.mem.read(pc + i); - } - println!("0x{:04x} {} a:{:02x} x:{:02x} y:{:02x} s: {:02x} sp: {:02x}", - pc, disasm::parse(opcode as u8, &code[1..]), - self.a, self.x, self.y, self.status, self.sp); - */ /* update opr pointing to operands of current inst */ self.opr = pc.wrapping_add(1); /* update program counter pointing to next inst */ @@ -692,9 +689,6 @@ impl<'a> CPU<'a> { //(self.cycle - cycle0) as u8 } - #[inline(always)] - pub fn get_pc(&self) -> u16 { self.pc } - pub fn reset(&mut self) { self.pc = read16!(self.mem, RESET_VECTOR as u16); self.sp = self.sp.wrapping_sub(3); |