Skip to content

Commit

Permalink
Memory controller 1
Browse files Browse the repository at this point in the history
  • Loading branch information
joajfreitas committed Jul 12, 2024
1 parent e6d0e37 commit 60c9966
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 35 deletions.
1 change: 0 additions & 1 deletion fpt/src/lr35902.rs
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,6 @@ impl LR35902 {
}

let cartridge_type = self.mem8(0x147);
println!("cartridge type: {}", cartridge_type);
match instruction.opcode {
0x00 => {
// NOP
Expand Down
145 changes: 142 additions & 3 deletions fpt/src/memory/cartridge.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,49 @@
use crate::memory::{Address, MemoryRange};
use std::cell::RefCell;
use std::rc::Rc;

use crate::memory::map;
use crate::memory::{Address, MemoryRange};

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

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

fn get_cartridge_type(tape: &[u8]) -> u8 {
tape[map::CARTRIDGE_FLAG]
}

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!(),
}
}

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

pub trait Cartridge {
fn read(&self, address: Address) -> u8;
Expand Down Expand Up @@ -56,7 +100,7 @@ impl Cartridge for EmptyCartridge {
0xFF
}
fn write(&mut self, _address: Address, _value: u8) {}

fn read_range(&self, memory_range: MemoryRange) -> Vec<u8> {
Vec::new()
}
Expand All @@ -79,10 +123,105 @@ impl Cartridge for NoMbcCartridge {
self.memory[address]
}
fn write(&mut self, address: Address, value: u8) {
self.memory[address] = value;
if map::EXT_RAM.contains(&address) {
self.memory[address] = value;
}
}

fn read_range(&self, memory_range: MemoryRange) -> Vec<u8> {
self.memory[memory_range].to_vec()
}
}

