Stabilizing API: New joypad, debugger and reset APIs; internal APIs and direct struct access are no longer available without defining GB_INTERNAL. The SDL port uses the new “public” APIs, as well as most of the non-debug Cocoa code.
This commit is contained in:
parent
0b1e2784cd
commit
a925ef130d
@ -1,16 +1,13 @@
|
||||
#define GB_INTERNAL // Todo: several debugging functions access the GB struct directly
|
||||
#include <AVFoundation/AVFoundation.h>
|
||||
#include <CoreAudio/CoreAudio.h>
|
||||
#include "GBAudioClient.h"
|
||||
#include "Document.h"
|
||||
#include "AppDelegate.h"
|
||||
#include "gb.h"
|
||||
#include "debugger.h"
|
||||
#include "memory.h"
|
||||
#include "camera.h"
|
||||
#include "display.h"
|
||||
#include "HexFiend/HexFiend.h"
|
||||
#include "GBMemoryByteArray.h"
|
||||
#include "GBWarningPopover.h"
|
||||
#include "gb.h"
|
||||
|
||||
/* Todo: The general Objective-C coding style conflicts with SameBoy's. This file needs a cleanup. */
|
||||
/* Todo: Split into category files! This is so messy!!! */
|
||||
@ -61,25 +58,25 @@
|
||||
|
||||
static void vblank(GB_gameboy_t *gb)
|
||||
{
|
||||
Document *self = (__bridge Document *)(gb->user_data);
|
||||
Document *self = (__bridge Document *)GB_get_user_data(gb);
|
||||
[self vblank];
|
||||
}
|
||||
|
||||
static void consoleLog(GB_gameboy_t *gb, const char *string, GB_log_attributes attributes)
|
||||
{
|
||||
Document *self = (__bridge Document *)(gb->user_data);
|
||||
Document *self = (__bridge Document *)GB_get_user_data(gb);
|
||||
[self log:string withAttributes: attributes];
|
||||
}
|
||||
|
||||
static char *consoleInput(GB_gameboy_t *gb)
|
||||
{
|
||||
Document *self = (__bridge Document *)(gb->user_data);
|
||||
Document *self = (__bridge Document *)GB_get_user_data(gb);
|
||||
return strdup([self getDebuggerInput]);
|
||||
}
|
||||
|
||||
static char *asyncConsoleInput(GB_gameboy_t *gb)
|
||||
{
|
||||
Document *self = (__bridge Document *)(gb->user_data);
|
||||
Document *self = (__bridge Document *)GB_get_user_data(gb);
|
||||
const char *ret = [self getAsyncDebuggerInput];
|
||||
return ret? strdup(ret) : NULL;
|
||||
}
|
||||
@ -91,20 +88,20 @@ static uint32_t rgbEncode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b)
|
||||
|
||||
static void cameraRequestUpdate(GB_gameboy_t *gb)
|
||||
{
|
||||
Document *self = (__bridge Document *)(gb->user_data);
|
||||
Document *self = (__bridge Document *)GB_get_user_data(gb);
|
||||
[self cameraRequestUpdate];
|
||||
}
|
||||
|
||||
static uint8_t cameraGetPixel(GB_gameboy_t *gb, uint8_t x, uint8_t y)
|
||||
{
|
||||
Document *self = (__bridge Document *)(gb->user_data);
|
||||
Document *self = (__bridge Document *)GB_get_user_data(gb);
|
||||
return [self cameraGetPixelAtX:x andY:y];
|
||||
}
|
||||
|
||||
static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height,
|
||||
uint8_t top_margin, uint8_t bottom_margin, uint8_t exposure)
|
||||
{
|
||||
Document *self = (__bridge Document *)(gb->user_data);
|
||||
Document *self = (__bridge Document *)GB_get_user_data(gb);
|
||||
[self printImage:image height:height topMargin:top_margin bottomMargin:bottom_margin exposure:exposure];
|
||||
}
|
||||
|
||||
@ -138,12 +135,11 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height,
|
||||
GB_init_cgb(&gb);
|
||||
[self initCommon];
|
||||
GB_load_boot_rom(&gb, [[[NSBundle mainBundle] pathForResource:@"cgb_boot" ofType:@"bin"] UTF8String]);
|
||||
|
||||
}
|
||||
|
||||
- (void) initCommon
|
||||
{
|
||||
gb.user_data = (__bridge void *)(self);
|
||||
GB_set_user_data(&gb, (__bridge void *)(self));
|
||||
GB_set_vblank_callback(&gb, (GB_vblank_callback_t) vblank);
|
||||
GB_set_log_callback(&gb, (GB_log_callback_t) consoleLog);
|
||||
GB_set_input_callback(&gb, (GB_input_callback_t) consoleInput);
|
||||
@ -151,13 +147,7 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height,
|
||||
GB_set_rgb_encode_callback(&gb, rgbEncode);
|
||||
GB_set_camera_get_pixel_callback(&gb, cameraGetPixel);
|
||||
GB_set_camera_update_request_callback(&gb, cameraRequestUpdate);
|
||||
NSString *rom_warnings = [self captureOutputForBlock:^{
|
||||
[self loadROM];
|
||||
}];
|
||||
if (rom_warnings && !rom_warning_issued) {
|
||||
rom_warning_issued = true;
|
||||
[GBWarningPopover popoverWithContents:rom_warnings onWindow:self.mainWindow];
|
||||
}
|
||||
[self loadROM];
|
||||
}
|
||||
|
||||
- (void) vblank
|
||||
@ -203,52 +193,37 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height,
|
||||
- (void) stop
|
||||
{
|
||||
if (!running) return;
|
||||
gb.debug_disable = true;
|
||||
if (gb.debug_stopped) {
|
||||
GB_debugger_set_disabled(&gb, true);
|
||||
if (GB_debugger_is_stopped(&gb)) {
|
||||
gb.debug_stopped = false;
|
||||
[self consoleInput:nil];
|
||||
}
|
||||
stopping = true;
|
||||
running = false;
|
||||
while (stopping);
|
||||
gb.debug_disable = false;
|
||||
GB_debugger_set_disabled(&gb, false);
|
||||
}
|
||||
|
||||
- (IBAction)reset:(id)sender
|
||||
{
|
||||
bool was_cgb = gb.is_cgb;
|
||||
[self stop];
|
||||
|
||||
/* Back up user's breakpoints/watchpoints */
|
||||
typeof(gb.breakpoints) breakpoints = gb.breakpoints;
|
||||
typeof(gb.n_breakpoints) n_breakpoints = gb.n_breakpoints;
|
||||
typeof(gb.watchpoints) watchpoints = gb.watchpoints;
|
||||
typeof(gb.n_watchpoints) n_watchpoints = gb.n_watchpoints;
|
||||
|
||||
/* Reset them so they're not freed*/
|
||||
gb.watchpoints = NULL;
|
||||
gb.breakpoints = NULL;
|
||||
gb.n_watchpoints = gb.n_breakpoints = 0;
|
||||
|
||||
GB_free(&gb);
|
||||
if (([sender tag] == 0 && was_cgb) || [sender tag] == 2) {
|
||||
[self initCGB];
|
||||
if ([sender tag] == 0) {
|
||||
GB_reset(&gb);
|
||||
}
|
||||
else {
|
||||
[self initDMG];
|
||||
GB_switch_model_and_reset(&gb, [sender tag] == 2);
|
||||
GB_load_boot_rom(&gb, [[[NSBundle mainBundle] pathForResource:[sender tag] == 2? @"cgb_boot" : @"dmg_boot" ofType:@"bin"] UTF8String]);
|
||||
}
|
||||
|
||||
/* Restore backpoints/watchpoints */
|
||||
gb.breakpoints = breakpoints;
|
||||
gb.n_breakpoints = n_breakpoints;
|
||||
gb.watchpoints = watchpoints;
|
||||
gb.n_watchpoints = n_watchpoints;
|
||||
|
||||
if ([sender tag] != 0) {
|
||||
/* User explictly selected a model, save the preference */
|
||||
[[NSUserDefaults standardUserDefaults] setBool:!gb.is_cgb forKey:@"EmulateDMG"];
|
||||
[[NSUserDefaults standardUserDefaults] setBool:[sender tag] == 1 forKey:@"EmulateDMG"];
|
||||
}
|
||||
[self readFromFile:self.fileName ofType:@"gb"];
|
||||
|
||||
/* Reload the ROM, SAV and SYM files */
|
||||
[self loadROM];
|
||||
|
||||
[self start];
|
||||
|
||||
if (hex_controller) {
|
||||
@ -380,10 +355,16 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height,
|
||||
|
||||
- (void) loadROM
|
||||
{
|
||||
GB_load_rom(&gb, [self.fileName UTF8String]);
|
||||
GB_load_battery(&gb, [[[self.fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"sav"] UTF8String]);
|
||||
GB_debugger_load_symbol_file(&gb, [[[NSBundle mainBundle] pathForResource:@"registers" ofType:@"sym"] UTF8String]);
|
||||
GB_debugger_load_symbol_file(&gb, [[[self.fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"sym"] UTF8String]);
|
||||
NSString *rom_warnings = [self captureOutputForBlock:^{
|
||||
GB_load_rom(&gb, [self.fileName UTF8String]);
|
||||
GB_load_battery(&gb, [[[self.fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"sav"] UTF8String]);
|
||||
GB_debugger_load_symbol_file(&gb, [[[NSBundle mainBundle] pathForResource:@"registers" ofType:@"sym"] UTF8String]);
|
||||
GB_debugger_load_symbol_file(&gb, [[[self.fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"sym"] UTF8String]);
|
||||
}];
|
||||
if (rom_warnings && !rom_warning_issued) {
|
||||
rom_warning_issued = true;
|
||||
[GBWarningPopover popoverWithContents:rom_warnings onWindow:self.mainWindow];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)close
|
||||
@ -398,7 +379,7 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height,
|
||||
- (IBAction) interrupt:(id)sender
|
||||
{
|
||||
[self log:"^C\n"];
|
||||
gb.debug_stopped = true;
|
||||
GB_debugger_break(&gb);
|
||||
if (!running) {
|
||||
[self start];
|
||||
}
|
||||
@ -428,8 +409,8 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height,
|
||||
[(NSMenuItem*)anItem setState:!self.audioClient.isPlaying];
|
||||
}
|
||||
else if ([anItem action] == @selector(togglePause:)) {
|
||||
[(NSMenuItem*)anItem setState:(!running) || (gb.debug_stopped)];
|
||||
return !gb.debug_stopped;
|
||||
[(NSMenuItem*)anItem setState:(!running) || (GB_debugger_is_stopped(&gb))];
|
||||
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)];
|
||||
@ -653,7 +634,7 @@ static void printImage(GB_gameboy_t *gb, uint32_t *image, uint8_t height,
|
||||
- (void) performAtomicBlock: (void (^)())block
|
||||
{
|
||||
while (!GB_is_inited(&gb));
|
||||
bool was_running = running && !gb.debug_stopped;
|
||||
bool was_running = running && !GB_debugger_is_stopped(&gb);
|
||||
if (was_running) {
|
||||
[self stop];
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
#define GB_INTERNAL // Todo: Some memory accesses are being done using the struct directly
|
||||
#import "GBMemoryByteArray.h"
|
||||
#import "GBCompleteByteSlice.h"
|
||||
|
||||
|
@ -172,11 +172,11 @@
|
||||
handled = true;
|
||||
switch (i) {
|
||||
case GBTurbo:
|
||||
_gb->turbo = true;
|
||||
GB_set_turbo_mode(_gb, true);
|
||||
break;
|
||||
|
||||
default:
|
||||
_gb->keys[i] = true;
|
||||
GB_set_key_state(_gb, (GB_key_t)i, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -198,11 +198,11 @@
|
||||
handled = true;
|
||||
switch (i) {
|
||||
case GBTurbo:
|
||||
_gb->turbo = false;
|
||||
GB_set_turbo_mode(_gb, false);
|
||||
break;
|
||||
|
||||
default:
|
||||
_gb->keys[i] = false;
|
||||
GB_set_key_state(_gb, (GB_key_t)i, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include "apu.h"
|
||||
#include "gb.h"
|
||||
|
||||
#undef max
|
||||
@ -443,4 +442,4 @@ void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value)
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,15 +2,11 @@
|
||||
#define apu_h
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "gb_struct_def.h"
|
||||
/* Divides nicely and never overflows with 4 channels */
|
||||
#define MAX_CH_AMP 0x1E00
|
||||
#define CH_STEP (0x1E00/0xF)
|
||||
|
||||
#include "save_struct.h"
|
||||
|
||||
struct GB_gameboy_s;
|
||||
typedef struct GB_gameboy_s GB_gameboy_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -59,10 +55,13 @@ typedef struct
|
||||
} GB_apu_t;
|
||||
|
||||
void GB_apu_copy_buffer(GB_gameboy_t *gb, GB_sample_t *dest, unsigned int count);
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
void GB_apu_write(GB_gameboy_t *gb, uint8_t reg, uint8_t value);
|
||||
uint8_t GB_apu_read(GB_gameboy_t *gb, uint8_t reg);
|
||||
void GB_apu_get_samples_and_update_pcm_regs(GB_gameboy_t *gb, GB_sample_t *samples);
|
||||
void GB_apu_init(GB_gameboy_t *gb);
|
||||
void GB_apu_run(GB_gameboy_t *gb);
|
||||
#endif
|
||||
|
||||
#endif /* apu_h */
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include "camera.h"
|
||||
#include "gb.h"
|
||||
|
||||
static int noise_seed = 0;
|
||||
|
||||
@ -147,4 +147,4 @@ uint8_t GB_camera_read_register(GB_gameboy_t *gb, uint16_t addr)
|
||||
return gb->camera_registers[GB_CAMERA_SHOOT_AND_1D_FLAGS];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
#ifndef camera_h
|
||||
#define camera_h
|
||||
#include "gb.h"
|
||||
#include <stdint.h>
|
||||
#include "gb_struct_def.h"
|
||||
|
||||
typedef uint8_t (*GB_camera_get_pixel_callback_t)(GB_gameboy_t *gb, uint8_t x, uint8_t y);
|
||||
typedef void (*GB_camera_update_request_callback_t)(GB_gameboy_t *gb);
|
||||
|
||||
enum {
|
||||
GB_CAMERA_SHOOT_AND_1D_FLAGS = 0,
|
||||
|
@ -1,9 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "debugger.h"
|
||||
#include "memory.h"
|
||||
#include "z80_cpu.h"
|
||||
#include "gb.h"
|
||||
|
||||
typedef struct {
|
||||
@ -1792,3 +1789,18 @@ bool GB_debugger_evaluate(GB_gameboy_t *gb, const char *string, uint16_t *result
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
void GB_debugger_break(GB_gameboy_t *gb)
|
||||
{
|
||||
gb->debug_stopped = true;
|
||||
}
|
||||
|
||||
bool GB_debugger_is_stopped(GB_gameboy_t *gb)
|
||||
{
|
||||
return gb->debug_stopped;
|
||||
}
|
||||
|
||||
void GB_debugger_set_disabled(GB_gameboy_t *gb, bool disabled)
|
||||
{
|
||||
gb->debug_disable = disabled;
|
||||
}
|
||||
|
@ -1,15 +1,24 @@
|
||||
#ifndef debugger_h
|
||||
#define debugger_h
|
||||
#include "gb.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "gb_struct_def.h"
|
||||
#include "symbol_hash.h"
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
void GB_debugger_run(GB_gameboy_t *gb);
|
||||
void GB_debugger_handle_async_commands(GB_gameboy_t *gb);
|
||||
void GB_debugger_call_hook(GB_gameboy_t *gb, uint16_t call_addr);
|
||||
void GB_debugger_ret_hook(GB_gameboy_t *gb);
|
||||
void GB_debugger_test_write_watchpoint(GB_gameboy_t *gb, uint16_t addr, uint8_t value);
|
||||
void GB_debugger_test_read_watchpoint(GB_gameboy_t *gb, uint16_t addr);
|
||||
void GB_debugger_load_symbol_file(GB_gameboy_t *gb, const char *path);
|
||||
const GB_bank_symbol_t *GB_debugger_find_symbol(GB_gameboy_t *gb, uint16_t addr);
|
||||
#endif
|
||||
|
||||
void GB_debugger_load_symbol_file(GB_gameboy_t *gb, const char *path);
|
||||
const char *GB_debugger_name_for_address(GB_gameboy_t *gb, uint16_t addr);
|
||||
bool GB_debugger_evaluate(GB_gameboy_t *gb, const char *string, uint16_t *result, uint16_t *result_bank); /* result_bank is -1 if unused. */
|
||||
void GB_debugger_break(GB_gameboy_t *gb);
|
||||
bool GB_debugger_is_stopped(GB_gameboy_t *gb);
|
||||
void GB_debugger_set_disabled(GB_gameboy_t *gb, bool disabled);
|
||||
#endif /* debugger_h */
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "gb.h"
|
||||
#include "display.h"
|
||||
#ifdef _WIN32
|
||||
#define _WIN32_WINNT 0x0500
|
||||
#include <Windows.h>
|
||||
|
@ -2,8 +2,10 @@
|
||||
#define display_h
|
||||
|
||||
#include "gb.h"
|
||||
#ifdef GB_INTERNAL
|
||||
void GB_display_run(GB_gameboy_t *gb, uint8_t cycles);
|
||||
void GB_palette_changed(GB_gameboy_t *gb, bool background_palette, uint8_t index);
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
GB_PALETTE_NONE,
|
||||
@ -33,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);
|
||||
|
||||
#endif /* display_h */
|
||||
|
133
Core/gb.c
133
Core/gb.c
@ -9,13 +9,6 @@
|
||||
#include <sys/time.h>
|
||||
#include <sys/select.h>
|
||||
#include "gb.h"
|
||||
#include "memory.h"
|
||||
#include "timing.h"
|
||||
#include "z80_cpu.h"
|
||||
#include "joypad.h"
|
||||
#include "display.h"
|
||||
#include "debugger.h"
|
||||
#include "mbc.h"
|
||||
|
||||
void GB_attributed_logv(GB_gameboy_t *gb, GB_log_attributes attributes, const char *fmt, va_list args)
|
||||
{
|
||||
@ -92,54 +85,28 @@ static char *default_async_input_callback(GB_gameboy_t *gb)
|
||||
void GB_init(GB_gameboy_t *gb)
|
||||
{
|
||||
memset(gb, 0, sizeof(*gb));
|
||||
gb->version = GB_STRUCT_VERSION;
|
||||
gb->ram = malloc(gb->ram_size = 0x2000);
|
||||
memset(gb->ram, 0, gb->ram_size);
|
||||
gb->vram = malloc(gb->vram_size = 0x2000);
|
||||
memset(gb->vram, 0, gb->vram_size);
|
||||
|
||||
gb->mbc_rom_bank = 1;
|
||||
gb->last_rtc_second = time(NULL);
|
||||
gb->last_vblank = clock();
|
||||
gb->cgb_ram_bank = 1;
|
||||
|
||||
/* Todo: this bypasses the rgb encoder because it is not set yet. */
|
||||
gb->sprite_palletes_rgb[4] = gb->sprite_palletes_rgb[0] = gb->background_palletes_rgb[0] = 0xFFFFFFFF;
|
||||
gb->sprite_palletes_rgb[5] = gb->sprite_palletes_rgb[1] = gb->background_palletes_rgb[1] = 0xAAAAAAAA;
|
||||
gb->sprite_palletes_rgb[6] = gb->sprite_palletes_rgb[2] = gb->background_palletes_rgb[2] = 0x55555555;
|
||||
gb->input_callback = default_input_callback;
|
||||
gb->async_input_callback = default_async_input_callback;
|
||||
gb->cartridge_type = &GB_cart_defs[0]; // Default cartridge type
|
||||
|
||||
gb->io_registers[GB_IO_OBP0] = gb->io_registers[GB_IO_OBP1] = 0xFF;
|
||||
gb->io_registers[GB_IO_JOYP] = 0xF;
|
||||
gb->io_registers[GB_IO_SC] = 0x7E;
|
||||
gb->magic = (uintptr_t)'SAME';
|
||||
|
||||
GB_reset(gb);
|
||||
}
|
||||
|
||||
void GB_init_cgb(GB_gameboy_t *gb)
|
||||
{
|
||||
memset(gb, 0, sizeof(*gb));
|
||||
gb->version = GB_STRUCT_VERSION;
|
||||
gb->ram = malloc(gb->ram_size = 0x2000 * 8);
|
||||
memset(gb->ram, 0, gb->ram_size);
|
||||
gb->vram = malloc(gb->vram_size = 0x2000 * 2);
|
||||
memset(gb->vram, 0, gb->vram_size);
|
||||
gb->is_cgb = true;
|
||||
gb->cgb_mode = true;
|
||||
|
||||
gb->mbc_rom_bank = 1;
|
||||
gb->last_rtc_second = time(NULL);
|
||||
gb->last_vblank = clock();
|
||||
gb->cgb_ram_bank = 1;
|
||||
gb->input_callback = default_input_callback;
|
||||
gb->async_input_callback = default_async_input_callback;
|
||||
gb->cartridge_type = &GB_cart_defs[0]; // Default cartridge type
|
||||
|
||||
gb->io_registers[GB_IO_OBP0] = gb->io_registers[GB_IO_OBP1] = 0xFF;
|
||||
gb->io_registers[GB_IO_JOYP] = 0xF;
|
||||
gb->io_registers[GB_IO_SC] = 0x7C;
|
||||
gb->magic = 'SAME';
|
||||
GB_reset(gb);
|
||||
}
|
||||
|
||||
void GB_free(GB_gameboy_t *gb)
|
||||
@ -200,6 +167,9 @@ int GB_load_rom(GB_gameboy_t *gb, const char *path)
|
||||
gb->rom_size++;
|
||||
}
|
||||
fseek(f, 0, SEEK_SET);
|
||||
if (gb->rom) {
|
||||
free(gb->rom);
|
||||
}
|
||||
gb->rom = malloc(gb->rom_size);
|
||||
memset(gb->rom, 0xFF, gb->rom_size); /* Pad with 0xFFs */
|
||||
fread(gb->rom, gb->rom_size, 1, f);
|
||||
@ -476,6 +446,16 @@ 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] =
|
||||
callback(gb, 0xFF, 0xFF, 0xFF);
|
||||
gb->sprite_palletes_rgb[5] = gb->sprite_palletes_rgb[1] = gb->background_palletes_rgb[1] =
|
||||
callback(gb, 0xAA, 0xAA, 0xAA);
|
||||
gb->sprite_palletes_rgb[6] = gb->sprite_palletes_rgb[2] = gb->background_palletes_rgb[2] =
|
||||
callback(gb, 0x55, 0x55, 0x55);
|
||||
gb->sprite_palletes_rgb[7] = gb->sprite_palletes_rgb[3] = gb->background_palletes_rgb[3] =
|
||||
callback(gb, 0, 0, 0);
|
||||
}
|
||||
gb->rgb_encode_callback = callback;
|
||||
}
|
||||
|
||||
@ -554,3 +534,84 @@ void GB_disconnect_serial(GB_gameboy_t *gb)
|
||||
/* Reset any internally-emulated device. Currently, only the printer. */
|
||||
memset(&gb->printer, 0, sizeof(gb->printer));
|
||||
}
|
||||
|
||||
bool GB_is_inited(GB_gameboy_t *gb)
|
||||
{
|
||||
return gb->magic == 'SAME';
|
||||
}
|
||||
|
||||
void GB_set_turbo_mode(GB_gameboy_t *gb, bool on)
|
||||
{
|
||||
gb->turbo = on;
|
||||
}
|
||||
|
||||
void *GB_get_user_data(GB_gameboy_t *gb)
|
||||
{
|
||||
return gb->user_data;
|
||||
}
|
||||
|
||||
void GB_set_user_data(GB_gameboy_t *gb, void *data)
|
||||
{
|
||||
gb->user_data = data;
|
||||
}
|
||||
|
||||
void GB_reset(GB_gameboy_t *gb)
|
||||
{
|
||||
bool cgb = gb->is_cgb;
|
||||
memset(gb, 0, (size_t)GB_GET_SECTION((GB_gameboy_t *) 0, unsaved));
|
||||
gb->version = GB_STRUCT_VERSION;
|
||||
|
||||
gb->mbc_rom_bank = 1;
|
||||
gb->last_rtc_second = time(NULL);
|
||||
gb->last_vblank = clock();
|
||||
gb->cgb_ram_bank = 1;
|
||||
gb->io_registers[GB_IO_JOYP] = 0xF;
|
||||
gb->io_registers[GB_IO_OBP0] = gb->io_registers[GB_IO_OBP1] = 0xFF;
|
||||
|
||||
if (cgb) {
|
||||
gb->ram_size = 0x2000 * 8;
|
||||
memset(gb->ram, 0, gb->ram_size);
|
||||
gb->vram_size = 0x2000 * 2;
|
||||
memset(gb->vram, 0, gb->vram_size);
|
||||
|
||||
gb->is_cgb = true;
|
||||
gb->cgb_mode = true;
|
||||
|
||||
gb->io_registers[GB_IO_SC] = 0x7C;
|
||||
}
|
||||
else {
|
||||
gb->ram_size = 0x2000;
|
||||
memset(gb->ram, 0, gb->ram_size);
|
||||
gb->vram_size = 0x2000;
|
||||
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->rgb_encode_callback(gb, 0xFF, 0xFF, 0xFF);
|
||||
gb->sprite_palletes_rgb[5] = gb->sprite_palletes_rgb[1] = gb->background_palletes_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->rgb_encode_callback(gb, 0x55, 0x55, 0x55);
|
||||
gb->sprite_palletes_rgb[7] = gb->sprite_palletes_rgb[3] = gb->background_palletes_rgb[3] =
|
||||
gb->rgb_encode_callback(gb, 0, 0, 0);
|
||||
}
|
||||
|
||||
gb->io_registers[GB_IO_SC] = 0x7E;
|
||||
}
|
||||
gb->magic = (uintptr_t)'SAME';
|
||||
}
|
||||
|
||||
void GB_switch_model_and_reset(GB_gameboy_t *gb, bool is_cgb)
|
||||
{
|
||||
if (is_cgb) {
|
||||
gb->ram = realloc(gb->ram, gb->ram_size = 0x2000 * 8);
|
||||
gb->vram = realloc(gb->vram, gb->vram_size = 0x2000 * 2);
|
||||
}
|
||||
else {
|
||||
gb->ram = realloc(gb->ram, gb->ram_size = 0x2000);
|
||||
gb->vram = realloc(gb->vram, gb->vram_size = 0x2000);
|
||||
}
|
||||
gb->is_cgb = is_cgb;
|
||||
GB_reset(gb);
|
||||
|
||||
}
|
||||
|
239
Core/gb.h
239
Core/gb.h
@ -4,11 +4,21 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include "printer.h"
|
||||
#include "apu.h"
|
||||
#include "save_struct.h"
|
||||
#include "symbol_hash.h"
|
||||
|
||||
#include "gb_struct_def.h"
|
||||
#include "save_struct.h"
|
||||
|
||||
#include "apu.h"
|
||||
#include "camera.h"
|
||||
#include "debugger.h"
|
||||
#include "display.h"
|
||||
#include "joypad.h"
|
||||
#include "mbc.h"
|
||||
#include "memory.h"
|
||||
#include "printer.h"
|
||||
#include "timing.h"
|
||||
#include "z80_cpu.h"
|
||||
#include "symbol_hash.h"
|
||||
|
||||
#define GB_STRUCT_VERSION 10
|
||||
|
||||
@ -140,12 +150,6 @@ enum {
|
||||
GB_IO_UNKNOWN8 = 0x7F, // Unknown, write only
|
||||
};
|
||||
|
||||
#define LCDC_PERIOD 70224
|
||||
#define CPU_FREQUENCY 0x400000
|
||||
#define DIV_CYCLES (0x100)
|
||||
#define INTERNAL_DIV_CYCLES (0x40000)
|
||||
#define FRAME_LENGTH 16742706 // in nanoseconds
|
||||
|
||||
typedef enum {
|
||||
GB_LOG_BOLD = 1,
|
||||
GB_LOG_DASHED_UNDERLINE = 2,
|
||||
@ -153,40 +157,23 @@ typedef enum {
|
||||
GB_LOG_UNDERLINE_MASK = GB_LOG_DASHED_UNDERLINE | GB_LOG_UNDERLINE
|
||||
} GB_log_attributes;
|
||||
|
||||
struct GB_gameboy_s;
|
||||
typedef struct GB_gameboy_s GB_gameboy_t;
|
||||
#ifdef GB_INTERNAL
|
||||
#define LCDC_PERIOD 70224
|
||||
#define CPU_FREQUENCY 0x400000
|
||||
#define DIV_CYCLES (0x100)
|
||||
#define INTERNAL_DIV_CYCLES (0x40000)
|
||||
#define FRAME_LENGTH 16742706 // in nanoseconds
|
||||
#endif
|
||||
|
||||
typedef void (*GB_vblank_callback_t)(GB_gameboy_t *gb);
|
||||
typedef void (*GB_log_callback_t)(GB_gameboy_t *gb, const char *string, GB_log_attributes attributes);
|
||||
typedef char *(*GB_input_callback_t)(GB_gameboy_t *gb);
|
||||
typedef uint32_t (*GB_rgb_encode_callback_t)(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b);
|
||||
typedef void (*GB_infrared_callback_t)(GB_gameboy_t *gb, bool on, long cycles_since_last_update);
|
||||
typedef uint8_t (*GB_camera_get_pixel_callback_t)(GB_gameboy_t *gb, uint8_t x, uint8_t y);
|
||||
typedef void (*GB_camera_update_request_callback_t)(GB_gameboy_t *gb);
|
||||
typedef void (*GB_rumble_callback_t)(GB_gameboy_t *gb, bool rumble_on);
|
||||
typedef void (*GB_serial_transfer_start_callback_t)(GB_gameboy_t *gb, uint8_t byte_to_send);
|
||||
typedef uint8_t (*GB_serial_transfer_end_callback_t)(GB_gameboy_t *gb);
|
||||
|
||||
|
||||
typedef struct {
|
||||
enum {
|
||||
GB_NO_MBC,
|
||||
GB_MBC1,
|
||||
GB_MBC2,
|
||||
GB_MBC3,
|
||||
GB_MBC5,
|
||||
GB_HUC1, /* Todo: HUC1 features are not emulated. Should be unified with the CGB IR sensor API. */
|
||||
GB_HUC3,
|
||||
} mbc_type;
|
||||
enum {
|
||||
GB_STANDARD_MBC,
|
||||
GB_CAMERA,
|
||||
} mbc_subtype;
|
||||
bool has_ram;
|
||||
bool has_battery;
|
||||
bool has_rtc;
|
||||
bool has_rumble;
|
||||
} GB_cartridge_t;
|
||||
|
||||
typedef struct {
|
||||
bool state;
|
||||
long delay;
|
||||
@ -205,13 +192,11 @@ struct GB_watchpoint_s;
|
||||
/* Todo: We might want to typedef our own bool if this prevents SameBoy from working on specific platforms. */
|
||||
_Static_assert(sizeof(bool) == 1, "sizeof(bool) != 1");
|
||||
|
||||
enum {
|
||||
GB_TIMA_RUNNING = 0,
|
||||
GB_TIMA_RELOADING = 1,
|
||||
GB_TIMA_RELOADED = 2
|
||||
};
|
||||
|
||||
typedef struct GB_gameboy_s {
|
||||
#ifdef GB_INTERNAL
|
||||
struct GB_gameboy_s {
|
||||
#else
|
||||
struct GB_gameboy_internal_s {
|
||||
#endif
|
||||
GB_SECTION(header,
|
||||
/* The magic makes sure a state file is:
|
||||
- Indeed a SameBoy state file.
|
||||
@ -389,95 +374,103 @@ typedef struct GB_gameboy_s {
|
||||
);
|
||||
|
||||
/* Unsaved data. This includes all pointers, as well as everything that shouldn't be on a save state */
|
||||
/* This data is reserved on reset and must come last in the struct */
|
||||
GB_SECTION(unsaved,
|
||||
/* ROM */
|
||||
uint8_t *rom;
|
||||
uint32_t rom_size;
|
||||
const GB_cartridge_t *cartridge_type;
|
||||
enum {
|
||||
GB_STANDARD_MBC1_WIRING,
|
||||
GB_MBC1M_WIRING,
|
||||
} mbc1_wiring;
|
||||
|
||||
/* ROM */
|
||||
uint8_t *rom;
|
||||
uint32_t rom_size;
|
||||
const GB_cartridge_t *cartridge_type;
|
||||
enum {
|
||||
GB_STANDARD_MBC1_WIRING,
|
||||
GB_MBC1M_WIRING,
|
||||
} mbc1_wiring;
|
||||
/* Various RAMs */
|
||||
uint8_t *ram;
|
||||
uint8_t *vram;
|
||||
uint8_t *mbc_ram;
|
||||
|
||||
/* Various RAMs */
|
||||
uint8_t *ram;
|
||||
uint8_t *vram;
|
||||
uint8_t *mbc_ram;
|
||||
/* I/O */
|
||||
uint32_t *screen;
|
||||
GB_sample_t *audio_buffer;
|
||||
bool keys[GB_KEY_MAX];
|
||||
|
||||
/* I/O */
|
||||
uint32_t *screen;
|
||||
GB_sample_t *audio_buffer;
|
||||
bool keys[8];
|
||||
/* Audio Specific */
|
||||
unsigned int buffer_size;
|
||||
unsigned int sample_rate;
|
||||
unsigned int audio_position;
|
||||
bool audio_stream_started; // detects first copy request to minimize lag
|
||||
volatile bool audio_copy_in_progress;
|
||||
volatile bool apu_lock;
|
||||
|
||||
/* Audio Specific */
|
||||
unsigned int buffer_size;
|
||||
unsigned int sample_rate;
|
||||
unsigned int audio_position;
|
||||
bool audio_stream_started; // detects first copy request to minimize lag
|
||||
volatile bool audio_copy_in_progress;
|
||||
volatile bool apu_lock;
|
||||
/* Callbacks */
|
||||
void *user_data;
|
||||
GB_log_callback_t log_callback;
|
||||
GB_input_callback_t input_callback;
|
||||
GB_input_callback_t async_input_callback;
|
||||
GB_rgb_encode_callback_t rgb_encode_callback;
|
||||
GB_vblank_callback_t vblank_callback;
|
||||
GB_infrared_callback_t infrared_callback;
|
||||
GB_camera_get_pixel_callback_t camera_get_pixel_callback;
|
||||
GB_camera_update_request_callback_t camera_update_request_callback;
|
||||
GB_rumble_callback_t rumble_callback;
|
||||
GB_serial_transfer_start_callback_t serial_transfer_start_callback;
|
||||
GB_serial_transfer_end_callback_t serial_transfer_end_callback;
|
||||
/* IR */
|
||||
long cycles_since_ir_change;
|
||||
long cycles_since_input_ir_change;
|
||||
GB_ir_queue_item_t ir_queue[GB_MAX_IR_QUEUE];
|
||||
size_t ir_queue_length;
|
||||
|
||||
/* Callbacks */
|
||||
void *user_data;
|
||||
GB_log_callback_t log_callback;
|
||||
GB_input_callback_t input_callback;
|
||||
GB_input_callback_t async_input_callback;
|
||||
GB_rgb_encode_callback_t rgb_encode_callback;
|
||||
GB_vblank_callback_t vblank_callback;
|
||||
GB_infrared_callback_t infrared_callback;
|
||||
GB_camera_get_pixel_callback_t camera_get_pixel_callback;
|
||||
GB_camera_update_request_callback_t camera_update_request_callback;
|
||||
GB_rumble_callback_t rumble_callback;
|
||||
GB_serial_transfer_start_callback_t serial_transfer_start_callback;
|
||||
GB_serial_transfer_end_callback_t serial_transfer_end_callback;
|
||||
/* IR */
|
||||
long cycles_since_ir_change;
|
||||
long cycles_since_input_ir_change;
|
||||
GB_ir_queue_item_t ir_queue[GB_MAX_IR_QUEUE];
|
||||
size_t ir_queue_length;
|
||||
/*** Debugger ***/
|
||||
volatile bool debug_stopped, debug_disable;
|
||||
bool debug_fin_command, debug_next_command;
|
||||
|
||||
/*** Debugger ***/
|
||||
volatile bool debug_stopped, debug_disable;
|
||||
bool debug_fin_command, debug_next_command;
|
||||
/* Breakpoints */
|
||||
uint16_t n_breakpoints;
|
||||
struct GB_breakpoint_s *breakpoints;
|
||||
|
||||
/* Breakpoints */
|
||||
uint16_t n_breakpoints;
|
||||
struct GB_breakpoint_s *breakpoints;
|
||||
/* SLD (Todo: merge with backtrace) */
|
||||
bool stack_leak_detection;
|
||||
int debug_call_depth;
|
||||
uint16_t sp_for_call_depth[0x200]; /* Should be much more than enough */
|
||||
uint16_t addr_for_call_depth[0x200];
|
||||
|
||||
/* SLD (Todo: merge with backtrace) */
|
||||
bool stack_leak_detection;
|
||||
int debug_call_depth;
|
||||
uint16_t sp_for_call_depth[0x200]; /* Should be much more than enough */
|
||||
uint16_t addr_for_call_depth[0x200];
|
||||
/* Backtrace */
|
||||
unsigned int backtrace_size;
|
||||
uint16_t backtrace_sps[0x200];
|
||||
struct {
|
||||
uint16_t bank;
|
||||
uint16_t addr;
|
||||
} backtrace_returns[0x200];
|
||||
|
||||
/* Backtrace */
|
||||
unsigned int backtrace_size;
|
||||
uint16_t backtrace_sps[0x200];
|
||||
struct {
|
||||
uint16_t bank;
|
||||
uint16_t addr;
|
||||
} backtrace_returns[0x200];
|
||||
/* Watchpoints */
|
||||
uint16_t n_watchpoints;
|
||||
struct GB_watchpoint_s *watchpoints;
|
||||
|
||||
/* Watchpoints */
|
||||
uint16_t n_watchpoints;
|
||||
struct GB_watchpoint_s *watchpoints;
|
||||
/* Symbol tables */
|
||||
GB_symbol_map_t *bank_symbols[0x200];
|
||||
GB_reversed_symbol_map_t reversed_symbol_map;
|
||||
|
||||
/* Symbol tables */
|
||||
GB_symbol_map_t *bank_symbols[0x200];
|
||||
GB_reversed_symbol_map_t reversed_symbol_map;
|
||||
/* Ticks command */
|
||||
unsigned long debugger_ticks;
|
||||
|
||||
/* Ticks command */
|
||||
unsigned long debugger_ticks;
|
||||
/* Misc */
|
||||
bool turbo;
|
||||
bool turbo_dont_skip;
|
||||
bool disable_rendering;
|
||||
uint32_t ram_size; // Different between CGB and DMG
|
||||
uint8_t boot_rom[0x900];
|
||||
bool vblank_just_occured; // For slow operations involving syscalls; these should only run once per vblank
|
||||
);
|
||||
};
|
||||
|
||||
#ifndef GB_INTERNAL
|
||||
struct GB_gameboy_s {
|
||||
char __internal[sizeof(struct GB_gameboy_internal_s)];
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Misc */
|
||||
bool turbo;
|
||||
bool turbo_dont_skip;
|
||||
bool disable_rendering;
|
||||
uint32_t ram_size; // Different between CGB and DMG
|
||||
uint8_t boot_rom[0x900];
|
||||
bool vblank_just_occured; // For slow operations involving syscalls; these should only run once per vblank
|
||||
|
||||
} GB_gameboy_t;
|
||||
|
||||
#ifndef __printflike
|
||||
/* Missing from Linux headers. */
|
||||
@ -488,6 +481,8 @@ __attribute__((__format__ (__printf__, fmtarg, firstvararg)))
|
||||
void GB_init(GB_gameboy_t *gb);
|
||||
void GB_init_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);
|
||||
int GB_load_boot_rom(GB_gameboy_t *gb, const char *path);
|
||||
int GB_load_rom(GB_gameboy_t *gb, const char *path);
|
||||
int GB_save_battery(GB_gameboy_t *gb, const char *path);
|
||||
@ -519,8 +514,8 @@ void GB_serial_set_data(GB_gameboy_t *gb, uint8_t data);
|
||||
|
||||
void GB_disconnect_serial(GB_gameboy_t *gb);
|
||||
|
||||
static inline bool GB_is_inited(GB_gameboy_t *gb)
|
||||
{
|
||||
return gb->magic == 'SAME';
|
||||
}
|
||||
bool GB_is_inited(GB_gameboy_t *gb);
|
||||
void GB_set_turbo_mode(GB_gameboy_t *gb, bool on);
|
||||
void *GB_get_user_data(GB_gameboy_t *gb);
|
||||
void GB_set_user_data(GB_gameboy_t *gb, void *data);
|
||||
#endif /* GB_h */
|
||||
|
5
Core/gb_struct_def.h
Normal file
5
Core/gb_struct_def.h
Normal file
@ -0,0 +1,5 @@
|
||||
#ifndef gb_struct_def_h
|
||||
#define gb_struct_def_h
|
||||
struct GB_gameboy_s;
|
||||
typedef struct GB_gameboy_s GB_gameboy_t;
|
||||
#endif
|
@ -1,6 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include "gb.h"
|
||||
#include "joypad.h"
|
||||
#include <assert.h>
|
||||
|
||||
void GB_update_joyp(GB_gameboy_t *gb)
|
||||
{
|
||||
@ -54,4 +54,10 @@ void GB_update_joyp(GB_gameboy_t *gb)
|
||||
gb->io_registers[GB_IO_IF] |= 0x10;
|
||||
}
|
||||
gb->io_registers[GB_IO_JOYP] |= 0xC0; // No SGB support
|
||||
}
|
||||
}
|
||||
|
||||
void GB_set_key_state(GB_gameboy_t *gb, GB_key_t index, bool pressed)
|
||||
{
|
||||
assert(index >= 0 && index < GB_KEY_MAX);
|
||||
gb->keys[index] = pressed;
|
||||
}
|
||||
|
@ -1,8 +1,22 @@
|
||||
#ifndef joypad_h
|
||||
#define joypad_h
|
||||
#include "gb.h"
|
||||
#include "gb_struct_def.h"
|
||||
|
||||
typedef enum {
|
||||
GB_KEY_RIGHT,
|
||||
GB_KEY_LEFT,
|
||||
GB_KEY_UP,
|
||||
GB_KEY_DOWN,
|
||||
GB_KEY_A,
|
||||
GB_KEY_B,
|
||||
GB_KEY_SELECT,
|
||||
GB_KEY_START,
|
||||
GB_KEY_MAX
|
||||
} GB_key_t;
|
||||
|
||||
void GB_set_key_state(GB_gameboy_t *gb, GB_key_t index, bool pressed);
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
void GB_update_joyp(GB_gameboy_t *gb);
|
||||
void GB_update_keys_status(GB_gameboy_t *gb);
|
||||
|
||||
#endif
|
||||
#endif /* joypad_h */
|
||||
|
25
Core/mbc.h
25
Core/mbc.h
@ -1,8 +1,31 @@
|
||||
#ifndef MBC_h
|
||||
#define MBC_h
|
||||
#include "gb.h"
|
||||
#include "gb_struct_def.h"
|
||||
|
||||
typedef struct {
|
||||
enum {
|
||||
GB_NO_MBC,
|
||||
GB_MBC1,
|
||||
GB_MBC2,
|
||||
GB_MBC3,
|
||||
GB_MBC5,
|
||||
GB_HUC1, /* Todo: HUC1 features are not emulated. Should be unified with the CGB IR sensor API. */
|
||||
GB_HUC3,
|
||||
} mbc_type;
|
||||
enum {
|
||||
GB_STANDARD_MBC,
|
||||
GB_CAMERA,
|
||||
} mbc_subtype;
|
||||
bool has_ram;
|
||||
bool has_battery;
|
||||
bool has_rtc;
|
||||
bool has_rumble;
|
||||
} GB_cartridge_t;
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
extern const GB_cartridge_t GB_cart_defs[256];
|
||||
void GB_update_mbc_mappings(GB_gameboy_t *gb);
|
||||
void GB_configure_cart(GB_gameboy_t *gb);
|
||||
#endif
|
||||
|
||||
#endif /* MBC_h */
|
||||
|
@ -1,13 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include "gb.h"
|
||||
#include "joypad.h"
|
||||
#include "display.h"
|
||||
#include "memory.h"
|
||||
#include "debugger.h"
|
||||
#include "mbc.h"
|
||||
#include "timing.h"
|
||||
#include "camera.h"
|
||||
|
||||
typedef uint8_t GB_read_function_t(GB_gameboy_t *gb, uint16_t addr);
|
||||
typedef void GB_write_function_t(GB_gameboy_t *gb, uint16_t addr, uint8_t value);
|
||||
|
@ -4,7 +4,9 @@
|
||||
|
||||
uint8_t GB_read_memory(GB_gameboy_t *gb, uint16_t addr);
|
||||
void GB_write_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value);
|
||||
#ifdef GB_INTERNAL
|
||||
void GB_dma_run(GB_gameboy_t *gb);
|
||||
void GB_hdma_run(GB_gameboy_t *gb);
|
||||
#endif
|
||||
|
||||
#endif /* memory_h */
|
||||
|
@ -2,12 +2,10 @@
|
||||
#define printer_h
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "gb_struct_def.h"
|
||||
#define GB_PRINTER_MAX_COMMAND_LENGTH 0x280
|
||||
#define GB_PRINTER_DATA_SIZE 0x280
|
||||
|
||||
typedef struct GB_gameboy_s GB_gameboy_t;
|
||||
|
||||
typedef void (*GB_print_image_callback_t)(GB_gameboy_t *gb,
|
||||
uint32_t *image,
|
||||
uint8_t height,
|
||||
@ -57,7 +55,5 @@ typedef struct
|
||||
} GB_printer_t;
|
||||
|
||||
|
||||
typedef struct GB_gameboy_s GB_gameboy_t;
|
||||
|
||||
void GB_connect_printer(GB_gameboy_t *gb, GB_print_image_callback_t callback);
|
||||
#endif
|
||||
#endif
|
||||
|
@ -21,16 +21,17 @@ typedef struct {
|
||||
size_t n_symbols;
|
||||
} GB_symbol_map_t;
|
||||
|
||||
GB_bank_symbol_t *GB_map_add_symbol(GB_symbol_map_t *map, uint16_t addr, const char *name);
|
||||
const GB_bank_symbol_t *GB_map_find_symbol(GB_symbol_map_t *map, uint16_t addr);
|
||||
GB_symbol_map_t *GB_map_alloc(void);
|
||||
void GB_map_free(GB_symbol_map_t *map);
|
||||
|
||||
typedef struct {
|
||||
GB_symbol_t *buckets[0x400];
|
||||
} GB_reversed_symbol_map_t;
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
void GB_reversed_map_add_symbol(GB_reversed_symbol_map_t *map, uint16_t bank, GB_bank_symbol_t *symbol);
|
||||
const GB_symbol_t *GB_reversed_map_find_symbol(GB_reversed_symbol_map_t *map, const char *name);
|
||||
GB_bank_symbol_t *GB_map_add_symbol(GB_symbol_map_t *map, uint16_t addr, const char *name);
|
||||
const GB_bank_symbol_t *GB_map_find_symbol(GB_symbol_map_t *map, uint16_t addr);
|
||||
GB_symbol_map_t *GB_map_alloc(void);
|
||||
void GB_map_free(GB_symbol_map_t *map);
|
||||
#endif
|
||||
|
||||
#endif /* symbol_hash_h */
|
||||
|
@ -1,7 +1,4 @@
|
||||
#include "gb.h"
|
||||
#include "timing.h"
|
||||
#include "memory.h"
|
||||
#include "display.h"
|
||||
|
||||
static void GB_ir_run(GB_gameboy_t *gb)
|
||||
{
|
||||
|
@ -2,8 +2,17 @@
|
||||
#define timing_h
|
||||
#include "gb.h"
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
void GB_advance_cycles(GB_gameboy_t *gb, uint8_t cycles);
|
||||
void GB_set_internal_div_counter(GB_gameboy_t *gb, uint32_t value);
|
||||
void GB_rtc_run(GB_gameboy_t *gb);
|
||||
void GB_emulate_timer_glitch(GB_gameboy_t *gb, uint8_t old_tac, uint8_t new_tac);
|
||||
|
||||
enum {
|
||||
GB_TIMA_RUNNING = 0,
|
||||
GB_TIMA_RELOADING = 1,
|
||||
GB_TIMA_RELOADED = 2
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* timing_h */
|
||||
|
@ -1,9 +1,5 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include "z80_cpu.h"
|
||||
#include "timing.h"
|
||||
#include "memory.h"
|
||||
#include "debugger.h"
|
||||
#include "gb.h"
|
||||
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
#ifndef z80_cpu_h
|
||||
#define z80_cpu_h
|
||||
#include "gb.h"
|
||||
|
||||
void GB_cpu_disassemble(GB_gameboy_t *gb, uint16_t pc, uint16_t count);
|
||||
#ifdef GB_INTERNAL
|
||||
void GB_cpu_run(GB_gameboy_t *gb);
|
||||
#endif
|
||||
|
||||
#endif /* z80_cpu_h */
|
||||
|
@ -1,9 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include "z80_cpu.h"
|
||||
#include "memory.h"
|
||||
#include "gb.h"
|
||||
#include "debugger.h"
|
||||
|
||||
|
||||
typedef void GB_opcode_t(GB_gameboy_t *gb, uint8_t opcode, uint16_t *pc);
|
||||
|
4
Makefile
4
Makefile
@ -135,6 +135,10 @@ $(OBJ)/%.dep: %
|
||||
|
||||
# Compilation rules
|
||||
|
||||
$(OBJ)/Core/%.c.o: Core/%.c
|
||||
-@$(MKDIR) -p $(dir $@)
|
||||
$(CC) $(CFLAGS) -DGB_INTERNAL -c $< -o $@
|
||||
|
||||
$(OBJ)/%.c.o: %.c
|
||||
-@$(MKDIR) -p $(dir $@)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
@ -1,3 +1,6 @@
|
||||
#define GB_INTERNAL // Todo: This file runs SameBoy in a special configuration
|
||||
// of the turbo mode, which is not available without direct
|
||||
// struct access
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
@ -27,7 +30,7 @@ static void log_callback(GB_gameboy_t *gb, const char *string, GB_log_attributes
|
||||
static void vblank(GB_gameboy_t *gb)
|
||||
{
|
||||
|
||||
struct local_data *local_data = (struct local_data *)gb->user_data;
|
||||
struct local_data *local_data = (struct local_data *)GB_get_user_data(gb);
|
||||
|
||||
if (local_data->frames == LENGTH) {
|
||||
local_data->running = false;
|
||||
@ -66,7 +69,7 @@ int get_image_for_rom(const char *filename, const char *boot_path, uint32_t *out
|
||||
|
||||
/* Run emulation */
|
||||
struct local_data local_data = {0,};
|
||||
gb.user_data = &local_data;
|
||||
GB_set_user_data(&gb, &local_data);
|
||||
local_data.running = true;
|
||||
local_data.frames = 0;
|
||||
gb.turbo = gb.turbo_dont_skip = gb.disable_rendering = true;
|
||||
|
30
SDL/main.c
30
SDL/main.c
@ -16,7 +16,6 @@
|
||||
#endif
|
||||
|
||||
#include "gb.h"
|
||||
#include "debugger.h"
|
||||
|
||||
static bool running = false;
|
||||
static char *filename;
|
||||
@ -38,34 +37,33 @@ static void GB_update_keys_status(GB_gameboy_t *gb)
|
||||
running = false;
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP:
|
||||
gb->stopped = false;
|
||||
switch (event.key.keysym.sym) {
|
||||
case SDLK_RIGHT:
|
||||
gb->keys[0] = event.type == SDL_KEYDOWN;
|
||||
GB_set_key_state(gb, GB_KEY_RIGHT, event.type == SDL_KEYDOWN);
|
||||
break;
|
||||
case SDLK_LEFT:
|
||||
gb->keys[1] = event.type == SDL_KEYDOWN;
|
||||
GB_set_key_state(gb, GB_KEY_LEFT, event.type == SDL_KEYDOWN);
|
||||
break;
|
||||
case SDLK_UP:
|
||||
gb->keys[2] = event.type == SDL_KEYDOWN;
|
||||
GB_set_key_state(gb, GB_KEY_UP, event.type == SDL_KEYDOWN);
|
||||
break;
|
||||
case SDLK_DOWN:
|
||||
gb->keys[3] = event.type == SDL_KEYDOWN;
|
||||
GB_set_key_state(gb, GB_KEY_DOWN, event.type == SDL_KEYDOWN);
|
||||
break;
|
||||
case SDLK_x:
|
||||
gb->keys[4] = event.type == SDL_KEYDOWN;
|
||||
GB_set_key_state(gb, GB_KEY_A, event.type == SDL_KEYDOWN);
|
||||
break;
|
||||
case SDLK_z:
|
||||
gb->keys[5] = event.type == SDL_KEYDOWN;
|
||||
GB_set_key_state(gb, GB_KEY_B, event.type == SDL_KEYDOWN);
|
||||
break;
|
||||
case SDLK_BACKSPACE:
|
||||
gb->keys[6] = event.type == SDL_KEYDOWN;
|
||||
GB_set_key_state(gb, GB_KEY_SELECT, event.type == SDL_KEYDOWN);
|
||||
break;
|
||||
case SDLK_RETURN:
|
||||
gb->keys[7] = event.type == SDL_KEYDOWN;
|
||||
GB_set_key_state(gb, GB_KEY_START, event.type == SDL_KEYDOWN);
|
||||
break;
|
||||
case SDLK_SPACE:
|
||||
gb->turbo = event.type == SDL_KEYDOWN;
|
||||
GB_set_turbo_mode(gb, event.type == SDL_KEYDOWN);
|
||||
break;
|
||||
case SDLK_LCTRL:
|
||||
case SDLK_RCTRL:
|
||||
@ -85,7 +83,7 @@ static void GB_update_keys_status(GB_gameboy_t *gb)
|
||||
case SDLK_c:
|
||||
if (ctrl && event.type == SDL_KEYDOWN) {
|
||||
ctrl = false;
|
||||
gb->debug_stopped = true;
|
||||
GB_debugger_break(gb);
|
||||
|
||||
}
|
||||
break;
|
||||
@ -122,7 +120,7 @@ static void GB_update_keys_status(GB_gameboy_t *gb)
|
||||
|
||||
static void vblank(GB_gameboy_t *gb)
|
||||
{
|
||||
SDL_Surface *screen = gb->user_data;
|
||||
SDL_Surface *screen = GB_get_user_data(gb);
|
||||
SDL_Flip(screen);
|
||||
GB_update_keys_status(gb);
|
||||
|
||||
@ -189,10 +187,10 @@ static uint32_t rgb_encode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b)
|
||||
static void debugger_interrupt(int ignore)
|
||||
{
|
||||
/* ^C twice to exit */
|
||||
if (gb.debug_stopped) {
|
||||
if (GB_debugger_is_stopped(&gb)) {
|
||||
exit(0);
|
||||
}
|
||||
gb.debug_stopped = true;
|
||||
GB_debugger_break(&gb);
|
||||
}
|
||||
|
||||
|
||||
@ -280,7 +278,7 @@ usage:
|
||||
/* Configure Screen */
|
||||
SDL_LockSurface(screen);
|
||||
GB_set_vblank_callback(&gb, (GB_vblank_callback_t) vblank);
|
||||
gb.user_data = screen;
|
||||
GB_set_user_data(&gb, screen);
|
||||
GB_set_pixels_output(&gb, screen->pixels);
|
||||
GB_set_rgb_encode_callback(&gb, rgb_encode);
|
||||
|
||||
|
@ -1,3 +1,6 @@
|
||||
// The tester requires low-level access to the GB struct to detect failures
|
||||
#define GB_INTERNAL
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
|
Loading…
Reference in New Issue
Block a user