New APIs, Document.m no longer requires GB_INTERNAL, fixed a bug where the sprite viewer showed incorrect sprites for some CGB exclusive games.

This commit is contained in:
Lior Halphon 2017-04-19 23:26:39 +03:00
parent 3feaeb153e
commit fb55c35f87
7 changed files with 183 additions and 70 deletions

View File

@ -1,4 +1,3 @@
#define GB_INTERNAL // Todo: several debugging functions access the GB struct directly
#include <AVFoundation/AVFoundation.h>
#include <CoreAudio/CoreAudio.h>
#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,
@ -1073,9 +1093,10 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height,
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' : '-',

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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]++;