pub struct Mbc1Cartridge {
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 Mbc1Cartridge {
pub fn new(cartridge: &[u8]) -> Mbc1Cartridge {
let rom_size = dbg!(convert_rom_size(get_rom_size(cartridge)));
let ram_size = dbg!(convert_ram_size(get_ram_size(cartridge)));
let mut rom_banks = vec![[0; 0x4000]; dbg!(rom_size as usize)];
let mut ram_banks = vec![[0; 0x2000]; dbg!(ram_size as usize)];

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

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

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

impl Cartridge for Mbc1Cartridge {
fn read(&self, address: Address) -> u8 {
if map::EXT_RAM.contains(&address) && !self.ext_ram_enabled {
0 // TODO: check that disabled ram reads 0
} else if map::EXT_RAM.contains(&address) && self.ext_ram_enabled {
self.ram_banks[self.ram_bank_number as usize][address - map::EXT_RAM.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 as usize][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_RAM.contains(&address) && self.ext_ram_enabled {
self.memory[address] = value;
}
}

fn read_range(&self, memory_range: MemoryRange) -> Vec<u8> {
self.memory[memory_range].to_vec()
}
}

pub fn create_memory_bank(cartridge_data: &[u8]) -> Rc<RefCell<dyn Cartridge>> {
let cartridge_type = get_cartridge_type(cartridge_data);

match dbg!(cartridge_type) {
0x00 => Rc::new(RefCell::new(NoMbcCartridge::new(cartridge_data))),
0x01 | 0x02 | 0x03 => Rc::new(RefCell::new(Mbc1Cartridge::new(cartridge_data))),
_ => panic!(),
}
}
3 changes: 1 addition & 2 deletions fpt/src/memory/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
/// ```
/// assert_eq!(fpt::memory::map::ROM_DATA.start, 0x0100);
/// ```
use super::{Address, MemoryRange};

//-------------------------------------------------------------------------
Expand All @@ -19,7 +18,7 @@ pub const ROM_DATA: MemoryRange = 0x0100..0x0150;
/// From cartridge, usually a fixed bank
pub const ROM_BANK0: MemoryRange = 0x0000..0x4000;
/// From cartridge, switchable bank via mapper (if any) pub const USER_PROGRAM: MemoryRange = 0x0000..0x8000;
pub const ROM_BANK1: MemoryRange = 0x4000..0x8000;
pub const ROM_BANK1: MemoryRange = 0x4000..0x8000;

/// Video RAM (8 KB) - In CGB mode, switchable bank 0/1
pub const VRAM: MemoryRange = 0x8000..0xA000;
Expand Down
45 changes: 19 additions & 26 deletions fpt/src/memory/memory.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use std::cell::{Ref, RefCell, RefMut};
use std::ops::DerefMut;
use std::ops::Range;
use std::rc::Rc;
use std::ops::DerefMut;

use crate::bw;
use crate::memory::{Cartridge, EmptyCartridge, NoMbcCartridge};
use crate::memory::map;
use crate::memory::{create_memory_bank, Cartridge, EmptyCartridge, NoMbcCartridge};

pub type Address = usize;
pub type MemoryRange = Range<Address>;
Expand Down Expand Up @@ -93,7 +93,7 @@ impl Memory {
self.bootrom_unloaded = true;
}

pub fn bootrom_unloaded(& self) -> bool {
pub fn bootrom_unloaded(&self) -> bool {
self.bootrom_unloaded
}
}
Expand Down Expand Up @@ -136,8 +136,8 @@ impl Bus {
pub fn load_cartridge(&mut self, cartridge: &[u8]) {
// TODO: load
self.memory_mut()
.set_cartridge(Rc::new(RefCell::new(NoMbcCartridge::new(cartridge))));
.set_cartridge(create_memory_bank(cartridge));

//println!("title: {}", self.memory().cartridge().get_title());
//println!("code: {}", self.memory().cartridge().get_manufacturer_code());
//println!("new licensee code: {}", self.memory().cartridge().get_new_licensee_code());
Expand All @@ -156,35 +156,28 @@ impl Bus {
pub fn read(&self, address: Address) -> u8 {
if map::BOOTROM.contains(&address) && !self.memory().bootrom_unloaded() {
self.memory().bootrom[address]
}
else if map::ROM_BANK0.contains(&address) {
} else if map::ROM_BANK0.contains(&address)
|| map::ROM_BANK1.contains(&address)
|| map::EXT_RAM.contains(&address)
{
self.memory().cartridge().borrow().read(address)
}
else if map::ROM_BANK1.contains(&address) {
self.memory().cartridge().borrow().read(address)
}
else if map::EXT_RAM.contains(&address) {
self.memory().cartridge().borrow().read(address)
}
else if address == map::JOYP {
} else if address == map::JOYP {
self.joyp()
} else {
self.memory().mem[address as Address]
}
}

pub fn write(&mut self, address: Address, value: u8) {
if address <= 0x7fff {
panic!(
"{}",
format!("writing to rom, address: {}, value: {}", address, value)
);
}

if map::EXT_RAM.contains(&address) {
self.memory_mut().cartridge_mut().borrow_mut().write(address, value);
}
else {
if map::ROM_BANK0.contains(&address)
|| map::ROM_BANK1.contains(&address)
|| map::EXT_RAM.contains(&address)
{
self.memory_mut()
.cartridge_mut()
.borrow_mut()
.write(address, value);
} else {
self.memory_mut().mem[address as Address] = value;
}
}
Expand Down
6 changes: 3 additions & 3 deletions fpt/src/memory/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
mod cartridge;
pub mod map;
mod mbc1;
mod memory;
mod memory_controller;
pub mod map;

pub use cartridge::{Cartridge, EmptyCartridge, NoMbcCartridge};
pub use memory::{Bus, Buttons, Address, MemoryRange};
pub use cartridge::{create_memory_bank, Cartridge, EmptyCartridge, NoMbcCartridge};
pub use memory::{Address, Bus, Buttons, MemoryRange};

0 comments on commit 60c9966

Please sign in to comment.