Files
EightBit/LR35902/src/Bus.cpp
2017-08-24 23:47:28 +01:00

163 lines
3.3 KiB
C++

#include "stdafx.h"
#include "Bus.h"
EightBit::Bus::Bus()
: Memory(0xffff),
m_disableBootRom(false),
m_disableGameRom(false),
m_rom(false),
m_ram(false),
m_battery(false),
m_higherRomBank(true),
m_ramBankSwitching(false),
m_romBank(1),
m_ramBank(0),
m_divCounter(256),
m_timerCounter(0),
m_timerRate(0) {
m_bootRom.resize(0x100);
m_gameRom.resize(0x10000);
WrittenByte.connect(std::bind(&Bus::Bus_WrittenByte, this, std::placeholders::_1));
}
void EightBit::Bus::reset() {
writeRegister(NR52, 0xf1);
writeRegister(LCDC, 0x91);
}
void EightBit::Bus::clear() {
Memory::clear();
std::fill(m_bootRom.begin(), m_bootRom.end(), 0);
std::fill(m_gameRom.begin(), m_gameRom.end(), 0);
}
void EightBit::Bus::loadBootRom(const std::string& path) {
loadBinary(path, m_bootRom, 0, 0x100);
}
void EightBit::Bus::loadGameRom(const std::string& path) {
loadBinary(path, m_gameRom);
validateCartridgeType();
}
uint8_t& EightBit::Bus::reference(uint16_t address, bool& rom) {
rom = true;
if ((address < 0x100) && bootRomEnabled())
return m_bootRom[address];
if ((address < 0x4000) && gameRomEnabled())
return m_gameRom[address];
if ((address < 0x8000) && gameRomEnabled())
return m_gameRom[(address - RomPageSize) + (m_romBank * RomPageSize)];
rom = false;
return m_bus[address];
}
void EightBit::Bus::Bus_WrittenByte(const AddressEventArgs& e) {
const auto address = e.getAddress();
const auto value = e.getCell();
auto handled = false;
switch (address & 0xe000) {
case 0x0000:
// Register 0: RAMCS gate data
if (m_ram) {
assert(false);
}
break;
case 0x2000:
// Register 1: ROM bank code
if (m_banked && m_higherRomBank) {
assert((address >= 0x2000) && (address < 0x4000));
assert((value > 0) && (value < 0x20));
m_romBank = value & Processor::Mask5;
handled = true;
}
break;
case 0x4000:
// Register 2: ROM bank selection
if (m_banked) {
assert(false);
}
case 0x6000:
// Register 3: ROM/RAM change
if (m_banked) {
switch (value & Processor::Mask1) {
case 0:
m_higherRomBank = true;
m_ramBankSwitching = false;
break;
case 1:
m_higherRomBank = false;
m_ramBankSwitching = true;
break;
default:
__assume(0);
}
handled = true;
}
break;
}
if (!handled) {
switch (address) {
case BASE + TAC:
m_timerRate = timerClockTicks();
break;
case BASE + BOOT_DISABLE:
m_disableBootRom = value != 0;
break;
case BASE + DIV:
Memory::reference() = 0;
m_timerCounter = 0;
break;
}
}
}
void EightBit::Bus::checkTimers(int cycles) {
checkDiv(cycles);
checkTimer(cycles);
}
void EightBit::Bus::checkDiv(int cycles) {
m_divCounter -= cycles;
if (m_divCounter <= 0) {
m_divCounter = 256;
incrementDIV();
}
}
void EightBit::Bus::checkTimer(int cycles) {
if (timerEnabled()) {
m_timerCounter -= cycles;
if (m_timerCounter <= 0) {
m_timerCounter = m_timerRate;
incrementTIMA();
}
}
}
void EightBit::Bus::validateCartridgeType() {
m_rom = m_banked = m_ram = m_battery = false;
switch (m_gameRom[0x147]) {
case ROM:
m_rom = true;
break;
case ROM_MBC1:
m_rom = m_banked = true;
break;
case ROM_MBC1_RAM:
m_rom = m_banked = m_ram = true;
break;
case ROM_MBC1_RAM_BATTERY:
m_rom = m_banked = m_ram = m_battery = true;
break;
default:
throw std::domain_error("Unhandled cartridge ROM type");
}
}