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:
parent
3feaeb153e
commit
fb55c35f87
@ -1,4 +1,3 @@
|
|||||||
#define GB_INTERNAL // Todo: several debugging functions access the GB struct directly
|
|
||||||
#include <AVFoundation/AVFoundation.h>
|
#include <AVFoundation/AVFoundation.h>
|
||||||
#include <CoreAudio/CoreAudio.h>
|
#include <CoreAudio/CoreAudio.h>
|
||||||
#include "GBAudioClient.h"
|
#include "GBAudioClient.h"
|
||||||
@ -47,8 +46,8 @@
|
|||||||
@property GBAudioClient *audioClient;
|
@property GBAudioClient *audioClient;
|
||||||
- (void) vblank;
|
- (void) vblank;
|
||||||
- (void) log: (const char *) log withAttributes: (GB_log_attributes) attributes;
|
- (void) log: (const char *) log withAttributes: (GB_log_attributes) attributes;
|
||||||
- (const char *) getDebuggerInput;
|
- (char *) getDebuggerInput;
|
||||||
- (const char *) getAsyncDebuggerInput;
|
- (char *) getAsyncDebuggerInput;
|
||||||
- (void) cameraRequestUpdate;
|
- (void) cameraRequestUpdate;
|
||||||
- (uint8_t) cameraGetPixelAtX:(uint8_t)x andY:(uint8_t)y;
|
- (uint8_t) cameraGetPixelAtX:(uint8_t)x andY:(uint8_t)y;
|
||||||
- (void) printImage:(uint32_t *)image height:(unsigned) height
|
- (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)
|
static char *consoleInput(GB_gameboy_t *gb)
|
||||||
{
|
{
|
||||||
Document *self = (__bridge Document *)GB_get_user_data(gb);
|
Document *self = (__bridge Document *)GB_get_user_data(gb);
|
||||||
return strdup([self getDebuggerInput]);
|
return [self getDebuggerInput];
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *asyncConsoleInput(GB_gameboy_t *gb)
|
static char *asyncConsoleInput(GB_gameboy_t *gb)
|
||||||
{
|
{
|
||||||
Document *self = (__bridge Document *)GB_get_user_data(gb);
|
Document *self = (__bridge Document *)GB_get_user_data(gb);
|
||||||
const char *ret = [self getAsyncDebuggerInput];
|
char *ret = [self getAsyncDebuggerInput];
|
||||||
return ret? strdup(ret) : NULL;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t rgbEncode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b)
|
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;
|
if (!running) return;
|
||||||
GB_debugger_set_disabled(&gb, true);
|
GB_debugger_set_disabled(&gb, true);
|
||||||
if (GB_debugger_is_stopped(&gb)) {
|
if (GB_debugger_is_stopped(&gb)) {
|
||||||
gb.debug_stopped = false;
|
[self interruptDebugInputRead];
|
||||||
[self consoleInput:nil];
|
|
||||||
}
|
}
|
||||||
stopping = true;
|
stopping = true;
|
||||||
running = false;
|
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);
|
return !GB_debugger_is_stopped(&gb);
|
||||||
}
|
}
|
||||||
else if ([anItem action] == @selector(reset:) && anItem.tag != 0) {
|
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:)) {
|
else if ([anItem action] == @selector(toggleBlend:)) {
|
||||||
[(NSMenuItem*)anItem setState:self.view.shouldBlendFrameWithPrevious];
|
[(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:@""];
|
[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:">"];
|
[self log:">"];
|
||||||
in_sync_input = true;
|
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];
|
[debugger_input_queue removeObjectAtIndex:0];
|
||||||
[has_debugger_input unlockWithCondition:[debugger_input_queue count] != 0];
|
[has_debugger_input unlockWithCondition:[debugger_input_queue count] != 0];
|
||||||
in_sync_input = false;
|
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];
|
[has_debugger_input lock];
|
||||||
NSString *input = [debugger_input_queue firstObject];
|
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];
|
[debugger_input_queue removeObjectAtIndex:0];
|
||||||
}
|
}
|
||||||
[has_debugger_input unlockWithCondition:[debugger_input_queue count] != 0];
|
[has_debugger_input unlockWithCondition:[debugger_input_queue count] != 0];
|
||||||
return [input UTF8String];
|
return input? strdup([input UTF8String]): NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)saveState:(id)sender
|
- (IBAction)saveState:(id)sender
|
||||||
@ -731,8 +739,7 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height,
|
|||||||
case 2:
|
case 2:
|
||||||
/* OAM */
|
/* OAM */
|
||||||
{
|
{
|
||||||
oamCount = GB_get_oam_info(&gb, oamInfo);
|
oamCount = GB_get_oam_info(&gb, oamInfo, &oamHeight);
|
||||||
oamHeight = (gb.io_registers[GB_IO_LCDC] & 4) ? 16:8;
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
if (!oamUpdating) {
|
if (!oamUpdating) {
|
||||||
oamUpdating = true;
|
oamUpdating = true;
|
||||||
@ -799,17 +806,23 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height,
|
|||||||
|
|
||||||
uint16_t n_banks = 1;
|
uint16_t n_banks = 1;
|
||||||
switch ([(GBMemoryByteArray *)(hex_controller.byteArray) mode]) {
|
switch ([(GBMemoryByteArray *)(hex_controller.byteArray) mode]) {
|
||||||
case GBMemoryROM:
|
case GBMemoryROM: {
|
||||||
n_banks = gb.rom_size / 0x4000;
|
size_t rom_size;
|
||||||
|
GB_get_direct_access(&gb, GB_DIRECT_ACCESS_ROM, &rom_size, NULL);
|
||||||
|
n_banks = rom_size / 0x4000;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case GBMemoryVRAM:
|
case GBMemoryVRAM:
|
||||||
n_banks = gb.is_cgb ? 2 : 1;
|
n_banks = GB_is_cgb(&gb) ? 2 : 1;
|
||||||
break;
|
break;
|
||||||
case GBMemoryExternalRAM:
|
case GBMemoryExternalRAM: {
|
||||||
n_banks = (gb.mbc_ram_size + 0x1FFF) / 0x2000;
|
size_t ram_size;
|
||||||
|
GB_get_direct_access(&gb, GB_DIRECT_ACCESS_CART_RAM, &ram_size, NULL);
|
||||||
|
n_banks = (ram_size + 0x1FFF) / 0x2000;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case GBMemoryRAM:
|
case GBMemoryRAM:
|
||||||
n_banks = gb.is_cgb ? 8 : 1;
|
n_banks = GB_is_cgb(&gb) ? 8 : 1;
|
||||||
break;
|
break;
|
||||||
case GBMemoryEntireSpace:
|
case GBMemoryEntireSpace:
|
||||||
break;
|
break;
|
||||||
@ -833,23 +846,28 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height,
|
|||||||
self.memoryBankItem.enabled = [sender indexOfSelectedItem] != GBMemoryEntireSpace;
|
self.memoryBankItem.enabled = [sender indexOfSelectedItem] != GBMemoryEntireSpace;
|
||||||
GBMemoryByteArray *byteArray = (GBMemoryByteArray *)(hex_controller.byteArray);
|
GBMemoryByteArray *byteArray = (GBMemoryByteArray *)(hex_controller.byteArray);
|
||||||
[byteArray setMode:(GB_memory_mode_t)[sender indexOfSelectedItem]];
|
[byteArray setMode:(GB_memory_mode_t)[sender indexOfSelectedItem]];
|
||||||
|
uint16_t bank;
|
||||||
switch ((GB_memory_mode_t)[sender indexOfSelectedItem]) {
|
switch ((GB_memory_mode_t)[sender indexOfSelectedItem]) {
|
||||||
case GBMemoryEntireSpace:
|
case GBMemoryEntireSpace:
|
||||||
case GBMemoryROM:
|
case GBMemoryROM:
|
||||||
lineRep.valueOffset = 0;
|
lineRep.valueOffset = 0;
|
||||||
byteArray.selectedBank = gb.mbc_rom_bank;
|
GB_get_direct_access(&gb, GB_DIRECT_ACCESS_ROM, NULL, &bank);
|
||||||
|
byteArray.selectedBank = bank;
|
||||||
break;
|
break;
|
||||||
case GBMemoryVRAM:
|
case GBMemoryVRAM:
|
||||||
lineRep.valueOffset = 0x8000;
|
lineRep.valueOffset = 0x8000;
|
||||||
byteArray.selectedBank = gb.cgb_vram_bank;
|
GB_get_direct_access(&gb, GB_DIRECT_ACCESS_VRAM, NULL, &bank);
|
||||||
|
byteArray.selectedBank = bank;
|
||||||
break;
|
break;
|
||||||
case GBMemoryExternalRAM:
|
case GBMemoryExternalRAM:
|
||||||
lineRep.valueOffset = 0xA000;
|
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;
|
break;
|
||||||
case GBMemoryRAM:
|
case GBMemoryRAM:
|
||||||
lineRep.valueOffset = 0xC000;
|
lineRep.valueOffset = 0xC000;
|
||||||
byteArray.selectedBank = gb.cgb_ram_bank;
|
GB_get_direct_access(&gb, GB_DIRECT_ACCESS_RAM, NULL, &bank);
|
||||||
|
byteArray.selectedBank = bank;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
[self.memoryBankInput setStringValue:[NSString stringWithFormat:@"$%x", byteArray.selectedBank]];
|
[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;
|
uint16_t map_base = 0x1800;
|
||||||
GB_map_type_t map_type = (GB_map_type_t) self.tilemapMapButton.indexOfSelectedItem;
|
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;
|
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;
|
map_base = 0x1c00;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tileset_type == GB_TILESET_AUTO) {
|
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;
|
uint16_t tile_address = 0;
|
||||||
if (tileset_type == GB_TILESET_8000) {
|
if (tileset_type == GB_TILESET_8000) {
|
||||||
tile_address = 0x8000 + tile * 0x10;
|
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;
|
tile_address = 0x9000 + (int8_t)tile * 0x10;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gb.is_cgb) {
|
if (GB_is_cgb(&gb)) {
|
||||||
uint8_t attributes = gb.vram[map_base + map_offset + 0x2000];
|
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)",
|
self.vramStatusLabel.stringValue = [NSString stringWithFormat:@"Tile number $%02x (%d:$%04x) at map address $%04x (Attributes: %c%c%c%d%d)",
|
||||||
tile,
|
tile,
|
||||||
attributes & 0x8? 1 : 0,
|
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];
|
NSUInteger columnIndex = [[tableView tableColumns] indexOfObject:tableColumn];
|
||||||
if (tableView == self.paletteTableView) {
|
if (tableView == self.paletteTableView) {
|
||||||
if (columnIndex == 0) {
|
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;
|
uint16_t index = columnIndex - 1 + (row & 7) * 4;
|
||||||
return @(((row >= 8? gb.sprite_palletes_data : gb.background_palletes_data)[(index << 1) + 1] << 8) |
|
return @((palette_data[(index << 1) + 1] << 8) | palette_data[(index << 1)]);
|
||||||
(row >= 8? gb.sprite_palletes_data : gb.background_palletes_data)[(index << 1)]);
|
|
||||||
}
|
}
|
||||||
else if (tableView == self.spritesTableView) {
|
else if (tableView == self.spritesTableView) {
|
||||||
switch (columnIndex) {
|
switch (columnIndex) {
|
||||||
@ -1092,7 +1113,7 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height,
|
|||||||
case 5:
|
case 5:
|
||||||
return [NSString stringWithFormat:@"$%04x", oamInfo[row].oam_addr];
|
return [NSString stringWithFormat:@"$%04x", oamInfo[row].oam_addr];
|
||||||
case 6:
|
case 6:
|
||||||
if (gb.cgb_mode) {
|
if (GB_is_cgb(&gb)) {
|
||||||
return [NSString stringWithFormat:@"%c%c%c%d%d",
|
return [NSString stringWithFormat:@"%c%c%c%d%d",
|
||||||
oamInfo[row].flags & 0x80? 'P' : '-',
|
oamInfo[row].flags & 0x80? 'P' : '-',
|
||||||
oamInfo[row].flags & 0x40? 'Y' : '-',
|
oamInfo[row].flags & 0x40? 'Y' : '-',
|
||||||
|
@ -1368,7 +1368,7 @@ static bool palettes(GB_gameboy_t *gb, char *arguments, char *modifiers, const d
|
|||||||
|
|
||||||
GB_log(gb, "Background palettes: \n");
|
GB_log(gb, "Background palettes: \n");
|
||||||
for (unsigned i = 0; i < 32; i++) {
|
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) {
|
if (i % 4 == 3) {
|
||||||
GB_log(gb, "\n");
|
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");
|
GB_log(gb, "Sprites palettes: \n");
|
||||||
for (unsigned i = 0; i < 32; i++) {
|
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) {
|
if (i % 4 == 3) {
|
||||||
GB_log(gb, "\n");
|
GB_log(gb, "\n");
|
||||||
}
|
}
|
||||||
@ -1704,6 +1704,12 @@ next_command:
|
|||||||
gb->stack_leak_detection = false;
|
gb->stack_leak_detection = false;
|
||||||
input = gb->input_callback(gb);
|
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)) {
|
if (GB_debugger_do_command(gb, input)) {
|
||||||
goto next_command;
|
goto next_command;
|
||||||
}
|
}
|
||||||
|
@ -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_pixel = (gb->io_registers[use_obp1? GB_IO_OBP1:GB_IO_OBP0] >> (sprite_pixel << 1)) & 3;
|
||||||
sprite_palette = use_obp1;
|
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) {
|
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_pixel = (gb->io_registers[use_obp1? GB_IO_OBP1:GB_IO_OBP0] >> (sprite_pixel << 1)) & 3;
|
||||||
sprite_palette = use_obp1;
|
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) {
|
if (!gb->cgb_mode) {
|
||||||
background_pixel = ((gb->io_registers[GB_IO_BGP] >> (background_pixel << 1)) & 3);
|
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)
|
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)
|
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);
|
uint16_t color = palette_data[index & ~1] | (palette_data[index | 1] << 8);
|
||||||
|
|
||||||
// No need to &, scale channel does that.
|
// 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 g = scale_channel(color >> 5);
|
||||||
uint8_t b = scale_channel(color >> 10);
|
uint8_t b = scale_channel(color >> 10);
|
||||||
assert (gb->rgb_encode_callback);
|
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;
|
palette = none_palette;
|
||||||
break;
|
break;
|
||||||
case GB_PALETTE_BACKGROUND:
|
case GB_PALETTE_BACKGROUND:
|
||||||
palette = gb->background_palletes_rgb + (4 * (palette_index & 7));
|
palette = gb->background_palettes_rgb + (4 * (palette_index & 7));
|
||||||
break;
|
break;
|
||||||
case GB_PALETTE_OAM:
|
case GB_PALETTE_OAM:
|
||||||
palette = gb->sprite_palletes_rgb + (4 * (palette_index & 7));
|
palette = gb->sprite_palettes_rgb + (4 * (palette_index & 7));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned y = 0; y < 192; y++) {
|
for (unsigned y = 0; y < 192; y++) {
|
||||||
for (unsigned x = 0; x < 256; x++) {
|
for (unsigned x = 0; x < 256; x++) {
|
||||||
if (x >= 128 && !gb->is_cgb) {
|
if (x >= 128 && !gb->is_cgb) {
|
||||||
*(dest++) = gb->background_palletes_rgb[0];
|
*(dest++) = gb->background_palettes_rgb[0];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
uint16_t tile = (x % 128) / 8 + y / 8 * 16;
|
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;
|
palette = none_palette;
|
||||||
break;
|
break;
|
||||||
case GB_PALETTE_BACKGROUND:
|
case GB_PALETTE_BACKGROUND:
|
||||||
palette = gb->background_palletes_rgb + (4 * (palette_index & 7));
|
palette = gb->background_palettes_rgb + (4 * (palette_index & 7));
|
||||||
break;
|
break;
|
||||||
case GB_PALETTE_OAM:
|
case GB_PALETTE_OAM:
|
||||||
palette = gb->sprite_palletes_rgb + (4 * (palette_index & 7));
|
palette = gb->sprite_palettes_rgb + (4 * (palette_index & 7));
|
||||||
break;
|
break;
|
||||||
case GB_PALETTE_AUTO:
|
case GB_PALETTE_AUTO:
|
||||||
break;
|
break;
|
||||||
@ -683,16 +683,16 @@ void GB_draw_tilemap(GB_gameboy_t *gb, uint32_t *dest, GB_palette_type_t palette
|
|||||||
*(dest++) = palette[pixel];
|
*(dest++) = palette[pixel];
|
||||||
}
|
}
|
||||||
else {
|
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;
|
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,};
|
uint8_t oam_to_dest_index[40] = {0,};
|
||||||
for (unsigned y = 0; y < LINES; y++) {
|
for (unsigned y = 0; y < LINES; y++) {
|
||||||
GB_sprite_t *sprite = (GB_sprite_t *) &gb->oam;
|
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;
|
int sprite_y = sprite->y - 16;
|
||||||
bool obscured = false;
|
bool obscured = false;
|
||||||
// Is sprite not in this line?
|
// 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;
|
if (++sprites_in_line == 11) obscured = true;
|
||||||
|
|
||||||
GB_oam_info_t *info = NULL;
|
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;
|
oam_to_dest_index[i] = ++count;
|
||||||
info->x = sprite->x;
|
info->x = sprite->x;
|
||||||
info->y = sprite->y;
|
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->flags = sprite->flags;
|
||||||
info->obscured_by_line_limit = false;
|
info->obscured_by_line_limit = false;
|
||||||
info->oam_addr = 0xFE00 + i * sizeof(*sprite);
|
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;
|
uint16_t vram_address = dest[i].tile * 0x10;
|
||||||
uint8_t flags = dest[i].flags;
|
uint8_t flags = dest[i].flags;
|
||||||
uint8_t palette = gb->cgb_mode? (flags & 7) : ((flags & 0x10)? 1 : 0);
|
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++) {
|
for (unsigned x = 0; x < 8; x++) {
|
||||||
uint8_t color = (((gb->vram[vram_address ] >> ((~x)&7)) & 1 ) |
|
uint8_t color = (((gb->vram[vram_address ] >> ((~x)&7)) & 1 ) |
|
||||||
((gb->vram[vram_address + 1] >> ((~x)&7)) & 1) << 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) {
|
if (!gb->cgb_mode) {
|
||||||
color = (gb->io_registers[palette? GB_IO_OBP1:GB_IO_OBP0] >> (color << 1)) & 3;
|
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;
|
vram_address += 2;
|
||||||
}
|
}
|
||||||
|
@ -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_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);
|
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 */
|
#endif /* display_h */
|
||||||
|
81
Core/gb.c
81
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)
|
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->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);
|
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);
|
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);
|
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);
|
callback(gb, 0, 0, 0);
|
||||||
}
|
}
|
||||||
gb->rgb_encode_callback = callback;
|
gb->rgb_encode_callback = callback;
|
||||||
@ -540,6 +540,11 @@ bool GB_is_inited(GB_gameboy_t *gb)
|
|||||||
return gb->magic == 'SAME';
|
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)
|
void GB_set_turbo_mode(GB_gameboy_t *gb, bool on, bool no_frame_skip)
|
||||||
{
|
{
|
||||||
gb->turbo = on;
|
gb->turbo = on;
|
||||||
@ -592,13 +597,13 @@ void GB_reset(GB_gameboy_t *gb)
|
|||||||
memset(gb->vram, 0, gb->vram_size);
|
memset(gb->vram, 0, gb->vram_size);
|
||||||
|
|
||||||
if (gb->rgb_encode_callback) {
|
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->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->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->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);
|
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);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
26
Core/gb.h
26
Core/gb.h
@ -361,10 +361,10 @@ struct GB_gameboy_internal_s {
|
|||||||
uint32_t vram_size; // Different between CGB and DMG
|
uint32_t vram_size; // Different between CGB and DMG
|
||||||
uint8_t cgb_vram_bank;
|
uint8_t cgb_vram_bank;
|
||||||
uint8_t oam[0xA0];
|
uint8_t oam[0xA0];
|
||||||
uint8_t background_palletes_data[0x40];
|
uint8_t background_palettes_data[0x40];
|
||||||
uint8_t sprite_palletes_data[0x40];
|
uint8_t sprite_palettes_data[0x40];
|
||||||
uint32_t background_palletes_rgb[0x20];
|
uint32_t background_palettes_rgb[0x20];
|
||||||
uint32_t sprite_palletes_rgb[0x20];
|
uint32_t sprite_palettes_rgb[0x20];
|
||||||
int16_t previous_lcdc_x;
|
int16_t previous_lcdc_x;
|
||||||
uint8_t padding;
|
uint8_t padding;
|
||||||
bool effective_window_enabled;
|
bool effective_window_enabled;
|
||||||
@ -481,11 +481,29 @@ __attribute__((__format__ (__printf__, fmtarg, firstvararg)))
|
|||||||
void GB_init(GB_gameboy_t *gb);
|
void GB_init(GB_gameboy_t *gb);
|
||||||
void GB_init_cgb(GB_gameboy_t *gb);
|
void GB_init_cgb(GB_gameboy_t *gb);
|
||||||
bool GB_is_inited(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_free(GB_gameboy_t *gb);
|
||||||
void GB_reset(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, bool is_cgb);
|
||||||
void GB_run(GB_gameboy_t *gb);
|
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_get_user_data(GB_gameboy_t *gb);
|
||||||
void GB_set_user_data(GB_gameboy_t *gb, void *data);
|
void GB_set_user_data(GB_gameboy_t *gb, void *data);
|
||||||
|
|
||||||
|
@ -206,8 +206,8 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
|
|||||||
}
|
}
|
||||||
uint8_t index_reg = (addr & 0xFF) - 1;
|
uint8_t index_reg = (addr & 0xFF) - 1;
|
||||||
return ((addr & 0xFF) == GB_IO_BGPD?
|
return ((addr & 0xFF) == GB_IO_BGPD?
|
||||||
gb->background_palletes_data :
|
gb->background_palettes_data :
|
||||||
gb->sprite_palletes_data)[gb->io_registers[index_reg] & 0x3F];
|
gb->sprite_palettes_data)[gb->io_registers[index_reg] & 0x3F];
|
||||||
}
|
}
|
||||||
|
|
||||||
case GB_IO_KEY1:
|
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;
|
uint8_t index_reg = (addr & 0xFF) - 1;
|
||||||
((addr & 0xFF) == GB_IO_BGPD?
|
((addr & 0xFF) == GB_IO_BGPD?
|
||||||
gb->background_palletes_data :
|
gb->background_palettes_data :
|
||||||
gb->sprite_palletes_data)[gb->io_registers[index_reg] & 0x3F] = value;
|
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);
|
GB_palette_changed(gb, (addr & 0xFF) == GB_IO_BGPD, gb->io_registers[index_reg] & 0x3F);
|
||||||
if (gb->io_registers[index_reg] & 0x80) {
|
if (gb->io_registers[index_reg] & 0x80) {
|
||||||
gb->io_registers[index_reg]++;
|
gb->io_registers[index_reg]++;
|
||||||
|
Loading…
Reference in New Issue
Block a user