Replaced the is_cgb bool with a more future compatible model enum. Removed the GB_init_cgb API and replaced it with an extended GB_init and GB_switch_model_and_reset APIs that now receive a model parameter. Increased the struct version.

This commit is contained in:
Lior Halphon 2018-06-16 13:59:33 +03:00
parent c286203640
commit 45c73e0175
13 changed files with 155 additions and 118 deletions

View File

@ -18,6 +18,13 @@ enum model {
MODEL_AGB,
};
static const GB_model_t cocoa_to_internal_model[] =
{
[MODEL_DMG] = GB_MODEL_DMG_B,
[MODEL_CGB] = GB_MODEL_CGB_E,
[MODEL_AGB] = GB_MODEL_AGB
};
@interface Document ()
{
/* NSTextViews freeze the entire app if they're modified too often and too quickly.
@ -137,21 +144,22 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height,
- (void) initDMG
{
current_model = MODEL_DMG;
GB_init(&gb);
GB_init(&gb, cocoa_to_internal_model[current_model]);
[self initCommon];
GB_load_boot_rom(&gb, [[[NSBundle mainBundle] pathForResource:@"dmg_boot" ofType:@"bin"] UTF8String]);
}
- (void) initCGB
{
GB_init_cgb(&gb);
[self initCommon];
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"EmulateAGB"]) {
current_model = MODEL_AGB;
GB_init(&gb, cocoa_to_internal_model[current_model]);
GB_load_boot_rom(&gb, [[[NSBundle mainBundle] pathForResource:@"agb_boot" ofType:@"bin"] UTF8String]);
}
else {
current_model = MODEL_CGB;
GB_init(&gb, cocoa_to_internal_model[current_model]);
GB_load_boot_rom(&gb, [[[NSBundle mainBundle] pathForResource:@"cgb_boot" ofType:@"bin"] UTF8String]);
}
}
@ -250,7 +258,7 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height,
}
else {
current_model = (enum model)[sender tag];
GB_switch_model_and_reset(&gb, current_model != MODEL_DMG);
GB_switch_model_and_reset(&gb, cocoa_to_internal_model[current_model]);
static NSString * const boot_names[] = {@"dmg_boot", @"cgb_boot", @"agb_boot"};
GB_load_boot_rom(&gb, [[[NSBundle mainBundle] pathForResource:boot_names[current_model - 1] ofType:@"bin"] UTF8String]);
}

View File

@ -54,7 +54,7 @@
break;
case GBMemoryVRAM:
bank_backup = gb->cgb_vram_bank;
if (gb->is_cgb) {
if (GB_is_cgb(gb)) {
gb->cgb_vram_bank = self.selectedBank;
}
addr += 0x8000;
@ -66,7 +66,7 @@
break;
case GBMemoryRAM:
bank_backup = gb->cgb_ram_bank;
if (gb->is_cgb) {
if (GB_is_cgb(gb)) {
gb->cgb_ram_bank = self.selectedBank;
}
addr += 0xC000;
@ -127,7 +127,7 @@
break;
case GBMemoryVRAM:
bank_backup = gb->cgb_vram_bank;
if (gb->is_cgb) {
if (GB_is_cgb(gb)) {
gb->cgb_vram_bank = self.selectedBank;
}
addr += 0x8000;
@ -139,7 +139,7 @@
break;
case GBMemoryRAM:
bank_backup = gb->cgb_ram_bank;
if (gb->is_cgb) {
if (GB_is_cgb(gb)) {
gb->cgb_ram_bank = self.selectedBank;
}
addr += 0xC000;

View File

@ -468,7 +468,7 @@ uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg)
};
if (reg >= GB_IO_WAV_START && reg <= GB_IO_WAV_END && gb->apu.is_active[GB_WAVE]) {
if (!gb->is_cgb && !gb->apu.wave_channel.wave_form_just_read) {
if (!GB_is_cgb(gb) && !gb->apu.wave_channel.wave_form_just_read) {
return 0xFF;
}
reg = GB_IO_WAV_START + gb->apu.wave_channel.current_sample_index / 2;
@ -479,7 +479,7 @@ uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg)
void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
{
if (!gb->apu.global_enable && reg != GB_IO_NR52 && (gb->is_cgb ||
if (!gb->apu.global_enable && reg != GB_IO_NR52 && (GB_is_cgb(gb) ||
(
reg != GB_IO_NR11 &&
reg != GB_IO_NR21 &&
@ -491,7 +491,7 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
}
if (reg >= GB_IO_WAV_START && reg <= GB_IO_WAV_END && gb->apu.is_active[GB_WAVE]) {
if (!gb->is_cgb && !gb->apu.wave_channel.wave_form_just_read) {
if (!GB_is_cgb(gb) && !gb->apu.wave_channel.wave_form_just_read) {
return;
}
reg = GB_IO_WAV_START + gb->apu.wave_channel.current_sample_index / 2;
@ -533,7 +533,7 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
gb->apu.global_enable = false;
}
if (!gb->is_cgb && (value & 0x80)) {
if (!GB_is_cgb(gb) && (value & 0x80)) {
GB_apu_write(gb, GB_IO_NR11, old_nrx1[0]);
GB_apu_write(gb, GB_IO_NR21, old_nrx1[1]);
GB_apu_write(gb, GB_IO_NR31, old_nrx1[2]);
@ -694,7 +694,7 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
if ((value & 0x80)) {
/* DMG bug: wave RAM gets corrupted if the channel is retriggerred 1 cycle before the APU
reads from it. */
if (!gb->is_cgb &&
if (!GB_is_cgb(gb) &&
gb->apu.is_active[GB_WAVE] &&
gb->apu.wave_channel.sample_countdown == 0 &&
gb->apu.wave_channel.enable) {

View File

@ -112,7 +112,7 @@ static inline void switch_banking_state(GB_gameboy_t *gb, uint16_t bank)
gb->mbc_rom_bank = bank;
gb->mbc_ram_bank = bank;
gb->mbc_ram_enable = true;
if (gb->is_cgb) {
if (GB_is_cgb(gb)) {
gb->cgb_ram_bank = bank & 7;
gb->cgb_vram_bank = bank & 1;
if (gb->cgb_ram_bank == 0) {
@ -1462,7 +1462,7 @@ static bool palettes(GB_gameboy_t *gb, char *arguments, char *modifiers, const d
return true;
}
if (!gb->is_cgb) {
if (!GB_is_cgb(gb)) {
GB_log(gb, "Not available on a DMG.\n");
return true;
}
@ -1495,7 +1495,7 @@ static bool lcd(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugg
}
GB_log(gb, "LCDC:\n");
GB_log(gb, " LCD enabled: %s\n",(gb->io_registers[GB_IO_LCDC] & 128)? "Enabled" : "Disabled");
GB_log(gb, " %s: %s\n", gb->is_cgb? (gb->cgb_mode? "Sprite priority flags" : "Background and Window") : "Background",
GB_log(gb, " %s: %s\n", GB_is_cgb(gb)? (gb->cgb_mode? "Sprite priority flags" : "Background and Window") : "Background",
(gb->io_registers[GB_IO_LCDC] & 1)? "Enabled" : "Disabled");
GB_log(gb, " Objects: %s\n", (gb->io_registers[GB_IO_LCDC] & 2)? "Enabled" : "Disabled");
GB_log(gb, " Object size: %s\n", (gb->io_registers[GB_IO_LCDC] & 4)? "8x16" : "8x8");

View File

@ -113,7 +113,7 @@ typedef struct __attribute__((packed)) {
static bool window_enabled(GB_gameboy_t *gb)
{
if ((gb->io_registers[GB_IO_LCDC] & 0x1) == 0) {
if (!gb->cgb_mode && gb->is_cgb) {
if (!gb->cgb_mode && GB_is_cgb(gb)) {
return false;
}
}
@ -203,7 +203,7 @@ uint32_t GB_convert_rgb15(GB_gameboy_t *gb, uint16_t color)
void GB_palette_changed(GB_gameboy_t *gb, bool background_palette, uint8_t index)
{
if (!gb->rgb_encode_callback || !gb->is_cgb) return;
if (!gb->rgb_encode_callback || !GB_is_cgb(gb)) return;
uint8_t *palette_data = background_palette? gb->background_palettes_data : gb->sprite_palettes_data;
uint16_t color = palette_data[index & ~1] | (palette_data[index | 1] << 8);
@ -213,7 +213,7 @@ void GB_palette_changed(GB_gameboy_t *gb, bool background_palette, uint8_t index
void GB_set_color_correction_mode(GB_gameboy_t *gb, GB_color_correction_mode_t mode)
{
gb->color_correction_mode = mode;
if (gb->is_cgb) {
if (GB_is_cgb(gb)) {
for (unsigned i = 0; i < 32; i++) {
GB_palette_changed(gb, false, i * 2);
GB_palette_changed(gb, true, i * 2);
@ -236,7 +236,7 @@ void GB_STAT_update(GB_gameboy_t *gb)
bool previous_interrupt_line = gb->stat_interrupt_line;
/* Set LY=LYC bit */
if (gb->ly_for_comparison != (uint16_t)-1 || !gb->is_cgb) {
if (gb->ly_for_comparison != (uint16_t)-1 || !GB_is_cgb(gb)) {
if (gb->ly_for_comparison == gb->io_registers[GB_IO_LYC]) {
gb->lyc_interrupt_line = true;
gb->io_registers[GB_IO_STAT] |= 4;
@ -362,7 +362,7 @@ static void render_pixel_if_possible(GB_gameboy_t *gb)
bg_enabled = false;
}
}
if (!gb->is_cgb && gb->in_window) {
if (!GB_is_cgb(gb) && gb->in_window) {
bg_enabled = true;
}
@ -434,7 +434,7 @@ static void advance_fetcher_state_machine(GB_gameboy_t *gb)
/* Todo: Verified for DMG (Tested: SGB2), CGB timing is wrong. */
uint8_t y = fetcher_y(gb);
if (gb->is_cgb) {
if (GB_is_cgb(gb)) {
/* This value is cached on the CGB, so it cannot be used to mix tiles together */
/* Todo: This is NOT true on CGB-B! This is likely the case for all CGBs prior to D.
Currently, SameBoy is emulating CGB-E, but if other revisions are added in the future
@ -442,7 +442,7 @@ static void advance_fetcher_state_machine(GB_gameboy_t *gb)
gb->fetcher_y = y;
}
gb->current_tile = gb->vram[map + gb->fetcher_x + y / 8 * 32];
if (gb->is_cgb) {
if (GB_is_cgb(gb)) {
/* The CGB actually accesses both the tile index AND the attributes in the same T-cycle.
This probably means the CGB has a 16-bit data bus for the VRAM. */
gb->current_tile_attributes = gb->vram[map + gb->fetcher_x + y / 8 * 32 + 0x2000];
@ -456,7 +456,7 @@ static void advance_fetcher_state_machine(GB_gameboy_t *gb)
case GB_FETCHER_GET_TILE_DATA_LOWER: {
uint8_t y_flip = 0;
uint16_t tile_address = 0;
uint8_t y = gb->is_cgb? gb->fetcher_y : fetcher_y(gb);
uint8_t y = GB_is_cgb(gb)? gb->fetcher_y : fetcher_y(gb);
/* Todo: Verified for DMG (Tested: SGB2), CGB timing is wrong. */
if (gb->io_registers[GB_IO_LCDC] & 0x10) {
@ -483,7 +483,7 @@ static void advance_fetcher_state_machine(GB_gameboy_t *gb)
bit mid-fetching causes a glitched mixing of the two, in comparison to the
more logical DMG version. */
uint16_t tile_address = 0;
uint8_t y = gb->is_cgb? gb->fetcher_y : fetcher_y(gb);
uint8_t y = GB_is_cgb(gb)? gb->fetcher_y : fetcher_y(gb);
if (gb->io_registers[GB_IO_LCDC] & 0x10) {
tile_address = gb->current_tile * 0x10;
@ -571,7 +571,7 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
return;
}
if (!gb->is_cgb) {
if (!GB_is_cgb(gb)) {
GB_SLEEP(gb, display, 23, 1);
}
@ -593,9 +593,9 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
gb->io_registers[GB_IO_STAT] |= 3;
gb->mode_for_interrupt = 3;
gb->oam_read_blocked = true;
gb->vram_read_blocked = !gb->is_cgb;
gb->vram_read_blocked = !GB_is_cgb(gb);
gb->oam_write_blocked = true;
gb->vram_write_blocked = !gb->is_cgb;
gb->vram_write_blocked = !GB_is_cgb(gb);
GB_STAT_update(gb);
gb->cycles_for_line += 2;
@ -634,7 +634,7 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
while (true) {
/* Lines 0 - 143 */
for (; gb->current_line < LINES; gb->current_line++) {
gb->oam_write_blocked = gb->is_cgb;
gb->oam_write_blocked = GB_is_cgb(gb);
gb->accessed_oam_row = 0;
GB_SLEEP(gb, display, 6, 3);
gb->io_registers[GB_IO_LY] = gb->current_line;
@ -647,7 +647,7 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
gb->mode_for_interrupt = 2;
gb->io_registers[GB_IO_STAT] &= ~3;
}
else if (!gb->is_cgb) {
else if (!GB_is_cgb(gb)) {
gb->io_registers[GB_IO_STAT] &= ~3;
}
GB_STAT_update(gb);
@ -665,19 +665,19 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
gb->n_visible_objs = 0;
for (gb->oam_search_index = 0; gb->oam_search_index < 40; gb->oam_search_index++) {
if (gb->is_cgb) {
if (GB_is_cgb(gb)) {
add_object_from_index(gb, gb->oam_search_index);
/* The CGB does not care about the accessed OAM row as there's no OAM bug*/
}
GB_SLEEP(gb, display, 8, 2);
if (!gb->is_cgb) {
if (!GB_is_cgb(gb)) {
add_object_from_index(gb, gb->oam_search_index);
gb->accessed_oam_row = (gb->oam_search_index & ~1) * 4 + 8;
}
if (gb->oam_search_index == 37) {
gb->vram_read_blocked = !gb->is_cgb;
gb->vram_read_blocked = !GB_is_cgb(gb);
gb->vram_write_blocked = false;
gb->oam_write_blocked = gb->is_cgb;
gb->oam_write_blocked = GB_is_cgb(gb);
GB_STAT_update(gb);
}
}
@ -719,7 +719,7 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
gb->n_visible_objs--;
}
while (gb->n_visible_objs != 0 &&
(gb->io_registers[GB_IO_LCDC] & 2 || gb->is_cgb) &&
(gb->io_registers[GB_IO_LCDC] & 2 || GB_is_cgb(gb)) &&
gb->obj_comperators[gb->n_visible_objs - 1] == (uint8_t)(gb->position_in_line + 8)) {
while (gb->fetcher_state < 5) {
@ -864,17 +864,17 @@ void GB_display_run(GB_gameboy_t *gb, uint8_t cycles)
gb->io_registers[GB_IO_LY] = 153;
gb->ly_for_comparison = -1;
GB_STAT_update(gb);
GB_SLEEP(gb, display, 14, gb->is_cgb? 4: 6);
GB_SLEEP(gb, display, 14, GB_is_cgb(gb)? 4: 6);
if (!gb->is_cgb) {
if (!GB_is_cgb(gb)) {
gb->io_registers[GB_IO_LY] = 0;
}
gb->ly_for_comparison = 153;
GB_STAT_update(gb);
GB_SLEEP(gb, display, 15, gb->is_cgb? 4: 2);
GB_SLEEP(gb, display, 15, GB_is_cgb(gb)? 4: 2);
gb->io_registers[GB_IO_LY] = 0;
gb->ly_for_comparison = gb->is_cgb? 153 : -1;
gb->ly_for_comparison = GB_is_cgb(gb)? 153 : -1;
GB_STAT_update(gb);
GB_SLEEP(gb, display, 16, 4);
@ -896,7 +896,7 @@ void GB_draw_tileset(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette
uint32_t none_palette[4];
uint32_t *palette = NULL;
switch (gb->is_cgb? palette_type : GB_PALETTE_NONE) {
switch (GB_is_cgb(gb)? palette_type : GB_PALETTE_NONE) {
default:
case GB_PALETTE_NONE:
none_palette[0] = gb->rgb_encode_callback(gb, 0xFF, 0xFF, 0xFF);
@ -915,7 +915,7 @@ void GB_draw_tileset(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette
for (unsigned y = 0; y < 192; y++) {
for (unsigned x = 0; x < 256; x++) {
if (x >= 128 && !gb->is_cgb) {
if (x >= 128 && !GB_is_cgb(gb)) {
*(dest++) = gb->background_palettes_rgb[0];
continue;
}
@ -947,7 +947,7 @@ void GB_draw_tilemap(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette
uint32_t *palette = NULL;
uint16_t map = 0x1800;
switch (gb->is_cgb? palette_type : GB_PALETTE_NONE) {
switch (GB_is_cgb(gb)? palette_type : GB_PALETTE_NONE) {
case GB_PALETTE_NONE:
none_palette[0] = gb->rgb_encode_callback(gb, 0xFF, 0xFF, 0xFF);
none_palette[1] = gb->rgb_encode_callback(gb, 0xAA, 0xAA, 0xAA);
@ -1048,7 +1048,7 @@ uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest, uint8_t *sprite_h
uint16_t vram_address = dest[i].tile * 0x10;
uint8_t flags = dest[i].flags;
uint8_t palette = gb->cgb_mode? (flags & 7) : ((flags & 0x10)? 1 : 0);
if (gb->is_cgb && (flags & 0x8)) {
if (GB_is_cgb(gb) && (flags & 0x8)) {
vram_address += 0x2000;
}

View File

@ -90,11 +90,18 @@ static char *default_async_input_callback(GB_gameboy_t *gb)
}
#endif
void GB_init(GB_gameboy_t *gb)
void GB_init(GB_gameboy_t *gb, GB_model_t model)
{
memset(gb, 0, sizeof(*gb));
gb->ram = malloc(gb->ram_size = 0x2000);
gb->vram = malloc(gb->vram_size = 0x2000);
gb->model = model;
if (GB_is_cgb(gb)) {
gb->ram = malloc(gb->ram_size = 0x2000 * 8);
gb->vram = malloc(gb->vram_size = 0x2000 * 2);
}
else {
gb->ram = malloc(gb->ram_size = 0x2000);
gb->vram = malloc(gb->vram_size = 0x2000);
}
#ifndef DISABLE_DEBUGGER
gb->input_callback = default_input_callback;
@ -106,21 +113,9 @@ void GB_init(GB_gameboy_t *gb)
GB_reset(gb);
}
void GB_init_cgb(GB_gameboy_t *gb)
GB_model_t GB_get_model(GB_gameboy_t *gb)
{
memset(gb, 0, sizeof(*gb));
gb->ram = malloc(gb->ram_size = 0x2000 * 8);
gb->vram = malloc(gb->vram_size = 0x2000 * 2);
gb->is_cgb = true;
#ifndef DISABLE_DEBUGGER
gb->input_callback = default_input_callback;
gb->async_input_callback = default_async_input_callback;
#endif
gb->cartridge_type = &GB_cart_defs[0]; // Default cartridge type
gb->clock_multiplier = 1.0;
GB_reset(gb);
return gb->model;
}
void GB_free(GB_gameboy_t *gb)
@ -339,7 +334,7 @@ void GB_set_async_input_callback(GB_gameboy_t *gb, GB_input_callback_t callback)
void GB_set_rgb_encode_callback(GB_gameboy_t *gb, GB_rgb_encode_callback_t callback)
{
if (!gb->rgb_encode_callback && !gb->is_cgb) {
if (!gb->rgb_encode_callback && !GB_is_cgb(gb)) {
gb->sprite_palettes_rgb[4] = gb->sprite_palettes_rgb[0] = gb->background_palettes_rgb[0] =
callback(gb, 0xFF, 0xFF, 0xFF);
gb->sprite_palettes_rgb[5] = gb->sprite_palettes_rgb[1] = gb->background_palettes_rgb[1] =
@ -424,7 +419,7 @@ bool GB_is_inited(GB_gameboy_t *gb)
bool GB_is_cgb(GB_gameboy_t *gb)
{
return gb->is_cgb;
return ((gb->model) & GB_MODEL_FAMILY_MASK) == GB_MODEL_CGB_FAMILY;
}
void GB_set_turbo_mode(GB_gameboy_t *gb, bool on, bool no_frame_skip)
@ -451,7 +446,7 @@ void GB_set_user_data(GB_gameboy_t *gb, void *data)
void GB_reset(GB_gameboy_t *gb)
{
uint32_t mbc_ram_size = gb->mbc_ram_size;
bool cgb = gb->is_cgb;
bool cgb = GB_is_cgb(gb);
memset(gb, 0, (size_t)GB_GET_SECTION((GB_gameboy_t *) 0, unsaved));
gb->version = GB_STRUCT_VERSION;
@ -466,7 +461,7 @@ void GB_reset(GB_gameboy_t *gb)
gb->vram_size = 0x2000 * 2;
memset(gb->vram, 0, gb->vram_size);
gb->is_cgb = true;
gb->model = GB_MODEL_CGB_E;
gb->cgb_mode = true;
}
else {
@ -491,16 +486,17 @@ void GB_reset(GB_gameboy_t *gb)
gb->io_registers[GB_IO_SC] = 0x7E;
/* These are not deterministic, but 00 (CGB) and FF (DMG) are the most common initial values by far */
gb->io_registers[GB_IO_DMA] = gb->io_registers[GB_IO_OBP0] = gb->io_registers[GB_IO_OBP1] = gb->is_cgb? 0x00 : 0xFF;
gb->io_registers[GB_IO_DMA] = gb->io_registers[GB_IO_OBP0] = gb->io_registers[GB_IO_OBP1] = GB_is_cgb(gb)? 0x00 : 0xFF;
gb->accessed_oam_row = -1;
gb->magic = (uintptr_t)'SAME';
}
void GB_switch_model_and_reset(GB_gameboy_t *gb, bool is_cgb)
void GB_switch_model_and_reset(GB_gameboy_t *gb, GB_model_t model)
{
if (is_cgb) {
gb->model = model;
if (GB_is_cgb(gb)) {
gb->ram = realloc(gb->ram, gb->ram_size = 0x2000 * 8);
gb->vram = realloc(gb->vram, gb->vram_size = 0x2000 * 2);
}
@ -508,7 +504,6 @@ void GB_switch_model_and_reset(GB_gameboy_t *gb, bool is_cgb)
gb->ram = realloc(gb->ram, gb->ram_size = 0x2000);
gb->vram = realloc(gb->vram, gb->vram_size = 0x2000);
}
gb->is_cgb = is_cgb;
GB_rewind_free(gb);
GB_reset(gb);
}
@ -553,7 +548,7 @@ void *GB_get_direct_access(GB_gameboy_t *gb, GB_direct_access_t access, size_t *
*bank = 0;
return &gb->io_registers;
case GB_DIRECT_ACCESS_BOOTROM:
*size = gb->is_cgb? sizeof(gb->boot_rom) : 0x100;
*size = GB_is_cgb(gb)? sizeof(gb->boot_rom) : 0x100;
*bank = 0;
return &gb->boot_rom;
case GB_DIRECT_ACCESS_OAM:

View File

@ -20,7 +20,34 @@
#include "z80_cpu.h"
#include "symbol_hash.h"
#define GB_STRUCT_VERSION 12
#define GB_STRUCT_VERSION 13
typedef enum {
#ifdef GB_INTERNAL
GB_MODEL_FAMILY_MASK = 0xF00,
GB_MODEL_DMG_FAMILY = 0x000,
#endif
// GB_MODEL_DMG_0 = 0x000,
// GB_MODEL_DMG_A = 0x001,
GB_MODEL_DMG_B = 0x002,
// GB_MODEL_DMG_C = 0x003,
// GB_MODEL_SGB = 0x004,
#ifdef GB_INTERNAL
GB_MODEL_MGB_FAMILY = 0x100,
#endif
// GB_MODEL_MGB = 0x100,
// GB_MODEL_SGB2 = 0x101,
#ifdef GB_INTERNAL
GB_MODEL_CGB_FAMILY = 0x200,
#endif
// GB_MODEL_CGB_0 = 0x200,
// GB_MODEL_CGB_A = 0x201,
// GB_MODEL_CGB_B = 0x202,
// GB_MODEL_CGB_C = 0x203,
// GB_MODEL_CGB_D = 0x204,
GB_MODEL_CGB_E = 0x205,
GB_MODEL_AGB = 0x206,
} GB_model_t;
enum {
GB_REGISTER_AF,
@ -261,8 +288,8 @@ struct GB_gameboy_internal_s {
uint8_t cgb_ram_bank;
/* CPU and General Hardware Flags*/
GB_model_t model;
bool cgb_mode;
bool is_cgb;
bool cgb_double_speed;
bool halted;
bool stopped;
@ -547,13 +574,13 @@ struct GB_gameboy_s {
__attribute__((__format__ (__printf__, fmtarg, firstvararg)))
#endif
void GB_init(GB_gameboy_t *gb);
void GB_init_cgb(GB_gameboy_t *gb);
void GB_init(GB_gameboy_t *gb, GB_model_t model);
bool GB_is_inited(GB_gameboy_t *gb);
bool GB_is_cgb(GB_gameboy_t *gb);
GB_model_t GB_get_model(GB_gameboy_t *gb);
void GB_free(GB_gameboy_t *gb);
void GB_reset(GB_gameboy_t *gb);
void GB_switch_model_and_reset(GB_gameboy_t *gb, bool is_cgb);
void GB_switch_model_and_reset(GB_gameboy_t *gb, GB_model_t model);
/* Returns the time passed, in 4MHz ticks. */
uint8_t GB_run(GB_gameboy_t *gb);

View File

@ -24,7 +24,7 @@ static GB_bus_t bus_for_addr(GB_gameboy_t *gb, uint16_t addr)
return GB_BUS_MAIN;
}
if (addr < 0xFE00) {
return gb->is_cgb? GB_BUS_RAM : GB_BUS_MAIN;
return GB_is_cgb(gb)? GB_BUS_RAM : GB_BUS_MAIN;
}
return GB_BUS_INTERNAL;
}
@ -46,7 +46,7 @@ static uint8_t bitwise_glitch_read_increase(uint8_t a, uint8_t b, uint8_t c, uin
void GB_trigger_oam_bug(GB_gameboy_t *gb, uint16_t address)
{
if (gb->is_cgb) return;
if (GB_is_cgb(gb)) return;
if (address >= 0xFE00 && address < 0xFF00) {
if (gb->accessed_oam_row != 0xff && gb->accessed_oam_row >= 8) {
@ -65,7 +65,7 @@ void GB_trigger_oam_bug(GB_gameboy_t *gb, uint16_t address)
void GB_trigger_oam_bug_read(GB_gameboy_t *gb, uint16_t address)
{
if (gb->is_cgb) return;
if (GB_is_cgb(gb)) return;
if (address >= 0xFE00 && address < 0xFF00) {
if (gb->accessed_oam_row != 0xff && gb->accessed_oam_row >= 8) {
@ -86,7 +86,7 @@ void GB_trigger_oam_bug_read(GB_gameboy_t *gb, uint16_t address)
void GB_trigger_oam_bug_read_increase(GB_gameboy_t *gb, uint16_t address)
{
if (gb->is_cgb) return;
if (GB_is_cgb(gb)) return;
if (address >= 0xFE00 && address < 0xFF00) {
if (gb->accessed_oam_row != 0xff && gb->accessed_oam_row >= 0x20 && gb->accessed_oam_row < 0x98) {
@ -119,7 +119,7 @@ static uint8_t read_rom(GB_gameboy_t *gb, uint16_t addr)
return gb->boot_rom[addr];
}
if (addr >= 0x200 && addr < 0x900 && gb->is_cgb && !gb->boot_rom_finished) {
if (addr >= 0x200 && addr < 0x900 && GB_is_cgb(gb) && !gb->boot_rom_finished) {
return gb->boot_rom[addr];
}
@ -208,7 +208,7 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
}
if (gb->oam_read_blocked) {
if (!gb->is_cgb) {
if (!GB_is_cgb(gb)) {
if (addr < 0xFEA0) {
if (gb->accessed_oam_row == 0) {
gb->oam[(addr & 0xf8)] =
@ -249,7 +249,7 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
if ((gb->io_registers[GB_IO_STAT] & 0x3) >= 2) { /* Seems to be disabled in Modes 2 and 3 */
return 0xFF;
}
if (gb->is_cgb) {
if (GB_is_cgb(gb)) {
return (addr & 0xF0) | ((addr >> 4) & 0xF);
}
}
@ -275,11 +275,11 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
return gb->io_registers[GB_IO_DMG_EMULATION_INDICATION] | 0xFE;
case GB_IO_PCM_12:
if (!gb->is_cgb) return 0xFF;
if (!GB_is_cgb(gb)) return 0xFF;
return (gb->apu.is_active[GB_SQUARE_2] ? (gb->apu.samples[GB_SQUARE_2] << 4) : 0) |
(gb->apu.is_active[GB_SQUARE_1] ? (gb->apu.samples[GB_SQUARE_1]) : 0);
case GB_IO_PCM_34:
if (!gb->is_cgb) return 0xFF;
if (!GB_is_cgb(gb)) return 0xFF;
return (gb->apu.is_active[GB_NOISE] ? (gb->apu.samples[GB_NOISE] << 4) : 0) |
(gb->apu.is_active[GB_WAVE] ? (gb->apu.samples[GB_WAVE]) : 0);
case GB_IO_JOYP:
@ -314,7 +314,7 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
}
return gb->cgb_ram_bank | ~0x7;
case GB_IO_VBK:
if (!gb->is_cgb) {
if (!GB_is_cgb(gb)) {
return 0xFF;
}
return gb->cgb_vram_bank | ~0x1;
@ -322,7 +322,7 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
/* Todo: It seems that a CGB in DMG mode can access BGPI and OBPI, but not BGPD and OBPD? */
case GB_IO_BGPI:
case GB_IO_OBPI:
if (!gb->is_cgb) {
if (!GB_is_cgb(gb)) {
return 0xFF;
}
return gb->io_registers[addr & 0xFF] | 0x40;
@ -357,11 +357,11 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
}
case GB_IO_UNKNOWN2:
case GB_IO_UNKNOWN3:
return gb->is_cgb? gb->io_registers[addr & 0xFF] : 0xFF;
return GB_is_cgb(gb)? gb->io_registers[addr & 0xFF] : 0xFF;
case GB_IO_UNKNOWN4:
return gb->cgb_mode? gb->io_registers[addr & 0xFF] : 0xFF;
case GB_IO_UNKNOWN5:
return gb->is_cgb? gb->io_registers[addr & 0xFF] | 0x8F : 0xFF;
return GB_is_cgb(gb)? gb->io_registers[addr & 0xFF] | 0x8F : 0xFF;
default:
if ((addr & 0xFF) >= GB_IO_NR10 && (addr & 0xFF) <= GB_IO_WAV_END) {
return GB_apu_read(gb, addr & 0xFF);
@ -531,7 +531,7 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
return;
}
if (gb->is_cgb) {
if (GB_is_cgb(gb)) {
if (addr < 0xFEA0) {
gb->oam[addr & 0xFF] = value;
}
@ -599,7 +599,7 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
/* TODO: Probably completely wrong in double speed mode */
/* TODO: This hack is disgusting */
if (gb->display_state == 29 && gb->is_cgb) {
if (gb->display_state == 29 && GB_is_cgb(gb)) {
gb->ly_for_comparison = 153;
GB_STAT_update(gb);
gb->ly_for_comparison = 0;
@ -609,14 +609,14 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
/* These are the states when LY changes, let the display routine call GB_STAT_update for use
so it correctly handles T-cycle accurate LYC writes */
if (!gb->is_cgb || (
if (!GB_is_cgb(gb) || (
gb->display_state != 6 &&
gb->display_state != 26 &&
gb->display_state != 15 &&
gb->display_state != 16)) {
/* More hacks to make LYC write conflicts work */
if (gb->display_state == 14 && gb->is_cgb) {
if (gb->display_state == 14 && GB_is_cgb(gb)) {
gb->ly_for_comparison = 153;
GB_STAT_update(gb);
gb->ly_for_comparison = -1;
@ -691,7 +691,7 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
return;
case GB_IO_DMG_EMULATION:
if (gb->is_cgb && !gb->boot_rom_finished) {
if (GB_is_cgb(gb) && !gb->boot_rom_finished) {
gb->cgb_mode = value != 4; /* The real "contents" of this register aren't quite known yet. */
}
return;
@ -728,7 +728,7 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
case GB_IO_BGPI:
case GB_IO_OBPI:
if (!gb->is_cgb) {
if (!GB_is_cgb(gb)) {
return;
}
gb->io_registers[addr & 0xFF] = value;
@ -823,7 +823,7 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
return;
case GB_IO_RP: {
if (!gb->is_cgb) {
if (!GB_is_cgb(gb)) {
return;
}
if ((value & 1) != (gb->io_registers[GB_IO_RP] & 1)) {

View File

@ -77,7 +77,7 @@ static void cycle_write(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
assert(gb->pending_cycles);
GB_conflict_t conflict = GB_CONFLICT_READ_OLD;
if ((addr & 0xFF80) == 0xFF00) {
conflict = (gb->is_cgb? cgb_conflict_map : dmg_conflict_map)[addr & 0x7F];
conflict = (GB_is_cgb(gb)? cgb_conflict_map : dmg_conflict_map)[addr & 0x7F];
}
switch (conflict) {
case GB_CONFLICT_READ_OLD:
@ -158,7 +158,7 @@ static void cycle_no_access(GB_gameboy_t *gb)
static void cycle_oam_bug(GB_gameboy_t *gb, uint8_t register_id)
{
if (gb->is_cgb) {
if (GB_is_cgb(gb)) {
/* Slight optimization */
gb->pending_cycles += 4;
return;
@ -1381,14 +1381,14 @@ void GB_cpu_run(GB_gameboy_t *gb)
return;
}
if (gb->halted && !gb->is_cgb && !gb->just_halted) {
if (gb->halted && !GB_is_cgb(gb) && !gb->just_halted) {
GB_advance_cycles(gb, 2);
}
uint8_t interrupt_queue = gb->interrupt_enable & gb->io_registers[GB_IO_IF] & 0x1F;
if (gb->halted) {
GB_advance_cycles(gb, (gb->is_cgb || gb->just_halted) ? 4 : 2);
GB_advance_cycles(gb, (GB_is_cgb(gb) || gb->just_halted) ? 4 : 2);
}
gb->just_halted = false;

View File

@ -47,7 +47,7 @@ static uint32_t rgb_encode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b)
int get_image_for_rom(const char *filename, const char *boot_path, uint32_t *output, uint8_t *cgb_flag)
{
GB_gameboy_t gb;
GB_init_cgb(&gb);
GB_init(&gb, GB_MODEL_CGB_E);
if (GB_load_boot_rom(&gb, boot_path)) {
GB_free(&gb);
return 1;

View File

@ -26,13 +26,19 @@ static bool paused = false;
static uint32_t pixel_buffer_1[160*144], pixel_buffer_2[160*144];
static uint32_t *active_pixel_buffer = pixel_buffer_1, *previous_pixel_buffer = pixel_buffer_2;
static char *filename = NULL;
static bool should_free_filename = false;
static char *battery_save_path_ptr;
SDL_AudioDeviceID device_id;
static const GB_model_t sdl_to_internal_model[] =
{
[MODEL_DMG] = GB_MODEL_DMG_B,
[MODEL_CGB] = GB_MODEL_CGB_E,
[MODEL_AGB] = GB_MODEL_AGB
};
void set_filename(const char *new_filename, bool new_should_free)
{
if (filename && should_free_filename) {
@ -364,15 +370,10 @@ static void run(void)
pending_command = GB_SDL_NO_COMMAND;
restart:
if (GB_is_inited(&gb)) {
GB_switch_model_and_reset(&gb, configuration.model != MODEL_DMG);
GB_switch_model_and_reset(&gb, sdl_to_internal_model[configuration.model]);
}
else {
if (configuration.model == MODEL_DMG) {
GB_init(&gb);
}
else {
GB_init_cgb(&gb);
}
GB_init(&gb, sdl_to_internal_model[configuration.model]);
GB_set_vblank_callback(&gb, (GB_vblank_callback_t) vblank);
GB_set_pixels_output(&gb, active_pixel_buffer);
@ -454,7 +455,7 @@ int main(int argc, char **argv)
signal(SIGINT, debugger_interrupt);
SDL_Init( SDL_INIT_EVERYTHING );
SDL_Init(SDL_INIT_EVERYTHING);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
@ -527,6 +528,9 @@ int main(int argc, char **argv)
fread(&configuration, 1, sizeof(configuration), prefs_file);
fclose(prefs_file);
}
if (configuration.model >= MODEL_MAX) {
configuration.model = MODEL_CGB;
}
atexit(save_configuration);

View File

@ -295,14 +295,14 @@ int main(int argc, char **argv)
fprintf(stderr, "Testing ROM %s\n", filename);
if (dmg) {
GB_init(&gb);
GB_init(&gb, GB_MODEL_DMG_B);
if (GB_load_boot_rom(&gb, boot_rom_path? boot_rom_path : executable_relative_path("dmg_boot.bin"))) {
perror("Failed to load boot ROM");
exit(1);
}
}
else {
GB_init_cgb(&gb);
GB_init(&gb, GB_MODEL_CGB_E);
if (GB_load_boot_rom(&gb, boot_rom_path? boot_rom_path : executable_relative_path("cgb_boot.bin"))) {
perror("Failed to load boot ROM");
exit(1);

View File

@ -52,6 +52,13 @@ enum model {
MODEL_AUTO
};
static const GB_model_t libretro_to_internal_model[] =
{
[MODEL_DMG] = GB_MODEL_DMG_B,
[MODEL_CGB] = GB_MODEL_CGB_E,
[MODEL_AGB] = GB_MODEL_AGB
};
enum screen_layout {
LAYOUT_TOP_DOWN,
LAYOUT_LEFT_RIGHT
@ -317,15 +324,11 @@ static void init_for_current_model(void)
for (i = 0; i < emulated_devices; i++)
{
if (GB_is_inited(&gameboy[i]))
GB_switch_model_and_reset(&gameboy[i], effective_model[i] != MODEL_DMG);
else
{
if (effective_model[i] == MODEL_DMG)
GB_init(&gameboy[i]);
else
GB_init_cgb(&gameboy[i]);
if (GB_is_inited(&gameboy[i])) {
GB_switch_model_and_reset(&gameboy[i], libretro_to_internal_model[effective_model[i]]);
}
else {
GB_init(&gameboy[i], libretro_to_internal_model[effective_model[i]]);
}
const char *model_name = (const char *[]){"dmg", "cgb", "agb"}[effective_model[i]];
const unsigned char *boot_code = (const unsigned char *[]){dmg_boot, cgb_boot, agb_boot}[effective_model[i]];