aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bin.rs28
-rw-r--r--src/cartridge.rs3
-rw-r--r--src/mapper.rs172
-rw-r--r--src/memory.rs18
-rw-r--r--src/mos6502.rs24
5 files changed, 203 insertions, 42 deletions
diff --git a/src/bin.rs b/src/bin.rs
index f79a24d..e608e7e 100644
--- a/src/bin.rs
+++ b/src/bin.rs
@@ -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);