Split MBC logic

This commit is contained in:
Kevin Hamacher 2016-05-29 22:04:22 +02:00
parent 411f0876af
commit 3458d4b7d9
8 changed files with 173 additions and 173 deletions

View File

@ -1,3 +1,5 @@
use super::mbc::mbc::MBC;
#[derive(Debug,PartialEq)]
enum MemoryBankControllerType {
None,
@ -16,32 +18,22 @@ enum RamSize {
}
pub struct Cartridge {
rom: Box<[u8]>,
ram: Box<[u8]>,
bank_no: u8,
mbc_type: MemoryBankControllerType,
ram_rtc_enabled: bool,
ram_bank_no: u8,
ram_size: RamSize,
rom_banks: u16,
bank_mode: u8,
bank_no_high: u8,
mbc: Box<super::mbc::mbc::MBC>,
}
impl Cartridge {
pub fn new(rom: Box<[u8]>) -> Cartridge {
let mbc: MemoryBankControllerType = match rom[0x0147] {
let mbc_type: MemoryBankControllerType = match rom[0x0147] {
0x00 | 0x08 ... 0x09 => MemoryBankControllerType::None,
0x01 ... 0x03 => MemoryBankControllerType::MBC1,
0x05 ... 0x06 => MemoryBankControllerType::MBC2,
// 0x01 ... 0x03 => MemoryBankControllerType::MBC1,
// 0x05 ... 0x06 => MemoryBankControllerType::MBC2,
0x0F ... 0x13 => MemoryBankControllerType::MBC3,
0xFF => MemoryBankControllerType::HuC1,
// 0xFF => MemoryBankControllerType::HuC1,
_ => panic!("Unsupported MBC type: {:02X}", rom[0x0147]),
};
println!("MBC Type: {:?}", &mbc);
println!("MBC Type: {:?}", &mbc_type);
let rom_banks: u16 = match rom[0x0148] {
0x00 => 0,
@ -70,157 +62,23 @@ impl Cartridge {
RamSize::Ram32KB => vec![0u8; 16 * 2048].into_boxed_slice(),
};
let mbc: Box<super::mbc::mbc::MBC> = match mbc_type {
MemoryBankControllerType::None => Box::new(super::mbc::mbc::NoMBC::new(rom, ram)),
MemoryBankControllerType::MBC3 => Box::new(super::mbc::mbc3::MBC3::new(rom, ram)),
_ => panic!("{:?} not implemented", mbc_type),
};
Cartridge {
rom: rom,
mbc_type: mbc,
bank_no: 1,
ram_rtc_enabled: false,
ram_bank_no: 0,
ram_size: ram_size,
rom_banks: rom_banks,
ram: ram,
bank_mode: 0,
bank_no_high: 0,
mbc: mbc,
mbc_type: mbc_type,
}
}
pub fn read_byte_mbc3(&self, addr: u16) -> u8 {
match addr {
0x0000 ... 0x3FFF => self.rom[addr as usize],
0x4000 ... 0x7FFF => {
let addr = addr - 0x4000;
// println!("BankNo: {:02X}", self.bank_no);
let abs_addr: usize = addr as usize + self.bank_no as usize * 0x4000;
let val: u8 = self.rom[abs_addr];
val
},
0xA000 ... 0xBFFF => {
// TODO: Safty checks? Or let rust handle this?
let addr = addr - 0xA000;
if self.ram_bank_no < 4 {
self.ram[self.ram_bank_no as usize * 0x2000 + addr as usize]
} else {
println!("Ignoring RTC read");
0
}
}
_ => {
panic!("Cartride: Unable to read from {:04X}", addr);
}
}
}
pub fn read_byte_mbc1(&self, addr: u16) -> u8 {
match addr {
0x0000 ... 0x3FFF => self.rom[addr as usize],
0x4000 ... 0x7FFF => {
let addr = addr - 0x4000;
let mut bank: u8 = self.bank_no;
if self.bank_mode == 0 {
bank |= self.bank_no_high << 5;
}
// println!("BankNo: {:02X}", bank);
let abs_addr: usize = addr as usize + bank as usize * 0x4000;
let val: u8 = self.rom[abs_addr];
val
},
0xA000 ... 0xBFFF => {
// TODO: Safty checks? Or let rust handle this?
let addr = addr - 0xA000;
let mut bank: u8 = 0;
if self.bank_mode == 1 {
bank = self.bank_no_high
}
self.ram[bank as usize * 0x2000 + addr as usize]
}
_ => {
panic!("Cartride: Unable to read from {:04X}", addr);
}
}
}
pub fn read_byte(&self, addr: u16) -> u8{
match self.mbc_type {
MemoryBankControllerType::MBC1 => self.read_byte_mbc1(addr),
MemoryBankControllerType::MBC3 | MemoryBankControllerType::None => self.read_byte_mbc3(addr),
_ => panic!("MBC not supported.")
}
}
fn write_byte_none(&mut self, addr: u16, val: u8) {
match addr {
0xA000 ... 0xBFFF => {
// self.ram[addr as usize - 0xA000] = val;
println!("No MBC, ignoring RAM write {:02X} to {:04X}", val, addr);
}
_ => println!("No MBC, unable to write {:02X} to {:04X}", val, addr),
}
}
fn write_byte_mbc1(&mut self, addr: u16, val: u8) {
match addr {
0x2000 ... 0x3FFF => {
// Write low bits of addr.
self.bank_no &= 0xE0;
self.bank_no |= val & 0x1F;
// Can't select 0x00, 0x20, 0x40, 0x60. Adapt it to 0x01, 0x21, 0x41, 0x61
if self.bank_no & 0x1F == 0 {
self.bank_no |= 1;
}
}
0x4000 ... 0x5FFF => {
self.bank_no_high = val & 3;
}
0x6000 ... 0x7FFF => {
self.bank_mode = val & 1;
}
_ => panic!("MBC1 Write {:02X} to {:04X} unsupported", val, addr),
}
}
fn write_byte_mbc3(&mut self, addr: u16, val: u8) {
match addr {
0x0000 ... 0x1FFF => {
match val {
0x0A => self.ram_rtc_enabled = true,
0x00 => self.ram_rtc_enabled = false,
_ => println!("Unknown MBC value {:02X} for {:04X}", val, addr)
}
},
0x2000 ... 0x3FFF => self.bank_no = val & 0x7F,
0x4000 ... 0x5FFF => {
// RAM bank select
match val {
0x00 ... 0x03 => self.ram_bank_no = val,
0x08 ... 0x0C => self.ram_bank_no = val, // RTC clock values, TODO
_ => panic!("Unknown MBC3 RAM BANK NO: {:02X}", val)
}
},
0x6000 ... 0x7FFF => {
// Latch clock data, ignore.
},
0xA000 ... 0xBFFF => {
// TODO: Safty checks? Or let rust handle this?
let addr = addr - 0xA000;
if self.ram_bank_no < 4 {
self.ram[self.ram_bank_no as usize * 0x2000 + addr as usize] = val;
} else {
println!("Ignoring RTC write");
}
}
_ => panic!("MBC3: Writing {:02X} to {:04X} not supported", val, addr),
}
pub fn read_byte(&self, addr: u16) -> u8 {
self.mbc.read_byte(addr)
}
pub fn write_byte(&mut self, addr: u16, val: u8) {
match self.mbc_type {
MemoryBankControllerType::None => self.write_byte_none(addr, val),
MemoryBankControllerType::MBC1 => self.write_byte_mbc1(addr, val),
MemoryBankControllerType::MBC3 => self.write_byte_mbc3(addr, val),
_ => panic!("MBC not supported.")
}
self.mbc.write_byte(addr, val);
}
}

View File

@ -157,7 +157,7 @@ impl CPU {
self.set_flag(FLAG_N);
self.set_clear_flag(FLAG_Z, new == 0);
self.set_clear_flag(FLAG_C, new > old || (new == old && c == 1));
self.set_clear_flag(FLAG_H, ((old & 0x0F) - (val & 0x0F) - c) > 0x0F);
self.set_clear_flag(FLAG_H, ((old & 0x0F).wrapping_sub((val & 0x0F)).wrapping_sub(c)) > 0x0F);
}
#[inline]
@ -658,7 +658,7 @@ impl CPU {
#[inline]
fn rst(&mut self, val: u8) -> u8 {
// Make sure this is correct.
if self.debug || true {
if self.debug {
println!("RST {:02X}", val);
}
self.call(val as u16);
@ -887,7 +887,7 @@ impl CPU {
// println!("Handling vblank interrupt");
self.handle_interrupt(0x40, interconnect::INTERRUPT_DISPLAY_VBLANK);
} else if e_pending & interconnect::INTERRUPT_DISPLAY_STAT > 0 {
println!("Handling display stat interrupt");
// println!("Handling display stat interrupt");
self.handle_interrupt(0x48, interconnect::INTERRUPT_DISPLAY_STAT);
} else if e_pending & interconnect::INTERRUPT_TIMER_OVERFLOW > 0{
println!("Handling timer interrupt");
@ -985,7 +985,10 @@ impl CPU {
4
}
0x10 => panic!("STOP 0 {:02X} not implemented.", self.load_args(1)[0]),
0x10 => {
println!("STOP 0 {:02X} not implemented.", self.load_args(1)[0]);
4
},
0x11 => self.ld_rr_vv(REG_N_D, REG_N_E),
0x12 => self.ld_dref_rr_a(REG_N_D, REG_N_E),
0x13 => self.inc_rr(REG_N_D, REG_N_E),
@ -1192,7 +1195,7 @@ impl CPU {
if self.debug {
println!("LD A, (HL-)");
}
let mut addr = self.get_pair_value(REG_N_H, REG_N_L);
let addr = self.get_pair_value(REG_N_H, REG_N_L);
self.regs[REG_A] = self.interconnect.read_byte(addr);
self.set_pair_value(REG_N_H, REG_N_L, addr.wrapping_sub(1));
8

View File

@ -72,7 +72,6 @@ pub struct Display {
pub event_pump: sdl2::EventPump,
vblank_fired: bool,
vblank_interrupt: bool,
stat_interrupt: bool,
}
@ -83,7 +82,7 @@ impl Display {
let video_ctx = sdl_ctx.video().unwrap();
let wnd = video_ctx.window("RustBoy", (GB_PIXELS_X * SCALE) as u32, (GB_PIXELS_Y * SCALE) as u32).position_centered().build().expect("Failed to create window :<");
let renderer = wnd.renderer().build().expect("Could not build renderer");
let mut event_pump = sdl_ctx.event_pump().expect("Getting event pump failed");
let event_pump = sdl_ctx.event_pump().expect("Getting event pump failed");
Display {
control: 0,
@ -106,7 +105,6 @@ impl Display {
event_pump: event_pump,
vblank_fired: false,
vblank_interrupt: false,
stat_interrupt: false,
}
@ -401,8 +399,8 @@ impl Display {
false => 8
};
for x_o in 0 .. limit {
let mut b1: bool;
let mut b2: bool;
let b1: bool;
let b2: bool;
let mut factor = 0;
if wide_mode && x_o > 7 {
b1 = (tile_line_3 & 1 << (14 - x_o)) > 0;

View File

@ -193,6 +193,9 @@ impl Interconnect {
},
0xD000 ... 0xDFFF => {
self.ram[(addr - 0xD000) as usize + self.wram_bank as usize * 0x1000]
},
0xE000 ... 0xEFFF => {
self.ram[(addr - 0xE000) as usize]
}
0xFF00 => {
if self.joy_switch & KEY_REGULAR == 0 {
@ -201,7 +204,7 @@ impl Interconnect {
self.joy_special_keys
} else {
println!("Reading none from joystick?");
0xFF
0x3F
}
}
0xFF01 ... 0xFF02 => self.serial.read_byte(addr),
@ -238,7 +241,8 @@ impl Interconnect {
self.interrupt
}
_ => {
panic!("Read from {:04X} not supported.", addr);
println!("Read from {:04X} not supported.", addr);
0
}
}
}

View File

@ -13,6 +13,8 @@ mod interconnect;
mod sound;
mod timer;
mod serial;
mod mbc;
fn main() {
let bios_path = env::args().nth(1).unwrap();

40
src/mbc/mbc.rs Normal file
View File

@ -0,0 +1,40 @@
pub trait MBC {
fn read_byte(&self, addr: u16) -> u8;
fn write_byte(&mut self, addr: u16, val: u8);
}
pub struct NoMBC {
rom: Box<[u8]>,
ram: Box<[u8]>,
}
impl NoMBC {
pub fn new(rom: Box<[u8]>, ram: Box<[u8]>) -> NoMBC {
NoMBC {
rom: rom,
ram: ram,
}
}
}
impl MBC for NoMBC {
fn write_byte(&mut self, addr: u16, val: u8) {
panic!("Writing not supported for cartridges without MBC.");
}
fn read_byte(&self, addr: u16) -> u8 {
match addr {
0x0000 ... 0x7FFF => self.rom[addr as usize],
0xA000 ... 0xBFFF => {
// TODO: Check for ram
let addr = (addr as usize) - 0xA000;
self.ram[addr]
}
_ => {
panic!("Cartride: Unable to read from {:04X}", addr);
}
}
}
}

93
src/mbc/mbc3.rs Normal file
View File

@ -0,0 +1,93 @@
use super::mbc::MBC;
pub struct MBC3 {
rom: Box<[u8]>,
ram: Box<[u8]>,
bank_no: u8,
ram_rtc_enabled: bool,
ram_bank_no: u8,
rom_banks: u16,
bank_mode: u8,
bank_no_high: u8,
}
impl MBC3 {
pub fn new(rom: Box<[u8]>, ram: Box<[u8]>) -> MBC3 {
MBC3 {
rom: rom,
ram: ram,
bank_no: 0,
ram_rtc_enabled: false,
ram_bank_no: 0,
rom_banks: 0,
bank_mode: 0,
bank_no_high: 0,
}
}
}
impl MBC for MBC3 {
fn read_byte(&self, addr: u16) -> u8 {
match addr {
0x0000 ... 0x3FFF => self.rom[addr as usize],
0x4000 ... 0x7FFF => {
let addr = addr - 0x4000;
// println!("BankNo: {:02X}", self.bank_no);
let abs_addr: usize = addr as usize + self.bank_no as usize * 0x4000;
let val: u8 = self.rom[abs_addr];
val
},
0xA000 ... 0xBFFF => {
// TODO: Safty checks? Or let rust handle this?
let addr = addr - 0xA000;
if self.ram_bank_no < 4 {
println!("Access [{:02X}] {:04X}", self.ram_bank_no, addr);
self.ram[self.ram_bank_no as usize * 0x2000 + addr as usize]
} else {
println!("Ignoring RTC read");
0
}
}
_ => {
panic!("Cartride: Unable to read from {:04X}", addr);
}
}
}
fn write_byte(&mut self, addr: u16, val: u8) {
match addr {
0x0000 ... 0x1FFF => {
match val {
0x0A => self.ram_rtc_enabled = true,
0x00 => self.ram_rtc_enabled = false,
_ => println!("Unknown MBC value {:02X} for {:04X}", val, addr)
}
},
0x2000 ... 0x3FFF => self.bank_no = val & 0x7F,
0x4000 ... 0x5FFF => {
// RAM bank select
match val {
0x00 ... 0x03 => self.ram_bank_no = 0, //val,
0x08 ... 0x0C => self.ram_bank_no = val, // RTC clock values, TODO
_ => panic!("Unknown MBC3 RAM BANK NO: {:02X}", val)
}
},
0x6000 ... 0x7FFF => {
// Latch clock data, ignore.
},
0xA000 ... 0xBFFF => {
// TODO: Safty checks? Or let rust handle this?
let addr = addr - 0xA000;
if self.ram_bank_no < 4 {
self.ram[self.ram_bank_no as usize * 0x2000 + addr as usize] = val;
} else {
println!("Ignoring RTC write");
}
}
_ => panic!("MBC3: Writing {:02X} to {:04X} not supported", val, addr),
}
}
}

2
src/mbc/mod.rs Normal file
View File

@ -0,0 +1,2 @@
pub mod mbc;
pub mod mbc3;