From f8ce7068399f5597a620917b9be6695eb29ca4b5 Mon Sep 17 00:00:00 2001 From: Raimon Zamora Date: Thu, 30 Jan 2025 17:14:09 +0100 Subject: [PATCH] - [NEW] MBC3 implementat --- mbc3.cpp | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ mbc3.h | 15 +++++++ mem.cpp | 24 ++++++++++- 3 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 mbc3.cpp create mode 100644 mbc3.h diff --git a/mbc3.cpp b/mbc3.cpp new file mode 100644 index 0000000..198cae2 --- /dev/null +++ b/mbc3.cpp @@ -0,0 +1,128 @@ +#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(); + } +} \ No newline at end of file diff --git a/mbc3.h b/mbc3.h new file mode 100644 index 0000000..414973f --- /dev/null +++ b/mbc3.h @@ -0,0 +1,15 @@ +#pragma once +#include + +namespace mbc3 +{ + void init(uint8_t *rom, uint32_t rom_size, uint32_t ram_size); + + void tick(); + + void reset(); + uint8_t readRom(uint16_t address); + void writeRom(uint16_t address, uint8_t value); + uint8_t readRam(uint16_t address); + void writeRam(uint16_t address, uint8_t value); +} diff --git a/mem.cpp b/mem.cpp index 94abf55..a87612f 100644 --- a/mem.cpp +++ b/mem.cpp @@ -7,6 +7,7 @@ #include "mbc_none.h" #include "mbc1.h" +#include "mbc3.h" #define DIV hram[0x104] // 0xff04 - 0xfe00 #define TIMA hram[0x105] // 0xff05 - 0xfe00 @@ -19,6 +20,7 @@ namespace mem void (*writeRom)(uint16_t, uint8_t); uint8_t (*readRam)(uint16_t); void (*writeRam)(uint16_t, uint8_t); + void (*tick)(void) = nullptr;; uint8_t bootrom[256]; uint8_t *rom; @@ -29,8 +31,10 @@ namespace mem uint8_t tags[65536]; char *title = nullptr; + uint8_t mapper_type = 0; uint32_t rom_size = 0; uint32_t ram_size = 0; + uint16_t timer = 0; uint16_t dma_address = 0; uint8_t dma_pos = 160; @@ -42,7 +46,7 @@ namespace mem void init(uint8_t* rom, const int size) { title = (char*)&rom[0x134]; - uint8_t mapper_type = rom[0x147]; + mapper_type = rom[0x147]; rom_size = 32768 * (1 << rom[0x148]); int sizes[] = { 0, 0, 8, 32, 128, 64}; ram_size = sizes[rom[0x149]] * 1024; @@ -67,6 +71,19 @@ namespace mem mem::readRam = mbc1::readRam; mem::writeRam = mbc1::writeRam; break; + case 0x0f: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + mbc3::init(rom, rom_size, ram_size); + mem::resetMbc = mbc3::reset; + mem::readRom = mbc3::readRom; + mem::writeRom = mbc3::writeRom; + mem::readRam = mbc3::readRam; + mem::writeRam = mbc3::writeRam; + mem::tick = mbc3::tick; + break; }; APU::init(); @@ -207,6 +224,11 @@ namespace mem uint16_t timer_frequencies[4] { 256*4, 4*4, 16*4, 64*4 }; void update_mapped(const uint32_t dt) { + timer+=dt; + if (timer >= 4194304 ) { + timer -= 4194304; + if (mem::tick) mem::tick(); + } // DIV Divider register (0xFF04) (val com a timer bàsic) div_counter += dt; if (div_counter>=256) {