#include "mbc3.h" #include "mem.h" #include "sm83.h" #include #include namespace mbc3 { #define ROM_BANK_SIZE 0x4000 #define RAM_BANK_SIZE 0x2000 uint8_t *rom; uint8_t exram[4 * RAM_BANK_SIZE]; uint8_t current_rom_bank = 1; uint8_t current_ram_bank = 0; bool ram_enabled = false; bool rtc_mode = false; // false = ROM banking mode, true = RAM banking mode uint8_t rtc_reg = 0; uint8_t rtc_latch = 1; uint8_t RTC[5] {0,0,0,0,0}; uint8_t RTC_latched[5] {0,0,0,0,0}; void reset() { for (int i=0; i<4*RAM_BANK_SIZE; ++i) { exram[i] = 0; } } void tick() { RTC[0]++; if (RTC[0]==60) { RTC[0] = 0; RTC[1]++; if (RTC[1]==60) { RTC[1] = 0; RTC[2]++; if (RTC[2]==24) { if (RTC[3]==0xff) { RTC[3]=0; if (RTC[4]&0x01) { RTC[4] = RTC[4] & 0xfe; RTC[4] = (RTC[4] & 0x80) ? RTC[4] & 0x7f : RTC[4] | 0x80; } else { RTC[4] = RTC[4] | 0x01; } } else RTC[3]++; } } } } void latchClock() { for (int i=0; i<5; ++i) RTC_latched[i] = RTC[i]; } uint8_t readRom(uint16_t address) { if (address < 0x4000) { // ROM Bank 0 return rom[address]; } else { // Switchable ROM bank uint32_t banked_address = (current_rom_bank * ROM_BANK_SIZE) + (address - 0x4000); return rom[banked_address]; } } void writeRom(uint16_t address, uint8_t value) { if (address < 0x2000) { // Enable/disable RAM ram_enabled = (value & 0x0F) == 0x0A; } else if (address < 0x4000) { // Select ROM bank if (value == 0) value = 1; // Bank 0 is not allowed current_rom_bank = current_rom_bank = (value & 0x7F); } else if (address < 0x6000) { // Select RAM bank or upper bits of ROM bank if (value<=0x03) { rtc_mode = false; current_ram_bank = value & 0x03; // 2 bits for RAM bank } else if ( (value >= 0x8) && (value <= 0x0c) ) { rtc_mode = true; rtc_reg = value-8; } } else { // Select banking mode if ( (rtc_latch == 0) && (value == 1) ) { latchClock(); } rtc_latch = value; } } uint8_t readRam(uint16_t address) { if (ram_enabled) { if (rtc_mode) { return RTC_latched[rtc_reg]; } else { uint32_t banked_address = (current_ram_bank * RAM_BANK_SIZE) + (address - 0xa000); return exram[banked_address]; } } return 0xff; // Return open bus value when RAM is disabled } void writeRam(uint16_t address, uint8_t value) { if (ram_enabled) { if (rtc_mode) { RTC[rtc_reg] = RTC_latched[rtc_reg] = value; } else { uint32_t banked_address = (current_ram_bank * RAM_BANK_SIZE) + (address - 0xa000); exram[banked_address] = value; } } } void init(uint8_t *rom, uint32_t rom_size, uint32_t ram_size) { mbc3::rom = rom; reset(); } }