From fb55c35f8743bddaf365d6d0c7f3f1383faec0aa Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Wed, 19 Apr 2017 23:26:39 +0300 Subject: [PATCH] New APIs, Document.m no longer requires GB_INTERNAL, fixed a bug where the sprite viewer showed incorrect sprites for some CGB exclusive games. --- Cocoa/Document.m | 89 ++++++++++++++++++++++++++++++------------------ Core/debugger.c | 10 ++++-- Core/display.c | 37 +++++++++++--------- Core/display.h | 2 +- Core/gb.c | 81 ++++++++++++++++++++++++++++++++++++++----- Core/gb.h | 26 +++++++++++--- Core/memory.c | 8 ++--- 7 files changed, 183 insertions(+), 70 deletions(-) diff --git a/Cocoa/Document.m b/Cocoa/Document.m index 924f212..5f04f1c 100644 --- a/Cocoa/Document.m +++ b/Cocoa/Document.m @@ -1,4 +1,3 @@ -#define GB_INTERNAL // Todo: several debugging functions access the GB struct directly #include #include #include "GBAudioClient.h" @@ -47,8 +46,8 @@ @property GBAudioClient *audioClient; - (void) vblank; - (void) log: (const char *) log withAttributes: (GB_log_attributes) attributes; -- (const char *) getDebuggerInput; -- (const char *) getAsyncDebuggerInput; +- (char *) getDebuggerInput; +- (char *) getAsyncDebuggerInput; - (void) cameraRequestUpdate; - (uint8_t) cameraGetPixelAtX:(uint8_t)x andY:(uint8_t)y; - (void) printImage:(uint32_t *)image height:(unsigned) height @@ -71,14 +70,14 @@ static void consoleLog(GB_gameboy_t *gb, const char *string, GB_log_attributes a static char *consoleInput(GB_gameboy_t *gb) { Document *self = (__bridge Document *)GB_get_user_data(gb); - return strdup([self getDebuggerInput]); + return [self getDebuggerInput]; } static char *asyncConsoleInput(GB_gameboy_t *gb) { Document *self = (__bridge Document *)GB_get_user_data(gb); - const char *ret = [self getAsyncDebuggerInput]; - return ret? strdup(ret) : NULL; + char *ret = [self getAsyncDebuggerInput]; + return ret; } static uint32_t rgbEncode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b) @@ -195,8 +194,7 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height, if (!running) return; GB_debugger_set_disabled(&gb, true); if (GB_debugger_is_stopped(&gb)) { - gb.debug_stopped = false; - [self consoleInput:nil]; + [self interruptDebugInputRead]; } stopping = true; running = false; @@ -413,7 +411,7 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height, return !GB_debugger_is_stopped(&gb); } else if ([anItem action] == @selector(reset:) && anItem.tag != 0) { - [(NSMenuItem*)anItem setState:(anItem.tag == 1 && !gb.is_cgb) || (anItem.tag == 2 && gb.is_cgb)]; + [(NSMenuItem*)anItem setState:(anItem.tag == 1 && !GB_is_cgb(&gb)) || (anItem.tag == 2 && GB_is_cgb(&gb))]; } else if ([anItem action] == @selector(toggleBlend:)) { [(NSMenuItem*)anItem setState:self.view.shouldBlendFrameWithPrevious]; @@ -557,7 +555,14 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height, [sender setStringValue:@""]; } -- (const char *) getDebuggerInput +- (void) interruptDebugInputRead +{ + [has_debugger_input lock]; + [debugger_input_queue addObject:[NSNull null]]; + [has_debugger_input unlockWithCondition:1]; +} + +- (char *) getDebuggerInput { [self log:">"]; in_sync_input = true; @@ -566,10 +571,13 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height, [debugger_input_queue removeObjectAtIndex:0]; [has_debugger_input unlockWithCondition:[debugger_input_queue count] != 0]; in_sync_input = false; - return [input UTF8String]; + if ((id) input == [NSNull null]) { + return NULL; + } + return strdup([input UTF8String]); } -- (const char *) getAsyncDebuggerInput +- (char *) getAsyncDebuggerInput { [has_debugger_input lock]; NSString *input = [debugger_input_queue firstObject]; @@ -577,7 +585,7 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height, [debugger_input_queue removeObjectAtIndex:0]; } [has_debugger_input unlockWithCondition:[debugger_input_queue count] != 0]; - return [input UTF8String]; + return input? strdup([input UTF8String]): NULL; } - (IBAction)saveState:(id)sender @@ -731,8 +739,7 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height, case 2: /* OAM */ { - oamCount = GB_get_oam_info(&gb, oamInfo); - oamHeight = (gb.io_registers[GB_IO_LCDC] & 4) ? 16:8; + oamCount = GB_get_oam_info(&gb, oamInfo, &oamHeight); dispatch_async(dispatch_get_main_queue(), ^{ if (!oamUpdating) { oamUpdating = true; @@ -799,17 +806,23 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height, uint16_t n_banks = 1; switch ([(GBMemoryByteArray *)(hex_controller.byteArray) mode]) { - case GBMemoryROM: - n_banks = gb.rom_size / 0x4000; + case GBMemoryROM: { + size_t rom_size; + GB_get_direct_access(&gb, GB_DIRECT_ACCESS_ROM, &rom_size, NULL); + n_banks = rom_size / 0x4000; break; + } case GBMemoryVRAM: - n_banks = gb.is_cgb ? 2 : 1; + n_banks = GB_is_cgb(&gb) ? 2 : 1; break; - case GBMemoryExternalRAM: - n_banks = (gb.mbc_ram_size + 0x1FFF) / 0x2000; + case GBMemoryExternalRAM: { + size_t ram_size; + GB_get_direct_access(&gb, GB_DIRECT_ACCESS_CART_RAM, &ram_size, NULL); + n_banks = (ram_size + 0x1FFF) / 0x2000; break; + } case GBMemoryRAM: - n_banks = gb.is_cgb ? 8 : 1; + n_banks = GB_is_cgb(&gb) ? 8 : 1; break; case GBMemoryEntireSpace: break; @@ -833,23 +846,28 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height, self.memoryBankItem.enabled = [sender indexOfSelectedItem] != GBMemoryEntireSpace; GBMemoryByteArray *byteArray = (GBMemoryByteArray *)(hex_controller.byteArray); [byteArray setMode:(GB_memory_mode_t)[sender indexOfSelectedItem]]; + uint16_t bank; switch ((GB_memory_mode_t)[sender indexOfSelectedItem]) { case GBMemoryEntireSpace: case GBMemoryROM: lineRep.valueOffset = 0; - byteArray.selectedBank = gb.mbc_rom_bank; + GB_get_direct_access(&gb, GB_DIRECT_ACCESS_ROM, NULL, &bank); + byteArray.selectedBank = bank; break; case GBMemoryVRAM: lineRep.valueOffset = 0x8000; - byteArray.selectedBank = gb.cgb_vram_bank; + GB_get_direct_access(&gb, GB_DIRECT_ACCESS_VRAM, NULL, &bank); + byteArray.selectedBank = bank; break; case GBMemoryExternalRAM: lineRep.valueOffset = 0xA000; - byteArray.selectedBank = gb.mbc_ram_bank; + GB_get_direct_access(&gb, GB_DIRECT_ACCESS_CART_RAM, NULL, &bank); + byteArray.selectedBank = bank; break; case GBMemoryRAM: lineRep.valueOffset = 0xC000; - byteArray.selectedBank = gb.cgb_ram_bank; + GB_get_direct_access(&gb, GB_DIRECT_ACCESS_RAM, NULL, &bank); + byteArray.selectedBank = bank; break; } [self.memoryBankInput setStringValue:[NSString stringWithFormat:@"$%x", byteArray.selectedBank]]; @@ -1011,16 +1029,18 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height, uint16_t map_base = 0x1800; GB_map_type_t map_type = (GB_map_type_t) self.tilemapMapButton.indexOfSelectedItem; GB_tileset_type_t tileset_type = (GB_tileset_type_t) self.TilemapSetButton.indexOfSelectedItem; + uint8_t lcdc = ((uint8_t *)GB_get_direct_access(&gb, GB_DIRECT_ACCESS_IO, NULL, NULL))[GB_IO_LCDC]; + uint8_t *vram = GB_get_direct_access(&gb, GB_DIRECT_ACCESS_VRAM, NULL, NULL); - if (map_type == GB_MAP_9C00 || (map_type == GB_MAP_AUTO && gb.io_registers[GB_IO_LCDC] & 0x08)) { + if (map_type == GB_MAP_9C00 || (map_type == GB_MAP_AUTO && lcdc & 0x08)) { map_base = 0x1c00; } if (tileset_type == GB_TILESET_AUTO) { - tileset_type = (gb.io_registers[GB_IO_LCDC] & 0x10)? GB_TILESET_8800 : GB_TILESET_8000; + tileset_type = (lcdc & 0x10)? GB_TILESET_8800 : GB_TILESET_8000; } - uint8_t tile = gb.vram[map_base + map_offset]; + uint8_t tile = vram[map_base + map_offset]; uint16_t tile_address = 0; if (tileset_type == GB_TILESET_8000) { tile_address = 0x8000 + tile * 0x10; @@ -1029,8 +1049,8 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height, tile_address = 0x9000 + (int8_t)tile * 0x10; } - if (gb.is_cgb) { - uint8_t attributes = gb.vram[map_base + map_offset + 0x2000]; + if (GB_is_cgb(&gb)) { + uint8_t attributes = vram[map_base + map_offset + 0x2000]; self.vramStatusLabel.stringValue = [NSString stringWithFormat:@"Tile number $%02x (%d:$%04x) at map address $%04x (Attributes: %c%c%c%d%d)", tile, attributes & 0x8? 1 : 0, @@ -1070,12 +1090,13 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height, NSUInteger columnIndex = [[tableView tableColumns] indexOfObject:tableColumn]; if (tableView == self.paletteTableView) { if (columnIndex == 0) { - return [NSString stringWithFormat:@"%s %d", row >=8? "Object" : "Background", (int)(row & 7)]; + return [NSString stringWithFormat:@"%s %d", row >=8 ? "Object" : "Background", (int)(row & 7)]; } + + uint8_t *palette_data = GB_get_direct_access(&gb, row >= 8? GB_DIRECT_ACCESS_OBP : GB_DIRECT_ACCESS_BGP, NULL, NULL); uint16_t index = columnIndex - 1 + (row & 7) * 4; - return @(((row >= 8? gb.sprite_palletes_data : gb.background_palletes_data)[(index << 1) + 1] << 8) | - (row >= 8? gb.sprite_palletes_data : gb.background_palletes_data)[(index << 1)]); + return @((palette_data[(index << 1) + 1] << 8) | palette_data[(index << 1)]); } else if (tableView == self.spritesTableView) { switch (columnIndex) { @@ -1092,7 +1113,7 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height, case 5: return [NSString stringWithFormat:@"$%04x", oamInfo[row].oam_addr]; case 6: - if (gb.cgb_mode) { + if (GB_is_cgb(&gb)) { return [NSString stringWithFormat:@"%c%c%c%d%d", oamInfo[row].flags & 0x80? 'P' : '-', oamInfo[row].flags & 0x40? 'Y' : '-', diff --git a/Core/debugger.c b/Core/debugger.c index 8d2dca7..8e191b4 100644 --- a/Core/debugger.c +++ b/Core/debugger.c @@ -1368,7 +1368,7 @@ static bool palettes(GB_gameboy_t *gb, char *arguments, char *modifiers, const d GB_log(gb, "Background palettes: \n"); for (unsigned i = 0; i < 32; i++) { - GB_log(gb, "%04x ", ((uint16_t *)&gb->background_palletes_data)[i]); + GB_log(gb, "%04x ", ((uint16_t *)&gb->background_palettes_data)[i]); if (i % 4 == 3) { GB_log(gb, "\n"); } @@ -1376,7 +1376,7 @@ static bool palettes(GB_gameboy_t *gb, char *arguments, char *modifiers, const d GB_log(gb, "Sprites palettes: \n"); for (unsigned i = 0; i < 32; i++) { - GB_log(gb, "%04x ", ((uint16_t *)&gb->sprite_palletes_data)[i]); + GB_log(gb, "%04x ", ((uint16_t *)&gb->sprite_palettes_data)[i]); if (i % 4 == 3) { GB_log(gb, "\n"); } @@ -1704,6 +1704,12 @@ next_command: gb->stack_leak_detection = false; input = gb->input_callback(gb); + if (input == NULL) { + /* Debugging is no currently available, continue running */ + gb->debug_stopped = false; + return; + } + if (GB_debugger_do_command(gb, input)) { goto next_command; } diff --git a/Core/display.c b/Core/display.c index 3e7d6f1..0855cb5 100755 --- a/Core/display.c +++ b/Core/display.c @@ -157,7 +157,7 @@ static uint32_t get_pixel(GB_gameboy_t *gb, uint8_t x, uint8_t y) sprite_pixel = (gb->io_registers[use_obp1? GB_IO_OBP1:GB_IO_OBP0] >> (sprite_pixel << 1)) & 3; sprite_palette = use_obp1; } - return gb->sprite_palletes_rgb[sprite_palette * 4 + sprite_pixel]; + return gb->sprite_palettes_rgb[sprite_palette * 4 + sprite_pixel]; } if (bg_enabled) { @@ -188,14 +188,14 @@ static uint32_t get_pixel(GB_gameboy_t *gb, uint8_t x, uint8_t y) sprite_pixel = (gb->io_registers[use_obp1? GB_IO_OBP1:GB_IO_OBP0] >> (sprite_pixel << 1)) & 3; sprite_palette = use_obp1; } - return gb->sprite_palletes_rgb[sprite_palette * 4 + sprite_pixel]; + return gb->sprite_palettes_rgb[sprite_palette * 4 + sprite_pixel]; } if (!gb->cgb_mode) { background_pixel = ((gb->io_registers[GB_IO_BGP] >> (background_pixel << 1)) & 3); } - return gb->background_palletes_rgb[(attributes & 7) * 4 + background_pixel]; + return gb->background_palettes_rgb[(attributes & 7) * 4 + background_pixel]; } static int64_t get_nanoseconds(void) @@ -269,7 +269,7 @@ static inline uint8_t scale_channel(uint8_t x) void GB_palette_changed(GB_gameboy_t *gb, bool background_palette, uint8_t index) { - uint8_t *palette_data = background_palette? gb->background_palletes_data : gb->sprite_palletes_data; + 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); // No need to &, scale channel does that. @@ -277,7 +277,7 @@ void GB_palette_changed(GB_gameboy_t *gb, bool background_palette, uint8_t index uint8_t g = scale_channel(color >> 5); uint8_t b = scale_channel(color >> 10); assert (gb->rgb_encode_callback); - (background_palette? gb->background_palletes_rgb : gb->sprite_palletes_rgb)[index / 2] = gb->rgb_encode_callback(gb, r, g, b); + (background_palette? gb->background_palettes_rgb : gb->sprite_palettes_rgb)[index / 2] = gb->rgb_encode_callback(gb, r, g, b); } /* @@ -584,17 +584,17 @@ void GB_draw_tileset(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette palette = none_palette; break; case GB_PALETTE_BACKGROUND: - palette = gb->background_palletes_rgb + (4 * (palette_index & 7)); + palette = gb->background_palettes_rgb + (4 * (palette_index & 7)); break; case GB_PALETTE_OAM: - palette = gb->sprite_palletes_rgb + (4 * (palette_index & 7)); + palette = gb->sprite_palettes_rgb + (4 * (palette_index & 7)); break; } for (unsigned y = 0; y < 192; y++) { for (unsigned x = 0; x < 256; x++) { if (x >= 128 && !gb->is_cgb) { - *(dest++) = gb->background_palletes_rgb[0]; + *(dest++) = gb->background_palettes_rgb[0]; continue; } uint16_t tile = (x % 128) / 8 + y / 8 * 16; @@ -634,10 +634,10 @@ void GB_draw_tilemap(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette palette = none_palette; break; case GB_PALETTE_BACKGROUND: - palette = gb->background_palletes_rgb + (4 * (palette_index & 7)); + palette = gb->background_palettes_rgb + (4 * (palette_index & 7)); break; case GB_PALETTE_OAM: - palette = gb->sprite_palletes_rgb + (4 * (palette_index & 7)); + palette = gb->sprite_palettes_rgb + (4 * (palette_index & 7)); break; case GB_PALETTE_AUTO: break; @@ -683,16 +683,16 @@ void GB_draw_tilemap(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette *(dest++) = palette[pixel]; } else { - *(dest++) = gb->background_palletes_rgb[(attributes & 7) * 4 + pixel]; + *(dest++) = gb->background_palettes_rgb[(attributes & 7) * 4 + pixel]; } } } } -uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest) +uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest, uint8_t *sprite_height) { uint8_t count = 0; - unsigned sprite_height = (gb->io_registers[GB_IO_LCDC] & 4) ? 16:8; + *sprite_height = (gb->io_registers[GB_IO_LCDC] & 4) ? 16:8; uint8_t oam_to_dest_index[40] = {0,}; for (unsigned y = 0; y < LINES; y++) { GB_sprite_t *sprite = (GB_sprite_t *) &gb->oam; @@ -701,7 +701,7 @@ uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest) int sprite_y = sprite->y - 16; bool obscured = false; // Is sprite not in this line? - if (sprite_y > y || sprite_y + sprite_height <= y) continue; + if (sprite_y > y || sprite_y + *sprite_height <= y) continue; if (++sprites_in_line == 11) obscured = true; GB_oam_info_t *info = NULL; @@ -710,7 +710,7 @@ uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest) oam_to_dest_index[i] = ++count; info->x = sprite->x; info->y = sprite->y; - info->tile = sprite_height == 16? sprite->tile & 0xFE : sprite->tile; + info->tile = *sprite_height == 16? sprite->tile & 0xFE : sprite->tile; info->flags = sprite->flags; info->obscured_by_line_limit = false; info->oam_addr = 0xFE00 + i * sizeof(*sprite); @@ -727,8 +727,11 @@ uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest) 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)) { + vram_address += 0x2000; + } - for (unsigned y = 0; y < sprite_height; y++) { + for (unsigned y = 0; y < *sprite_height; y++) { for (unsigned x = 0; x < 8; x++) { uint8_t color = (((gb->vram[vram_address ] >> ((~x)&7)) & 1 ) | ((gb->vram[vram_address + 1] >> ((~x)&7)) & 1) << 1 ); @@ -736,7 +739,7 @@ uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest) if (!gb->cgb_mode) { color = (gb->io_registers[palette? GB_IO_OBP1:GB_IO_OBP0] >> (color << 1)) & 3; } - dest[i].image[((flags & 0x20)?7-x:x) + ((flags & 0x40)?sprite_height - 1 -y:y) * 8] = gb->sprite_palletes_rgb[palette * 4 + color]; + dest[i].image[((flags & 0x20)?7-x:x) + ((flags & 0x40)?*sprite_height - 1 -y:y) * 8] = gb->sprite_palettes_rgb[palette * 4 + color]; } vram_address += 2; } diff --git a/Core/display.h b/Core/display.h index 418bd66..3967787 100644 --- a/Core/display.h +++ b/Core/display.h @@ -35,6 +35,6 @@ typedef struct { void GB_draw_tileset(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette_type, uint8_t palette_index); void GB_draw_tilemap(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette_type, uint8_t palette_index, GB_map_type_t map_type, GB_tileset_type_t tileset_type); -uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest); +uint8_t GB_get_oam_info(GB_gameboy_t *gb, GB_oam_info_t *dest, uint8_t *sprite_height); #endif /* display_h */ diff --git a/Core/gb.c b/Core/gb.c index 89265c2..1497573 100755 --- a/Core/gb.c +++ b/Core/gb.c @@ -447,13 +447,13 @@ 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) { - gb->sprite_palletes_rgb[4] = gb->sprite_palletes_rgb[0] = gb->background_palletes_rgb[0] = + gb->sprite_palettes_rgb[4] = gb->sprite_palettes_rgb[0] = gb->background_palettes_rgb[0] = callback(gb, 0xFF, 0xFF, 0xFF); - gb->sprite_palletes_rgb[5] = gb->sprite_palletes_rgb[1] = gb->background_palletes_rgb[1] = + gb->sprite_palettes_rgb[5] = gb->sprite_palettes_rgb[1] = gb->background_palettes_rgb[1] = callback(gb, 0xAA, 0xAA, 0xAA); - gb->sprite_palletes_rgb[6] = gb->sprite_palletes_rgb[2] = gb->background_palletes_rgb[2] = + gb->sprite_palettes_rgb[6] = gb->sprite_palettes_rgb[2] = gb->background_palettes_rgb[2] = callback(gb, 0x55, 0x55, 0x55); - gb->sprite_palletes_rgb[7] = gb->sprite_palletes_rgb[3] = gb->background_palletes_rgb[3] = + gb->sprite_palettes_rgb[7] = gb->sprite_palettes_rgb[3] = gb->background_palettes_rgb[3] = callback(gb, 0, 0, 0); } gb->rgb_encode_callback = callback; @@ -540,6 +540,11 @@ bool GB_is_inited(GB_gameboy_t *gb) return gb->magic == 'SAME'; } +bool GB_is_cgb(GB_gameboy_t *gb) +{ + return gb->is_cgb; +} + void GB_set_turbo_mode(GB_gameboy_t *gb, bool on, bool no_frame_skip) { gb->turbo = on; @@ -592,13 +597,13 @@ void GB_reset(GB_gameboy_t *gb) memset(gb->vram, 0, gb->vram_size); if (gb->rgb_encode_callback) { - gb->sprite_palletes_rgb[4] = gb->sprite_palletes_rgb[0] = gb->background_palletes_rgb[0] = + gb->sprite_palettes_rgb[4] = gb->sprite_palettes_rgb[0] = gb->background_palettes_rgb[0] = gb->rgb_encode_callback(gb, 0xFF, 0xFF, 0xFF); - gb->sprite_palletes_rgb[5] = gb->sprite_palletes_rgb[1] = gb->background_palletes_rgb[1] = + gb->sprite_palettes_rgb[5] = gb->sprite_palettes_rgb[1] = gb->background_palettes_rgb[1] = gb->rgb_encode_callback(gb, 0xAA, 0xAA, 0xAA); - gb->sprite_palletes_rgb[6] = gb->sprite_palletes_rgb[2] = gb->background_palletes_rgb[2] = + gb->sprite_palettes_rgb[6] = gb->sprite_palettes_rgb[2] = gb->background_palettes_rgb[2] = gb->rgb_encode_callback(gb, 0x55, 0x55, 0x55); - gb->sprite_palletes_rgb[7] = gb->sprite_palletes_rgb[3] = gb->background_palletes_rgb[3] = + gb->sprite_palettes_rgb[7] = gb->sprite_palettes_rgb[3] = gb->background_palettes_rgb[3] = gb->rgb_encode_callback(gb, 0, 0, 0); } @@ -621,3 +626,63 @@ void GB_switch_model_and_reset(GB_gameboy_t *gb, bool is_cgb) GB_reset(gb); } + +void *GB_get_direct_access(GB_gameboy_t *gb, GB_direct_access_t access, size_t *size, uint16_t *bank) +{ + /* Set size and bank to dummy pointers if not set */ + if (!size) { + size = alloca(sizeof(size)); + } + + if (!bank) { + bank = alloca(sizeof(bank)); + } + + + switch (access) { + case GB_DIRECT_ACCESS_ROM: + *size = gb->rom_size; + *bank = gb->mbc_rom_bank; + return gb->rom; + case GB_DIRECT_ACCESS_RAM: + *size = gb->ram_size; + *bank = gb->cgb_ram_bank; + return gb->ram; + case GB_DIRECT_ACCESS_CART_RAM: + *size = gb->mbc_ram_size; + *bank = gb->mbc_ram_bank; + return gb->mbc_ram; + case GB_DIRECT_ACCESS_VRAM: + *size = gb->vram_size; + *bank = gb->cgb_vram_bank; + return gb->vram; + case GB_DIRECT_ACCESS_HRAM: + *size = sizeof(gb->hram); + *bank = 0; + return &gb->hram; + case GB_DIRECT_ACCESS_IO: + *size = sizeof(gb->io_registers); + *bank = 0; + return &gb->io_registers; + case GB_DIRECT_ACCESS_BOOTROM: + *size = gb->is_cgb? sizeof(gb->boot_rom) : 0x100; + *bank = 0; + return &gb->boot_rom; + case GB_DIRECT_ACCESS_OAM: + *size = sizeof(gb->oam); + *bank = 0; + return &gb->oam; + case GB_DIRECT_ACCESS_BGP: + *size = sizeof(gb->background_palettes_data); + *bank = 0; + return &gb->background_palettes_data; + case GB_DIRECT_ACCESS_OBP: + *size = sizeof(gb->sprite_palettes_data); + *bank = 0; + return &gb->sprite_palettes_data; + default: + *size = 0; + *bank = 0; + return NULL; + } +} diff --git a/Core/gb.h b/Core/gb.h index c9b772b..c185a48 100644 --- a/Core/gb.h +++ b/Core/gb.h @@ -361,10 +361,10 @@ struct GB_gameboy_internal_s { uint32_t vram_size; // Different between CGB and DMG uint8_t cgb_vram_bank; uint8_t oam[0xA0]; - uint8_t background_palletes_data[0x40]; - uint8_t sprite_palletes_data[0x40]; - uint32_t background_palletes_rgb[0x20]; - uint32_t sprite_palletes_rgb[0x20]; + uint8_t background_palettes_data[0x40]; + uint8_t sprite_palettes_data[0x40]; + uint32_t background_palettes_rgb[0x20]; + uint32_t sprite_palettes_rgb[0x20]; int16_t previous_lcdc_x; uint8_t padding; bool effective_window_enabled; @@ -481,11 +481,29 @@ __attribute__((__format__ (__printf__, fmtarg, firstvararg))) void GB_init(GB_gameboy_t *gb); void GB_init_cgb(GB_gameboy_t *gb); bool GB_is_inited(GB_gameboy_t *gb); +bool GB_is_cgb(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_run(GB_gameboy_t *gb); +typedef enum { + GB_DIRECT_ACCESS_ROM, + GB_DIRECT_ACCESS_RAM, + GB_DIRECT_ACCESS_CART_RAM, + GB_DIRECT_ACCESS_VRAM, + GB_DIRECT_ACCESS_HRAM, + GB_DIRECT_ACCESS_IO, /* Warning: Some registers can only be read/written correctly via GB_memory_read/write. */ + GB_DIRECT_ACCESS_BOOTROM, + GB_DIRECT_ACCESS_OAM, + GB_DIRECT_ACCESS_BGP, + GB_DIRECT_ACCESS_OBP, +} GB_direct_access_t; + +/* Returns a mutable pointer to various hardware memories. If that memory is banked, the current bank + is returned at *bank, even if only a portion of the memory is banked. */ +void *GB_get_direct_access(GB_gameboy_t *gb, GB_direct_access_t access, size_t *size, uint16_t *bank); + void *GB_get_user_data(GB_gameboy_t *gb); void GB_set_user_data(GB_gameboy_t *gb, void *data); diff --git a/Core/memory.c b/Core/memory.c index fb8e7cc..70635a8 100644 --- a/Core/memory.c +++ b/Core/memory.c @@ -206,8 +206,8 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr) } uint8_t index_reg = (addr & 0xFF) - 1; return ((addr & 0xFF) == GB_IO_BGPD? - gb->background_palletes_data : - gb->sprite_palletes_data)[gb->io_registers[index_reg] & 0x3F]; + gb->background_palettes_data : + gb->sprite_palettes_data)[gb->io_registers[index_reg] & 0x3F]; } case GB_IO_KEY1: @@ -526,8 +526,8 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value) } uint8_t index_reg = (addr & 0xFF) - 1; ((addr & 0xFF) == GB_IO_BGPD? - gb->background_palletes_data : - gb->sprite_palletes_data)[gb->io_registers[index_reg] & 0x3F] = value; + gb->background_palettes_data : + gb->sprite_palettes_data)[gb->io_registers[index_reg] & 0x3F] = value; GB_palette_changed(gb, (addr & 0xFF) == GB_IO_BGPD, gb->io_registers[index_reg] & 0x3F); if (gb->io_registers[index_reg] & 0x80) { gb->io_registers[index_reg]++;