- [NEW] MBC3 implementat
This commit is contained in:
128
mbc3.cpp
Normal file
128
mbc3.cpp
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
#include "mbc3.h"
|
||||||
|
#include "mem.h"
|
||||||
|
#include "sm83.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
15
mbc3.h
Normal file
15
mbc3.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
24
mem.cpp
24
mem.cpp
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "mbc_none.h"
|
#include "mbc_none.h"
|
||||||
#include "mbc1.h"
|
#include "mbc1.h"
|
||||||
|
#include "mbc3.h"
|
||||||
|
|
||||||
#define DIV hram[0x104] // 0xff04 - 0xfe00
|
#define DIV hram[0x104] // 0xff04 - 0xfe00
|
||||||
#define TIMA hram[0x105] // 0xff05 - 0xfe00
|
#define TIMA hram[0x105] // 0xff05 - 0xfe00
|
||||||
@@ -19,6 +20,7 @@ namespace mem
|
|||||||
void (*writeRom)(uint16_t, uint8_t);
|
void (*writeRom)(uint16_t, uint8_t);
|
||||||
uint8_t (*readRam)(uint16_t);
|
uint8_t (*readRam)(uint16_t);
|
||||||
void (*writeRam)(uint16_t, uint8_t);
|
void (*writeRam)(uint16_t, uint8_t);
|
||||||
|
void (*tick)(void) = nullptr;;
|
||||||
|
|
||||||
uint8_t bootrom[256];
|
uint8_t bootrom[256];
|
||||||
uint8_t *rom;
|
uint8_t *rom;
|
||||||
@@ -29,8 +31,10 @@ namespace mem
|
|||||||
uint8_t tags[65536];
|
uint8_t tags[65536];
|
||||||
|
|
||||||
char *title = nullptr;
|
char *title = nullptr;
|
||||||
|
uint8_t mapper_type = 0;
|
||||||
uint32_t rom_size = 0;
|
uint32_t rom_size = 0;
|
||||||
uint32_t ram_size = 0;
|
uint32_t ram_size = 0;
|
||||||
|
uint16_t timer = 0;
|
||||||
|
|
||||||
uint16_t dma_address = 0;
|
uint16_t dma_address = 0;
|
||||||
uint8_t dma_pos = 160;
|
uint8_t dma_pos = 160;
|
||||||
@@ -42,7 +46,7 @@ namespace mem
|
|||||||
void init(uint8_t* rom, const int size)
|
void init(uint8_t* rom, const int size)
|
||||||
{
|
{
|
||||||
title = (char*)&rom[0x134];
|
title = (char*)&rom[0x134];
|
||||||
uint8_t mapper_type = rom[0x147];
|
mapper_type = rom[0x147];
|
||||||
rom_size = 32768 * (1 << rom[0x148]);
|
rom_size = 32768 * (1 << rom[0x148]);
|
||||||
int sizes[] = { 0, 0, 8, 32, 128, 64};
|
int sizes[] = { 0, 0, 8, 32, 128, 64};
|
||||||
ram_size = sizes[rom[0x149]] * 1024;
|
ram_size = sizes[rom[0x149]] * 1024;
|
||||||
@@ -67,6 +71,19 @@ namespace mem
|
|||||||
mem::readRam = mbc1::readRam;
|
mem::readRam = mbc1::readRam;
|
||||||
mem::writeRam = mbc1::writeRam;
|
mem::writeRam = mbc1::writeRam;
|
||||||
break;
|
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();
|
APU::init();
|
||||||
@@ -207,6 +224,11 @@ namespace mem
|
|||||||
uint16_t timer_frequencies[4] { 256*4, 4*4, 16*4, 64*4 };
|
uint16_t timer_frequencies[4] { 256*4, 4*4, 16*4, 64*4 };
|
||||||
void update_mapped(const uint32_t dt)
|
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 Divider register (0xFF04) (val com a timer bàsic)
|
||||||
div_counter += dt;
|
div_counter += dt;
|
||||||
if (div_counter>=256) {
|
if (div_counter>=256) {
|
||||||
|
|||||||
Reference in New Issue
Block a user