Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mbc3 #86

Merged
merged 6 commits into from
Jul 27, 2024
Merged

Mbc3 #86

Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Memory bank controller 3
joajfreitas committed Jul 27, 2024
commit 38d53e5a5c06b3bf7a5b9e72f5bd9e094a190dfd
37 changes: 37 additions & 0 deletions fpt/src/memory/cartridge.rs
Original file line number Diff line number Diff line change
@@ -5,6 +5,43 @@ pub fn get_cartridge_type(cartridge_rom_data: &[u8]) -> u8 {
cartridge_rom_data[map::CARTRIDGE_TYPE]
}

pub fn get_rom_size(cartridge_rom_data: &[u8]) -> u8 {
cartridge_rom_data[map::ROM_SIZE]
}

pub fn get_ram_size(cartridge_rom_data: &[u8]) -> u8 {
cartridge_rom_data[map::RAM_SIZE]
}

pub fn convert_rom_size(rom_size: u8) -> usize {
match rom_size {
0x00 => 2,
0x01 => 4,
0x02 => 8,
0x03 => 16,
0x04 => 32,
0x05 => 64,
0x06 => 128,
0x07 => 256,
0x08 => 512,
0x52 => 72,
0x53 => 80,
0x54 => 96,
_ => panic!(),
}
}

pub fn convert_ram_size(ram_size: u8) -> usize {
match ram_size {
0x00 => 0,
0x02 => 1,
0x03 => 4,
0x04 => 16,
0x05 => 8,
_ => panic!(),
}
}

pub trait Cartridge {
fn read(&self, address: Address) -> u8;

84 changes: 84 additions & 0 deletions fpt/src/memory/mbc3.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use super::cartridge::{convert_ram_size, convert_rom_size, get_ram_size, get_rom_size};
use super::{map, Address, Cartridge, MemoryRange};

pub struct Mbc3Cartridge {
memory: Vec<u8>,
rom_banks: Vec<[u8; 0x4000]>,
ram_banks: Vec<[u8; 0x2000]>,
ext_ram_enabled: bool,
rom_bank_number: usize,
ram_bank_number: usize,
}

impl Mbc3Cartridge {
pub fn new(cartridge: &[u8]) -> Mbc3Cartridge {
let rom_size = convert_rom_size(get_rom_size(cartridge));
let ram_size = convert_ram_size(get_ram_size(cartridge));
let mut rom_banks = vec![[0; 0x4000]; rom_size as usize];
let mut ram_banks = vec![[0; 0x2000]; ram_size as usize];

// TODO: wtf is this initialization
for i in 0..rom_size {
for j in 0..0x4000 {
rom_banks[i][j] = cartridge[0x4000 * i + j];
}
}

for i in 0..ram_size {
for j in 0..0x2000 {
ram_banks[i][j] = cartridge[0x2000 * i + j];
}
}

Mbc3Cartridge {
memory: cartridge.to_vec(),
rom_banks,
ram_banks,
ext_ram_enabled: false,
rom_bank_number: 0,
ram_bank_number: 0,
}
}
}

impl Cartridge for Mbc3Cartridge {
fn read(&self, address: Address) -> u8 {
if map::EXT_WRAM.contains(&address) && !self.ext_ram_enabled {
0 // TODO: check that disabled ram reads 0
} else if map::EXT_WRAM.contains(&address) && self.ext_ram_enabled {
self.ram_banks[self.ram_bank_number][address - map::EXT_WRAM.start]
} else if map::ROM_BANK0.contains(&address) {
self.rom_banks[0][address - map::ROM_BANK0.start]
} else if map::ROM_BANK1.contains(&address) {
self.rom_banks[self.rom_bank_number][address - map::ROM_BANK1.start]
} else {
self.memory[address]
}
}
fn write(&mut self, address: Address, value: u8) {
if (0x0000..0x2000).contains(&address) {
self.ext_ram_enabled = value & 0xF == 0xA;
} else if (0x2000..0x4000).contains(&address) {
// TODO: rom bank number upper bits
let rom_bank_number = value & 0x1F;
if rom_bank_number == 0 {
self.rom_bank_number = 1;
} else {
self.rom_bank_number = rom_bank_number as usize; // TODO: needs to be masked to log2(#banks)
}
} else if (0x4000..0x6000).contains(&address) {
let ram_bank_number = value & 0x3;
self.ram_bank_number = ram_bank_number as usize; // TODO: needs to be checked for number of ram
// banks
} else if map::EXT_WRAM.contains(&address) && self.ext_ram_enabled {
self.memory[address] = value;
}
}

fn read_range(&self, memory_range: MemoryRange) -> Vec<u8> {
memory_range
.into_iter()
.map(|address| self.read(address))
.collect()
}
}
4 changes: 3 additions & 1 deletion fpt/src/memory/mbc_builder.rs
Original file line number Diff line number Diff line change
@@ -2,12 +2,14 @@ use std::cell::RefCell;

use super::cartridge::{get_cartridge_type, EmptyCartridge};
use super::mbc_none::NoMbcCartridge;
use super::mbc3::Mbc3Cartridge;
use super::Cartridge;

pub fn create_mbc(cartridge_data: &[u8]) -> Option<Box<RefCell<dyn Cartridge>>> {
// https://gbdev.io/pandocs/The_Cartridge_Header.html#0147--cartridge-type
match get_cartridge_type(cartridge_data) {
match dbg!(get_cartridge_type(cartridge_data)) {
0x00 => Some(Box::new(RefCell::new(NoMbcCartridge::new(cartridge_data)))), // rom only
0x0F..=0x13 => Some(Box::new(RefCell::new(Mbc3Cartridge::new(cartridge_data)))),
_ => None,
}
}
1 change: 1 addition & 0 deletions fpt/src/memory/mod.rs
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ mod cartridge;
pub mod map;
mod mbc_builder;
mod mbc_none;
mod mbc3;

use std::cell::{Ref, RefCell, RefMut};
use std::ops::Range;