feat(cartridge): implement MBC2
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
01064bab69
commit
44ac0c8ebd
|
@ -47,6 +47,8 @@ impl Cartridge {
|
||||||
MBCKind::None => Box::new(NoMBC),
|
MBCKind::None => Box::new(NoMBC),
|
||||||
MBCKind::MBC1 => Box::new(MBC1::new(ram_size, rom_size)),
|
MBCKind::MBC1 => Box::new(MBC1::new(ram_size, rom_size)),
|
||||||
MBCKind::MBC1WithBattery => Box::new(MBC1::new(ram_size, rom_size)), // TODO: Implement Saving
|
MBCKind::MBC1WithBattery => Box::new(MBC1::new(ram_size, rom_size)), // TODO: Implement Saving
|
||||||
|
MBCKind::MBC2 => Box::new(MBC2::new(rom_cap)),
|
||||||
|
MBCKind::MBC2WithBattery => Box::new(MBC2::new(rom_cap)), // TODO: Implement Saving
|
||||||
MBCKind::MBC3 => Box::new(MBC3::new(ram_cap)),
|
MBCKind::MBC3 => Box::new(MBC3::new(ram_cap)),
|
||||||
MBCKind::MBC3WithBattery => Box::new(MBC3::new(ram_cap)), // TODO: Implement Saving
|
MBCKind::MBC3WithBattery => Box::new(MBC3::new(ram_cap)), // TODO: Implement Saving
|
||||||
MBCKind::MBC5 => Box::new(MBC5::new(ram_cap, rom_cap)),
|
MBCKind::MBC5 => Box::new(MBC5::new(ram_cap, rom_cap)),
|
||||||
|
@ -80,14 +82,18 @@ impl Cartridge {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_mbc(memory: &[u8]) -> MBCKind {
|
fn find_mbc(memory: &[u8]) -> MBCKind {
|
||||||
|
use MBCKind::*;
|
||||||
|
|
||||||
match memory[MBC_TYPE_ADDRESS] {
|
match memory[MBC_TYPE_ADDRESS] {
|
||||||
0x00 => MBCKind::None,
|
0x00 => None,
|
||||||
0x01 | 0x02 => MBCKind::MBC1,
|
0x01 | 0x02 => MBC1,
|
||||||
0x03 => MBCKind::MBC1WithBattery,
|
0x03 => MBC1WithBattery,
|
||||||
0x19 | 0x1A => MBCKind::MBC5,
|
0x05 => MBC2,
|
||||||
0x1B => MBCKind::MBC5WithBattery,
|
0x06 => MBC2WithBattery,
|
||||||
0x13 => MBCKind::MBC3WithBattery,
|
0x19 | 0x1A => MBC5,
|
||||||
0x11 | 0x12 => MBCKind::MBC3,
|
0x1B => MBC5WithBattery,
|
||||||
|
0x13 => MBC3WithBattery,
|
||||||
|
0x11 | 0x12 => MBC3,
|
||||||
id => unimplemented!("id {:#04X} is an unsupported MBC", id),
|
id => unimplemented!("id {:#04X} is an unsupported MBC", id),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -405,6 +411,67 @@ impl MBCIo for MBC5 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct MBC2 {
|
||||||
|
/// 4-bit number
|
||||||
|
rom_bank: u8,
|
||||||
|
memory: Box<[u8; Self::RAM_SIZE]>,
|
||||||
|
mem_enabled: bool,
|
||||||
|
|
||||||
|
rom_cap: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MBC2 {
|
||||||
|
const RAM_SIZE: usize = 0x0200;
|
||||||
|
|
||||||
|
fn new(rom_cap: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
rom_bank: 0x01,
|
||||||
|
memory: Box::new([0; Self::RAM_SIZE]),
|
||||||
|
mem_enabled: Default::default(),
|
||||||
|
rom_cap,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rom_addr(&self, addr: u16) -> usize {
|
||||||
|
(0x4000 * self.rom_bank as usize + (addr as usize - 0x4000)) % self.rom_cap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MBCIo for MBC2 {
|
||||||
|
fn handle_read(&self, addr: u16) -> MBCResult {
|
||||||
|
use MBCResult::*;
|
||||||
|
|
||||||
|
match addr {
|
||||||
|
0x0000..=0x3FFF => Address(addr as usize),
|
||||||
|
0x4000..=0x7FFF => Address(self.rom_addr(addr)),
|
||||||
|
0xA000..=0xBFFF if self.mem_enabled => {
|
||||||
|
let mbc2_addr = addr as usize & (Self::RAM_SIZE - 1);
|
||||||
|
Value(self.memory[mbc2_addr] | 0xF0)
|
||||||
|
}
|
||||||
|
0xA000..=0xBFFF => Value(0xFF),
|
||||||
|
_ => unreachable!("A read from {:#06X} should not be handled by MBC2", addr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_write(&mut self, addr: u16, byte: u8) {
|
||||||
|
let nybble = byte & 0x0F;
|
||||||
|
|
||||||
|
match addr {
|
||||||
|
0x0000..=0x3FFF if addr >> 8 & 0x01 == 0x01 => {
|
||||||
|
self.rom_bank = if nybble == 0x00 { 0x01 } else { nybble };
|
||||||
|
}
|
||||||
|
0x0000..=0x3FFF => self.mem_enabled = nybble == 0x0A,
|
||||||
|
0xA000..=0xBFFF if self.mem_enabled => {
|
||||||
|
let mbc2_addr = addr as usize & (Self::RAM_SIZE - 1);
|
||||||
|
self.memory[mbc2_addr] = nybble;
|
||||||
|
}
|
||||||
|
0x4000..=0x7FFF | 0xA000..=0xBFFF => {}
|
||||||
|
_ => unreachable!("A write to {:#06X} should not be handled by MBC2", addr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct NoMBC;
|
struct NoMBC;
|
||||||
|
|
||||||
|
@ -434,6 +501,8 @@ enum MBCKind {
|
||||||
None,
|
None,
|
||||||
MBC1,
|
MBC1,
|
||||||
MBC1WithBattery,
|
MBC1WithBattery,
|
||||||
|
MBC2,
|
||||||
|
MBC2WithBattery,
|
||||||
MBC3,
|
MBC3,
|
||||||
MBC3WithBattery,
|
MBC3WithBattery,
|
||||||
MBC5,
|
MBC5,
|
||||||
|
|
Loading…
Reference in New Issue