Skip to content

Commit

Permalink
add start of separate cartridge support; needs work
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkMcCaskey committed Mar 20, 2017
1 parent 613763f commit 411dce9
Show file tree
Hide file tree
Showing 2 changed files with 198 additions and 0 deletions.
172 changes: 172 additions & 0 deletions src/cpu/cartridge.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
use cpu::constants::*;

/// The things that are constant between all types of cartridges
/// This also includes things like video ram
/// Thus this struct is best understood as dealing with any and all things
/// addressable
///
/// TODO: memory locking during certain periods (i.e. the rest of the virtual
/// memory system...)
pub struct Cartridge {
/// top 16kb
memory_bank0: [byte; 0x4000],
cart_sub: CartridgeSubType,
/// 8kb video ram
video_ram: [byte; 0x2000],
/// 8kb internal ram
internal_ram: [byte; 0x2000],
/// sprite attribute memory
oam: [byte; 0xA0],

/// 0xFF80-0xFFFF
internal_ram2: [byte; 0x80],
interrupt_flag: byte,
}

pub enum CartridgeSubType {
ROM_only {
memory_bank1: [byte; 0x4000],
},
MBC1 {
/*
MBC1 has two modes:
* 16mbit ROM (with 128 banks), 8KB RAM (1 bank)
* 4mbit (with 32 banks), 32KB RAM (4 banks)
*/
//13 bits for 8KB addressing
//addressing 16mbit = 2MB, (1kb = 10) (8kb = 13) (16kb = 14)
//(2mb = 21)
//21bits to index fully, because first 0x4000 address are sep
memory_model: MBC1_type,
memory_banks: [byte; (2 << 13) + (2 << 21) - 0x4000],
ram_active: bool,
//top two bits (21 & 22?) used for selecting RAM in 4_32 mode
mem_bank_selector: u32,
},
}

pub enum MBC1_type {
sixteen_eight,
four_thirtytwo,
}

impl Cartridge {
//for reading
pub fn index(&self, ind: u16) -> byte {
match ind {
0x0000...0x3FFF => {
self.memory_bank0[ind as usize]
}
0x4000...0x7FFF => {
match self.cart_sub {
CartridgeSubType::ROM_only {memory_bank1: membank1} => {
membank1[(ind - 0x4000) as usize]
},
CartridgeSubType::MBC1 {memory_model: MBC1_type::sixteen_eight,
memory_banks: mb,
ram_active: ra,
mem_bank_selector: index} => {
mb[((ind - 0x4000) as usize) + ((index * 0x4000) as usize)]
},
CartridgeSubType::MBC1 {memory_model: MBC1_type::four_thirtytwo,
memory_banks: mb,
ram_active: ra,
mem_bank_selector: index} => {
unimplemented!()
},

_ => unimplemented!(),
}
},
// Video RAM:
0x8000...0x9FFF => {
//TODO: block reads if reads should be blocked
unimplemented!()
},
// switchable RAM bank
0xA000...0xBFFF => {
unimplemented!()
},
//internal ram
0xC000...0xDFFF => {
self.internal_ram[(ind - 0xC000) as usize]
},
//echo of internal ram
0xE000...0xFDFF => {
self.internal_ram[(ind - 0xE000) as usize]
},
// OAM
0xFE00...0xFF9F => {
self.oam[(ind - 0xFE00) as usize]
},
// IO ports
0xFF00...0xFF4B => {
//TODO:
unimplemented!()
},
//more internal RAM
0xFF80...0xFFFE => {
self.internal_ram2[(ind - 0xFF80) as usize]
},
//interrupt flag
0xFFFF => {
//TODO:
self.interrupt_flag
}
_ => {
error!("Address 0x{:X} cannot be read from", ind);
0
},
}
}

pub fn index_set(&mut self, ind: u16, val: u8) {
match self.cart_sub {
CartridgeSubType::ROM_only {memory_bank1: membank1} => {
match ind as usize {
0xFF80...0xFFFE => {
self.internal_ram2[(ind - 0xFF80) as usize] = val;
}
//internal ram
0xC000...0xDFFF => {
self.internal_ram[(ind - 0xC000) as usize] = val;
},
//echo of internal ram
0xE000...0xFDFF => {
self.internal_ram[(ind - 0xE000) as usize] = val;
},
0x0000...0x7FFF => {
error!("Cannot write to address 0x{:X} of a ROM-only cartridge", ind);
}
addr => {
unimplemented!();
}
}
},
CartridgeSubType::MBC1 {memory_model: MBC1_type::sixteen_eight,
memory_banks: mb,
ram_active: ra,
mem_bank_selector: mut index} => {
match ind as usize {
0x2000...0x3FFF => {
//take the lower 5 bits to select the 2nd ROM bank
let bank_select = if (val & 0x1F) == 0 {1} else {val & 0x1F};
index = bank_select as u32;
debug!("MBC1 switching second ROM bank to ROM bank {}", bank_select);
}
0x6000...0x7FFF => {
if (val & 0x1) == 1 {
debug!("MBC1 switching to 4-32 mode");
unimplemented!();
} else {
debug!("MBC1: already in 16-8 mode");
}
}
_ => unimplemented!(),
}
},

_ => unimplemented!(),
}
}
}
26 changes: 26 additions & 0 deletions src/cpu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
#[macro_use] mod macros;
mod tests;
pub mod constants;
pub mod cartridge;

