- [NEW] MBC1 implementat

This commit is contained in:
2025-01-25 09:00:39 +01:00
parent b45ce4e76d
commit 63d1f6ef05
3 changed files with 213 additions and 0 deletions

200
mbc1.cpp Normal file
View File

@@ -0,0 +1,200 @@
#include "mbc1.h"
#include "mem.h"
#include <stdlib.h>
#include <SDL2/SDL.h>
namespace mbc1
{
#define ROM_BANK_SIZE 0x4000
#define RAM_BANK_SIZE 0x2000
uint8_t bootrom[256];
uint8_t *rom;
uint8_t vram[8192];
uint8_t exram[4 * RAM_BANK_SIZE];
uint8_t wram[8192];
uint8_t hram[512];
uint8_t tags[65536];
uint8_t current_rom_bank = 1;
uint8_t current_ram_bank = 0;
bool ram_enabled = false;
bool banking_mode = false; // false = ROM banking mode, true = RAM banking mode
uint8_t getKeypad(uint8_t value)
{
const uint8_t *keys = SDL_GetKeyboardState(NULL);
value = value & 0xf0;
if (value & 0x10) {
if (!keys[SDL_SCANCODE_RETURN]) value = value | 0x8;
if (!keys[SDL_SCANCODE_SPACE]) value = value | 0x4;
if (!keys[SDL_SCANCODE_Z]) value = value | 0x2;
if (!keys[SDL_SCANCODE_X]) value = value | 0x1;
} else if (value & 0x20) {
if (!keys[SDL_SCANCODE_DOWN]) value = value | 0x8;
if (!keys[SDL_SCANCODE_UP]) value = value | 0x4;
if (!keys[SDL_SCANCODE_LEFT]) value = value | 0x2;
if (!keys[SDL_SCANCODE_RIGHT]) value = value | 0x1;
} else {
value = value | 0x0f;
}
return value;
}
uint8_t readMem(uint16_t address)
{
if (address < 0x8000) {
if ( (address < 0x0100) && ((hram[0x150]&0x01)==0) ) return bootrom[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];
}
} else if (address < 0xA000) {
return vram[address - 0x8000];
} else if (address < 0xC000) {
if (ram_enabled) {
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
} else if (address < 0xE000) {
return wram[address - 0xC000];
} else if (address < 0xFE00) {
return wram[address - 0xE000];
} else {
if (address==0xFF00) {
hram[address - 0XFE00] = getKeypad(hram[address - 0XFE00]);
}
return hram[address - 0XFE00];
}
}
void writeMem(uint16_t address, uint8_t value)
{
if (address < 0x8000) {
if (address < 0x2000) {
// Enable/disable RAM
ram_enabled = (value & 0x0F) == 0x0A;
} else if (address < 0x4000) {
// Select ROM bank
value &= 0x1F; // Lower 5 bits are used
if (value == 0) value = 1; // Bank 0 is not allowed
current_rom_bank = (current_rom_bank & 0x60) | value;
} else if (address < 0x6000) {
// Select RAM bank or upper bits of ROM bank
if (banking_mode) {
current_ram_bank = value & 0x03; // 2 bits for RAM bank
} else {
current_rom_bank = (current_rom_bank & 0x1F) | ((value & 0x03) << 5);
}
} else {
// Select banking mode
banking_mode = value & 0x01;
}
} else if (address < 0xA000) {
vram[address - 0x8000] = value;
} else if (address < 0xC000) {
if (ram_enabled) {
uint32_t banked_address = (current_ram_bank * RAM_BANK_SIZE) + (address - 0xA000);
exram[banked_address] = value;
}
} else if (address < 0xE000) {
wram[address - 0xC000] = value;
} else if (address < 0xFE00) {
wram[address - 0xE000] = value;
} else {
if ( (address==0xFF50) && ((value&0x01) != 1) ) return; //Only allow disabling boot room
if ( (address==0xFF00) ) { value = value & 0x30; }
if ( (address==0xFF04) ) { hram[address-0xFE00] = 0; return; }
if ( (address==0xFF46) ) mem::init_dma_transfer(value);
hram[address - 0xFE00] = value;
}
}
uint8_t getTag(uint16_t address)
{
return tags[address];
}
void setTag(uint16_t address, uint8_t value)
{
tags[address] = value;
}
void saveState(FILE* f)
{
}
void loadState(FILE *f)
{
}
uint8_t* rawPtr(uint16_t address)
{
if (address < 0x8000) {
if ( (address < 0x0100) && ((hram[0x150]&0x01)==0) ) return &bootrom[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];
}
} else if (address < 0xA000) {
return &vram[address - 0x8000];
} else if (address < 0xC000) {
if (ram_enabled) {
uint32_t banked_address = (current_ram_bank * RAM_BANK_SIZE) + (address - 0xA000);
return &exram[banked_address];
}
return nullptr; // Return open bus value when RAM is disabled
} else if (address < 0xE000) {
return &wram[address - 0xC000];
} else if (address < 0xFE00) {
return &wram[address - 0xE000];
} else {
return &hram[address - 0XFE00];
}
}
void reset()
{
FILE *f = fopen("dmg_boot.bin", "rb");
if (!f) { printf("ABORTING: 'dmg_boot.bin' not found!\n"); exit(1); }
fseek(f, 0, SEEK_END);
const int size = ftell(f);
fseek(f, 0, SEEK_SET);
fread(bootrom, size, 1, f);
fclose(f);
for (int i=0; i<8192; ++i) { vram[i] = 0; }
for (int i=0; i<4*RAM_BANK_SIZE; ++i) { exram[i] = 0; }
for (int i=0; i<8192; ++i) { wram[i] = 0; }
for (int i=0; i<512; ++i) { hram[i] = 0; }
for (int i=0; i<65536; ++i) { tags[i] = MEMTAG_NONE; }
}
void init(uint8_t *rom, uint32_t rom_size, uint32_t ram_size)
{
mem::readMem = mbc1::readMem;
mem::writeMem = mbc1::writeMem;
mem::getTag = mbc1::getTag;
mem::setTag = mbc1::setTag;
mem::saveState = mbc1::saveState;
mem::loadState = mbc1::loadState;
mem::reset = mbc1::reset;
mem::rawPtr = mbc1::rawPtr;
mbc1::rom = rom;
reset();
}
}

7
mbc1.h Normal file
View File

@@ -0,0 +1,7 @@
#pragma once
#include <stdint.h>
namespace mbc1
{
void init(uint8_t *rom, uint32_t rom_size, uint32_t ram_size);
}

View File

@@ -4,6 +4,7 @@
#include <stdio.h>
#include "mbc_none.h"
#include "mbc1.h"
namespace mem
{
void (*reset)(void);
@@ -39,6 +40,11 @@ namespace mem
case 0x00:
mbc_none::init(rom, rom_size, ram_size);
break;
case 0x01:
case 0x02:
case 0x03:
mbc1::init(rom, rom_size, ram_size);
break;
};
}