Rewrote MBC support
This commit is contained in:
parent
78a809795e
commit
c6bafe3fc3
@ -855,7 +855,7 @@ static bool mbc(GB_gameboy_t *gb, char *arguments)
|
||||
GB_log(gb, "RAM is curently %s\n", gb->mbc_ram_enable? "enabled" : "disabled");
|
||||
}
|
||||
if (cartridge->mbc_type == GB_MBC1) {
|
||||
GB_log(gb, "MBC1 banking mode is %s\n", gb->mbc_ram_banking? "RAM" : "ROM");
|
||||
GB_log(gb, "MBC1 banking mode is %s\n", gb->mbc1.mode == 1 ? "RAM" : "ROM");
|
||||
}
|
||||
|
||||
}
|
||||
|
57
Core/gb.c
57
Core/gb.c
@ -14,50 +14,7 @@
|
||||
#include "joypad.h"
|
||||
#include "display.h"
|
||||
#include "debugger.h"
|
||||
|
||||
static const GB_cartridge_t cart_defs[256] = {
|
||||
// From http://gbdev.gg8.se/wiki/articles/The_Cartridge_Header#0147_-_Cartridge_Type
|
||||
/* MBC RAM BAT. RTC RUMB. */
|
||||
{ GB_NO_MBC, false, false, false, false}, // 00h ROM ONLY
|
||||
{ GB_MBC1 , false, false, false, false}, // 01h MBC1
|
||||
{ GB_MBC1 , true , false, false, false}, // 02h MBC1+RAM
|
||||
{ GB_MBC1 , true , true , false, false}, // 03h MBC1+RAM+BATTERY
|
||||
[5] =
|
||||
{ GB_MBC2 , true , false, false, false}, // 05h MBC2
|
||||
{ GB_MBC2 , true , true , false, false}, // 06h MBC2+BATTERY
|
||||
[8] =
|
||||
{ GB_NO_MBC, true , false, false, false}, // 08h ROM+RAM
|
||||
{ GB_NO_MBC, true , true , false, false}, // 09h ROM+RAM+BATTERY
|
||||
[0xB] =
|
||||
// Todo: What are these?
|
||||
{ GB_NO_MBC, false, false, false, false}, // 0Bh MMM01
|
||||
{ GB_NO_MBC, false, false, false, false}, // 0Ch MMM01+RAM
|
||||
{ GB_NO_MBC, false, false, false, false}, // 0Dh MMM01+RAM+BATTERY
|
||||
[0xF] =
|
||||
{ GB_MBC3 , false, true, true , false}, // 0Fh MBC3+TIMER+BATTERY
|
||||
{ GB_MBC3 , true , true, true , false}, // 10h MBC3+TIMER+RAM+BATTERY
|
||||
{ GB_MBC3 , false, false, false, false}, // 11h MBC3
|
||||
{ GB_MBC3 , true , false, false, false}, // 12h MBC3+RAM
|
||||
{ GB_MBC3 , true , true , false, false}, // 13h MBC3+RAM+BATTERY
|
||||
[0x15] =
|
||||
// Todo: Do these exist?
|
||||
{ GB_MBC4 , false, false, false, false}, // 15h MBC4
|
||||
{ GB_MBC4 , true , false, false, false}, // 16h MBC4+RAM
|
||||
{ GB_MBC4 , true , true , false, false}, // 17h MBC4+RAM+BATTERY
|
||||
[0x19] =
|
||||
{ GB_MBC5 , false, false, false, false}, // 19h MBC5
|
||||
{ GB_MBC5 , true , false, false, false}, // 1Ah MBC5+RAM
|
||||
{ GB_MBC5 , true , true , false, false}, // 1Bh MBC5+RAM+BATTERY
|
||||
{ GB_MBC5 , false, false, false, true }, // 1Ch MBC5+RUMBLE
|
||||
{ GB_MBC5 , true , false, false, true }, // 1Dh MBC5+RUMBLE+RAM
|
||||
{ GB_MBC5 , true , true , false, true }, // 1Eh MBC5+RUMBLE+RAM+BATTERY
|
||||
[0xFC] =
|
||||
// Todo: What are these?
|
||||
{ GB_NO_MBC, false, false, false, false}, // FCh POCKET CAMERA
|
||||
{ GB_NO_MBC, false, false, false, false}, // FDh BANDAI TAMA5
|
||||
{ GB_NO_MBC, false, false, false, false}, // FEh HuC3
|
||||
{ GB_NO_MBC, true , true , false, false}, // FFh HuC1+RAM+BATTERY
|
||||
};
|
||||
#include "mbc.h"
|
||||
|
||||
void GB_attributed_logv(GB_gameboy_t *gb, GB_log_attributes attributes, const char *fmt, va_list args)
|
||||
{
|
||||
@ -131,7 +88,7 @@ void GB_init(GB_gameboy_t *gb)
|
||||
gb->sprite_palletes_rgb[5] = gb->sprite_palletes_rgb[1] = gb->background_palletes_rgb[1] = 0xAAAAAAAA;
|
||||
gb->sprite_palletes_rgb[6] = gb->sprite_palletes_rgb[2] = gb->background_palletes_rgb[2] = 0x55555555;
|
||||
gb->input_callback = default_input_callback;
|
||||
gb->cartridge_type = &cart_defs[0]; // Default cartridge type
|
||||
gb->cartridge_type = &GB_cart_defs[0]; // Default cartridge type
|
||||
|
||||
gb->io_registers[GB_IO_JOYP] = 0xF;
|
||||
}
|
||||
@ -155,7 +112,7 @@ void GB_init_cgb(GB_gameboy_t *gb)
|
||||
gb->last_vblank = clock();
|
||||
gb->cgb_ram_bank = 1;
|
||||
gb->input_callback = default_input_callback;
|
||||
gb->cartridge_type = &cart_defs[0]; // Default cartridge type
|
||||
gb->cartridge_type = &GB_cart_defs[0]; // Default cartridge type
|
||||
|
||||
gb->io_registers[GB_IO_JOYP] = 0xF;
|
||||
}
|
||||
@ -197,12 +154,18 @@ int GB_load_rom(GB_gameboy_t *gb, const char *path)
|
||||
if (!f) return errno;
|
||||
fseek(f, 0, SEEK_END);
|
||||
gb->rom_size = (ftell(f) + 0x3FFF) & ~0x3FFF; /* Round to bank */
|
||||
/* And then round to a power of two */
|
||||
while (gb->rom_size & (gb->rom_size - 1)) {
|
||||
/* I promise this works. */
|
||||
gb->rom_size |= gb->rom_size >> 1;
|
||||
gb->rom_size++;
|
||||
}
|
||||
fseek(f, 0, SEEK_SET);
|
||||
gb->rom = malloc(gb->rom_size);
|
||||
memset(gb->rom, 0xFF, gb->rom_size); /* Pad with 0xFFs */
|
||||
fread(gb->rom, gb->rom_size, 1, f);
|
||||
fclose(f);
|
||||
gb->cartridge_type = &cart_defs[gb->rom[0x147]];
|
||||
gb->cartridge_type = &GB_cart_defs[gb->rom[0x147]];
|
||||
if (gb->cartridge_type->has_ram) {
|
||||
static const int ram_sizes[256] = {0, 0x800, 0x2000, 0x8000, 0x20000, 0x10000};
|
||||
gb->mbc_ram_size = ram_sizes[gb->rom[0x149]];
|
||||
|
25
Core/gb.h
25
Core/gb.h
@ -226,7 +226,30 @@ typedef struct GB_gameboy_s {
|
||||
uint8_t mbc_ram_bank;
|
||||
uint32_t mbc_ram_size;
|
||||
bool mbc_ram_enable;
|
||||
bool mbc_ram_banking;
|
||||
union {
|
||||
struct {
|
||||
uint8_t bank_low:5;
|
||||
uint8_t bank_high:3;
|
||||
uint8_t mode:1;
|
||||
} mbc1;
|
||||
|
||||
struct {
|
||||
uint8_t rom_bank:4;
|
||||
} mbc2;
|
||||
|
||||
struct {
|
||||
uint8_t rom_bank:7;
|
||||
uint8_t padding:1;
|
||||
uint8_t ram_bank:4;
|
||||
} mbc3;
|
||||
|
||||
struct {
|
||||
uint8_t rom_bank_low;
|
||||
uint8_t rom_bank_high:1;
|
||||
uint8_t ram_bank:4;
|
||||
} mbc5;
|
||||
};
|
||||
uint16_t mbc_rom0_bank; /* For some MBC1 wirings. */
|
||||
);
|
||||
|
||||
|
||||
|
78
Core/mbc.c
Normal file
78
Core/mbc.c
Normal file
@ -0,0 +1,78 @@
|
||||
#include <stdbool.h>
|
||||
#include "gb.h"
|
||||
|
||||
const GB_cartridge_t GB_cart_defs[256] = {
|
||||
// From http://gbdev.gg8.se/wiki/articles/The_Cartridge_Header#0147_-_Cartridge_Type
|
||||
/* MBC RAM BAT. RTC RUMB. */
|
||||
{ GB_NO_MBC, false, false, false, false}, // 00h ROM ONLY
|
||||
{ GB_MBC1 , false, false, false, false}, // 01h MBC1
|
||||
{ GB_MBC1 , true , false, false, false}, // 02h MBC1+RAM
|
||||
{ GB_MBC1 , true , true , false, false}, // 03h MBC1+RAM+BATTERY
|
||||
[5] =
|
||||
{ GB_MBC2 , true , false, false, false}, // 05h MBC2
|
||||
{ GB_MBC2 , true , true , false, false}, // 06h MBC2+BATTERY
|
||||
[8] =
|
||||
{ GB_NO_MBC, true , false, false, false}, // 08h ROM+RAM
|
||||
{ GB_NO_MBC, true , true , false, false}, // 09h ROM+RAM+BATTERY
|
||||
[0xB] =
|
||||
// Todo: What are these?
|
||||
{ GB_NO_MBC, false, false, false, false}, // 0Bh MMM01
|
||||
{ GB_NO_MBC, false, false, false, false}, // 0Ch MMM01+RAM
|
||||
{ GB_NO_MBC, false, false, false, false}, // 0Dh MMM01+RAM+BATTERY
|
||||
[0xF] =
|
||||
{ GB_MBC3 , false, true, true , false}, // 0Fh MBC3+TIMER+BATTERY
|
||||
{ GB_MBC3 , true , true, true , false}, // 10h MBC3+TIMER+RAM+BATTERY
|
||||
{ GB_MBC3 , false, false, false, false}, // 11h MBC3
|
||||
{ GB_MBC3 , true , false, false, false}, // 12h MBC3+RAM
|
||||
{ GB_MBC3 , true , true , false, false}, // 13h MBC3+RAM+BATTERY
|
||||
[0x15] =
|
||||
// Todo: Do these exist?
|
||||
{ GB_MBC4 , false, false, false, false}, // 15h MBC4
|
||||
{ GB_MBC4 , true , false, false, false}, // 16h MBC4+RAM
|
||||
{ GB_MBC4 , true , true , false, false}, // 17h MBC4+RAM+BATTERY
|
||||
[0x19] =
|
||||
{ GB_MBC5 , false, false, false, false}, // 19h MBC5
|
||||
{ GB_MBC5 , true , false, false, false}, // 1Ah MBC5+RAM
|
||||
{ GB_MBC5 , true , true , false, false}, // 1Bh MBC5+RAM+BATTERY
|
||||
{ GB_MBC5 , false, false, false, true }, // 1Ch MBC5+RUMBLE
|
||||
{ GB_MBC5 , true , false, false, true }, // 1Dh MBC5+RUMBLE+RAM
|
||||
{ GB_MBC5 , true , true , false, true }, // 1Eh MBC5+RUMBLE+RAM+BATTERY
|
||||
[0xFC] =
|
||||
// Todo: What are these?
|
||||
{ GB_NO_MBC, false, false, false, false}, // FCh POCKET CAMERA
|
||||
{ GB_NO_MBC, false, false, false, false}, // FDh BANDAI TAMA5
|
||||
{ GB_NO_MBC, false, false, false, false}, // FEh HuC3
|
||||
{ GB_NO_MBC, true , true , false, false}, // FFh HuC1+RAM+BATTERY
|
||||
};
|
||||
|
||||
void GB_update_mbc_mappings(GB_gameboy_t *gb)
|
||||
{
|
||||
switch (gb->cartridge_type->mbc_type) {
|
||||
case GB_NO_MBC: case GB_MBC4: return;
|
||||
case GB_MBC1:
|
||||
/* Standard MBC1 wiring: */
|
||||
if (gb->mbc1.mode == 0) {
|
||||
gb->mbc_rom_bank = gb->mbc1.bank_low | (gb->mbc1.bank_high << 5);
|
||||
gb->mbc_ram_bank = 0;
|
||||
}
|
||||
else {
|
||||
gb->mbc_rom_bank = gb->mbc1.bank_low;
|
||||
gb->mbc_ram_bank = gb->mbc1.bank_high;
|
||||
}
|
||||
break;
|
||||
case GB_MBC2:
|
||||
gb->mbc_rom_bank = gb->mbc2.rom_bank;
|
||||
break;
|
||||
case GB_MBC3:
|
||||
gb->mbc_rom_bank = gb->mbc3.rom_bank;
|
||||
gb->mbc_ram_bank = gb->mbc3.ram_bank;
|
||||
break;
|
||||
case GB_MBC5:
|
||||
gb->mbc_rom_bank = gb->mbc5.rom_bank_low | (gb->mbc5.rom_bank_high << 8);
|
||||
gb->mbc_ram_bank = gb->mbc5.ram_bank;
|
||||
break;
|
||||
}
|
||||
if (gb->mbc_rom_bank == 0 && gb->cartridge_type->mbc_type != GB_MBC5) {
|
||||
gb->mbc_rom_bank = 1;
|
||||
}
|
||||
}
|
8
Core/mbc.h
Normal file
8
Core/mbc.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef MBC_h
|
||||
#define MBC_h
|
||||
#include "gb.h"
|
||||
|
||||
extern const GB_cartridge_t GB_cart_defs[256];
|
||||
void GB_update_mbc_mappings(GB_gameboy_t *gb);
|
||||
|
||||
#endif /* MBC_h */
|
145
Core/memory.c
145
Core/memory.c
@ -5,6 +5,7 @@
|
||||
#include "display.h"
|
||||
#include "memory.h"
|
||||
#include "debugger.h"
|
||||
#include "mbc.h"
|
||||
|
||||
typedef uint8_t GB_read_function_t(GB_gameboy_t *gb, uint16_t addr);
|
||||
typedef void GB_write_function_t(GB_gameboy_t *gb, uint16_t addr, uint8_t value);
|
||||
@ -22,15 +23,14 @@ static uint8_t read_rom(GB_gameboy_t *gb, uint16_t addr)
|
||||
if (!gb->rom_size) {
|
||||
return 0xFF;
|
||||
}
|
||||
return gb->rom[addr];
|
||||
unsigned int effective_address = (addr & 0x3FFF) + gb->mbc_rom0_bank * 0x4000;
|
||||
return gb->rom[effective_address & (gb->rom_size - 1)];
|
||||
}
|
||||
|
||||
static uint8_t read_mbc_rom(GB_gameboy_t *gb, uint16_t addr)
|
||||
{
|
||||
if (gb->mbc_rom_bank >= gb->rom_size / 0x4000) {
|
||||
return 0xFF;
|
||||
}
|
||||
return gb->rom[(addr & 0x3FFF) + gb->mbc_rom_bank * 0x4000];
|
||||
unsigned int effective_address = (addr & 0x3FFF) + gb->mbc_rom_bank * 0x4000;
|
||||
return gb->rom[effective_address & (gb->rom_size - 1)];
|
||||
}
|
||||
|
||||
static uint8_t read_vram(GB_gameboy_t *gb, uint16_t addr)
|
||||
@ -43,22 +43,19 @@ static uint8_t read_vram(GB_gameboy_t *gb, uint16_t addr)
|
||||
|
||||
static uint8_t read_mbc_ram(GB_gameboy_t *gb, uint16_t addr)
|
||||
{
|
||||
if (!gb->mbc_ram_enable) return 0xFF;
|
||||
|
||||
if (gb->cartridge_type->has_rtc && gb->mbc_ram_bank >= 8 && gb->mbc_ram_bank <= 0xC) {
|
||||
/* RTC read */
|
||||
gb->rtc_high |= ~0xC1; /* Not all bytes in RTC high are used. */
|
||||
return gb->rtc_data[gb->mbc_ram_bank - 8];
|
||||
}
|
||||
unsigned int ram_index = (addr & 0x1FFF) + gb->mbc_ram_bank * 0x2000;
|
||||
if (!gb->mbc_ram_enable)
|
||||
{
|
||||
GB_log(gb, "Read from %02x:%04x (%06x) (Disabled MBC RAM)\n", gb->mbc_ram_bank, addr, ram_index);
|
||||
|
||||
if (!gb->mbc_ram) {
|
||||
return 0xFF;
|
||||
}
|
||||
if (ram_index >= gb->mbc_ram_size) {
|
||||
GB_log(gb, "Read from %02x:%04x (%06x) (Unmapped MBC RAM)\n", gb->mbc_ram_bank, addr, ram_index);
|
||||
return 0xFF;
|
||||
}
|
||||
return gb->mbc_ram[(addr & 0x1FFF) + gb->mbc_ram_bank * 0x2000];
|
||||
|
||||
return gb->mbc_ram[((addr & 0x1FFF) + gb->mbc_ram_bank * 0x2000) & (gb->mbc_ram_size - 1)];
|
||||
}
|
||||
|
||||
static uint8_t read_ram(GB_gameboy_t *gb, uint16_t addr)
|
||||
@ -205,75 +202,41 @@ uint8_t GB_read_memory(GB_gameboy_t *gb, uint16_t addr)
|
||||
|
||||
static void write_mbc(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
{
|
||||
if (gb->cartridge_type->mbc_type == GB_NO_MBC) return;
|
||||
switch (addr >> 12) {
|
||||
case 0:
|
||||
case 1:
|
||||
gb->mbc_ram_enable = value == 0x0a;
|
||||
break;
|
||||
case 2:
|
||||
bank_low:
|
||||
/* Bank number, lower bits */
|
||||
if (gb->cartridge_type->mbc_type == GB_MBC1) {
|
||||
value &= 0x1F;
|
||||
}
|
||||
if (gb->cartridge_type->mbc_type != GB_MBC5 && !value) {
|
||||
value++;
|
||||
}
|
||||
gb->mbc_rom_bank = (gb->mbc_rom_bank & 0x100) | value;
|
||||
break;
|
||||
case 3:
|
||||
if (gb->cartridge_type->mbc_type != GB_MBC5) goto bank_low;
|
||||
if (value > 1) {
|
||||
GB_log(gb, "Bank overflow: [%x] <- %d\n", addr, value);
|
||||
}
|
||||
gb->mbc_rom_bank = (gb->mbc_rom_bank & 0xFF) | value << 8;
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
if (gb->cartridge_type->mbc_type == GB_MBC1) {
|
||||
if (gb->mbc_ram_banking) {
|
||||
gb->mbc_ram_bank = value & 0x3;
|
||||
}
|
||||
else {
|
||||
gb->mbc_rom_bank = (gb->mbc_rom_bank & 0x1F) | ((value & 0x3) << 5);
|
||||
}
|
||||
}
|
||||
else {
|
||||
gb->mbc_ram_bank = value;
|
||||
/* Some games assume banks wrap around. We can do this if RAM size is a power of two */
|
||||
if (gb->mbc_ram_bank >= gb->mbc_ram_size / 0x2000 && (gb->mbc_ram_size & (gb->mbc_ram_size - 1)) == 0 && gb->mbc_ram_size != 0) {
|
||||
gb->mbc_ram_bank %= gb->mbc_ram_size / 0x2000;
|
||||
}
|
||||
switch (gb->cartridge_type->mbc_type) {
|
||||
case GB_NO_MBC: case GB_MBC4: return;
|
||||
case GB_MBC1:
|
||||
switch (addr & 0xF000) {
|
||||
case 0x0000: case 0x1000: gb->mbc_ram_enable = (value & 0xF) == 0xA; break;
|
||||
case 0x2000: case 0x3000: gb->mbc1.bank_low = value; break;
|
||||
case 0x4000: case 0x5000: gb->mbc1.bank_high = value; break;
|
||||
case 0x6000: case 0x7000: gb->mbc1.mode = value; break;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
case 7:
|
||||
if (gb->cartridge_type->mbc_type == GB_MBC1) {
|
||||
value &= 1;
|
||||
|
||||
if (value & !gb->mbc_ram_banking) {
|
||||
gb->mbc_ram_bank = gb->mbc_rom_bank >> 5;
|
||||
gb->mbc_rom_bank &= 0x1F;
|
||||
}
|
||||
else if (value & !gb->mbc_ram_banking) {
|
||||
gb->mbc_rom_bank = gb->mbc_rom_bank | (gb->mbc_ram_bank << 5);
|
||||
gb->mbc_ram_bank = 0;
|
||||
}
|
||||
|
||||
gb->mbc_ram_banking = value;
|
||||
case GB_MBC2:
|
||||
switch (addr & 0xF000) {
|
||||
/* Todo: is this correct? */
|
||||
case 0x0000: case 0x1000: if (!(addr & 0x100)) gb->mbc_ram_enable = value & 0x1; break;
|
||||
case 0x2000: case 0x3000: if ( addr & 0x100) gb->mbc2.rom_bank = value; break;
|
||||
}
|
||||
break;
|
||||
case GB_MBC3:
|
||||
switch (addr & 0xF000) {
|
||||
case 0x0000: case 0x1000: gb->mbc_ram_enable = (value & 0xF) == 0xA; break;
|
||||
case 0x2000: case 0x3000: gb->mbc3.rom_bank = value; break;
|
||||
case 0x4000: case 0x5000: gb->mbc3.ram_bank = value; break;
|
||||
case 0x6000: case 0x7000: /* Todo: Clock latching support */ break;
|
||||
}
|
||||
break;
|
||||
case GB_MBC5:
|
||||
switch (addr & 0xF000) {
|
||||
case 0x0000: case 0x1000: gb->mbc_ram_enable = (value & 0xF) == 0xA; break;
|
||||
case 0x2000: gb->mbc5.rom_bank_low = value; break;
|
||||
case 0x3000: gb->mbc5.rom_bank_high = value; break;
|
||||
case 0x4000: case 0x5000: gb->mbc5.ram_bank = value; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Some games assume banks wrap around. We can do this if ROM size is a power of two */
|
||||
if (gb->mbc_rom_bank >= gb->rom_size / 0x4000 && (gb->rom_size & (gb->rom_size - 1)) == 0 && gb->rom_size != 0) {
|
||||
gb->mbc_rom_bank %= gb->rom_size / 0x4000;
|
||||
}
|
||||
|
||||
if (gb->cartridge_type->mbc_type != GB_MBC5 && !gb->mbc_rom_bank) {
|
||||
gb->mbc_rom_bank = 1;
|
||||
}
|
||||
GB_update_mbc_mappings(gb);
|
||||
}
|
||||
|
||||
static void write_vram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
@ -287,23 +250,23 @@ static void write_vram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
|
||||
static void write_mbc_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
{
|
||||
if (gb->mbc_ram_bank >= 8 && gb->mbc_ram_bank <= 0xC) {
|
||||
/* RTC write*/
|
||||
if (!gb->mbc_ram_enable) return;
|
||||
|
||||
if (gb->cartridge_type->has_rtc && gb->mbc_ram_bank >= 8 && gb->mbc_ram_bank <= 0xC) {
|
||||
/* RTC read */
|
||||
gb->rtc_data[gb->mbc_ram_bank - 8] = value;
|
||||
gb->rtc_high |= ~0xC1; /* Not all bytes in RTC high are used. */
|
||||
}
|
||||
|
||||
if (gb->cartridge_type->mbc_type == GB_MBC2) {
|
||||
value &= 0xF;
|
||||
}
|
||||
|
||||
if (!gb->mbc_ram) {
|
||||
return;
|
||||
}
|
||||
unsigned int ram_index = (addr & 0x1FFF) + gb->mbc_ram_bank * 0x2000;
|
||||
if (!gb->mbc_ram_enable)
|
||||
{
|
||||
GB_log(gb, "Write to %02x:%04x (%06x) (Disabled MBC RAM)\n", gb->mbc_ram_bank, addr, ram_index);
|
||||
return;
|
||||
}
|
||||
if (ram_index >= gb->mbc_ram_size) {
|
||||
GB_log(gb, "Write to %02x:%04x (%06x) (Unmapped MBC RAM)\n", gb->mbc_ram_bank, addr, ram_index);
|
||||
return;
|
||||
}
|
||||
gb->mbc_ram[(addr & 0x1FFF) + gb->mbc_ram_bank * 0x2000] = value;
|
||||
|
||||
gb->mbc_ram[((addr & 0x1FFF) + gb->mbc_ram_bank * 0x2000) & (gb->mbc_ram_size - 1)] = value;
|
||||
}
|
||||
|
||||
static void write_ram(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
|
Loading…
Reference in New Issue
Block a user