use std::collections::VecDeque;
use std::num::Wrapping;

use disasm::*;
use self::constants::*;
use self::cartridge::*;

pub trait CpuEventLogger {
fn new(mem: Option<&[u8]>) -> Self;
Expand Down Expand Up @@ -191,6 +193,9 @@ pub struct Cpu {

memory_banks: Vec<[byte; 0x4000]>,

/// Whether or not the RAM (included in some carts is writable)
ram_writable: bool,

/// Whether or not the CPU is running, waiting for input, or stopped
pub state: CpuState,

Expand Down Expand Up @@ -223,6 +228,7 @@ impl Clone for Cpu {
cartridge_type: None,
mbc_type: None,
memory_banks: vec![],
ram_writable: false,
state: self.state,
input_state: self.input_state,

Expand Down Expand Up @@ -257,6 +263,7 @@ impl Cpu {
cartridge_type: None,
mbc_type: None,
memory_banks: vec![],
ram_writable: false,
state: CpuState::Normal,
input_state: 0xFF,

Expand Down Expand Up @@ -284,6 +291,7 @@ impl Cpu {
self.sp = 0xFFFE;
self.pc = 0x100;
self.cycles = 0;
self.ram_writable = false;
// if let Some(ref mut el) = self.event_logger {
// el.events_deq.clear();
// }
Expand Down Expand Up @@ -1026,6 +1034,14 @@ impl Cpu {

if let Some(cart_type) = self.cartridge_type {
match address {
0...0x1FFF if cart_type == CartridgeType::RomRam
|| cart_type == CartridgeType::RomRamBatt
|| cart_type == CartridgeType::RomMBC1Ram
|| cart_type == CartridgeType::RomMBC1RamBatt => {
self.ram_writable = (value & 0xF) == 0b1010;
debug!("Setting RAM to {}",
if self.ram_writable {"on"} else {"off"});
},
0...0x7FFF if cart_type == CartridgeType::RomOnly
|| cart_type == CartridgeType::RomRam
|| cart_type == CartridgeType::RomRamBatt => {
Expand Down Expand Up @@ -2498,6 +2514,16 @@ impl Cpu {
} else { // to_cartridge_type failed
error!("Could not find a cartridge type!");
}

debug!("Cart loaded with {} ram banks",
match self.mem[0x149] {
0 => 0,
1 => 1,
2 => 1,
3 => 4,
4 => 16,
_ => {error!("Undefined value at 0x149 in ROM"); -1},
});
}
}

Expand Down

0 comments on commit 411dce9

Please sign in to comment.