#![allow(dead_code)]
extern crate core;
use memory::VMem;
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: 0x0c,
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((prg_nbank - 1) << 14, 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_banks: [&'a [u8]; 2],
chr_bank: &'a mut [u8],
sram: &'a mut [u8],
prg_nbank: usize
}
impl<'a, C> VMem for Mapper2<'a, C> where C: Cartridge {
fn read(&self, addr: u16) -> u8 {
let addr = addr as usize;
if addr < 0x2000 { /* 0x2000 size bank */
self.chr_bank[addr]
} 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_bank[addr] = data;
} else if addr >= 0x8000 {
self.prg_banks[0] = unsafe {
&*self.cart.get_bank(((data as usize) % self.prg_nbank) << 14,
0x4000,
BankType::PrgRom)
}
} else if addr >= 0x6000 {
self.sram[addr - 0x6000] = data
} else {
panic!("invalid write to address: 0x{:04x}", addr);
}
}
}
impl<'a, C> Mapper2<'a, C> where C: Cartridge {
pub fn new(cart: C) -> Self {
unsafe {
let nbank = cart.get_size(BankType::PrgRom) >> 14;
let null = core::mem::uninitialized();
let mut m = Mapper2{cart,
prg_nbank: nbank,
prg_banks: [null; 2],
chr_bank: 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((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
}
}
}
impl<'a, C> Mapper for Mapper2<'a, C> where C: Cartridge {
fn get_cart(&self) -> &Cartridge {&self.cart}
}