Add support to the ISX format, including symbols
This commit is contained in:
parent
36aa3f31b9
commit
152924e13f
@ -647,11 +647,16 @@ static void audioCallback(GB_gameboy_t *gb, GB_sample_t *sample)
|
||||
- (void) loadROM
|
||||
{
|
||||
NSString *rom_warnings = [self captureOutputForBlock:^{
|
||||
GB_load_rom(&gb, [self.fileName UTF8String]);
|
||||
GB_debugger_clear_symbols(&gb);
|
||||
if ([[self.fileType pathExtension] isEqualToString:@"isx"]) {
|
||||
GB_load_isx(&gb, [self.fileName UTF8String]);
|
||||
}
|
||||
else {
|
||||
GB_load_rom(&gb, [self.fileName UTF8String]);
|
||||
}
|
||||
GB_load_battery(&gb, [[[self.fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"sav"] UTF8String]);
|
||||
GB_load_cheats(&gb, [[[self.fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"cht"] UTF8String]);
|
||||
[self.cheatWindowController cheatsUpdated];
|
||||
GB_debugger_clear_symbols(&gb);
|
||||
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]);
|
||||
}];
|
||||
|
@ -16,7 +16,7 @@
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>Cartridge</string>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>GameBoy Game</string>
|
||||
<string>Game Boy Game</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>LSItemContentTypes</key>
|
||||
@ -36,7 +36,7 @@
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>ColorCartridge</string>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>GameBoy Color Game</string>
|
||||
<string>Game Boy Color Game</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>LSItemContentTypes</key>
|
||||
@ -48,6 +48,26 @@
|
||||
<key>NSDocumentClass</key>
|
||||
<string>Document</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>gbc</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>ColorCartridge</string>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Game Boy ISX File</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>LSItemContentTypes</key>
|
||||
<array>
|
||||
<string>com.github.liji32.sameboy.isx</string>
|
||||
</array>
|
||||
<key>LSTypeIsPackage</key>
|
||||
<integer>0</integer>
|
||||
<key>NSDocumentClass</key>
|
||||
<string>Document</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>SameBoy</string>
|
||||
@ -85,7 +105,7 @@
|
||||
<string>public.data</string>
|
||||
</array>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>GameBoy Game</string>
|
||||
<string>Game Boy Game</string>
|
||||
<key>UTTypeIconFile</key>
|
||||
<string>Cartridge</string>
|
||||
<key>UTTypeIdentifier</key>
|
||||
@ -104,7 +124,7 @@
|
||||
<string>public.data</string>
|
||||
</array>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>GameBoy Color Game</string>
|
||||
<string>Game Boy Color Game</string>
|
||||
<key>UTTypeIconFile</key>
|
||||
<string>ColorCartridge</string>
|
||||
<key>UTTypeIdentifier</key>
|
||||
@ -117,6 +137,25 @@
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
<string>public.data</string>
|
||||
</array>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>Game Boy ISX File</string>
|
||||
<key>UTTypeIconFile</key>
|
||||
<string>ColorCartridge</string>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>com.github.liji32.sameboy.isx</string>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>isx</string>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
</array>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>SameBoy needs to access your camera to emulate the Game Boy Camera</string>
|
||||
|
@ -2160,6 +2160,19 @@ void GB_debugger_handle_async_commands(GB_gameboy_t *gb)
|
||||
}
|
||||
}
|
||||
|
||||
void GB_debugger_add_symbol(GB_gameboy_t *gb, uint16_t bank, uint16_t address, const char *symbol)
|
||||
{
|
||||
bank &= 0x1FF;
|
||||
|
||||
if (!gb->bank_symbols[bank]) {
|
||||
gb->bank_symbols[bank] = GB_map_alloc();
|
||||
}
|
||||
GB_bank_symbol_t *allocated_symbol = GB_map_add_symbol(gb->bank_symbols[bank], address, symbol);
|
||||
if (allocated_symbol) {
|
||||
GB_reversed_map_add_symbol(&gb->reversed_symbol_map, bank, allocated_symbol);
|
||||
}
|
||||
}
|
||||
|
||||
void GB_debugger_load_symbol_file(GB_gameboy_t *gb, const char *path)
|
||||
{
|
||||
FILE *f = fopen(path, "r");
|
||||
@ -2182,14 +2195,7 @@ void GB_debugger_load_symbol_file(GB_gameboy_t *gb, const char *path)
|
||||
char symbol[length];
|
||||
|
||||
if (sscanf(line, "%x:%x %s", &bank, &address, symbol) == 3) {
|
||||
bank &= 0x1FF;
|
||||
if (!gb->bank_symbols[bank]) {
|
||||
gb->bank_symbols[bank] = GB_map_alloc();
|
||||
}
|
||||
GB_bank_symbol_t *allocated_symbol = GB_map_add_symbol(gb->bank_symbols[bank], address, symbol);
|
||||
if (allocated_symbol) {
|
||||
GB_reversed_map_add_symbol(&gb->reversed_symbol_map, bank, allocated_symbol);
|
||||
}
|
||||
GB_debugger_add_symbol(gb, bank, address, symbol);
|
||||
}
|
||||
}
|
||||
free(line);
|
||||
|
@ -14,6 +14,8 @@
|
||||
#define GB_debugger_call_hook(gb, addr) (void)addr
|
||||
#define GB_debugger_test_write_watchpoint(gb, addr, value) ((void)addr, (void)value)
|
||||
#define GB_debugger_test_read_watchpoint(gb, addr) (void)addr
|
||||
#define GB_debugger_add_symbol(gb, bank, address, symbol) ((void)bank, (void)address, (void)symbol)
|
||||
|
||||
#else
|
||||
void GB_debugger_run(GB_gameboy_t *gb);
|
||||
void GB_debugger_handle_async_commands(GB_gameboy_t *gb);
|
||||
@ -22,6 +24,7 @@ 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);
|
||||
const GB_bank_symbol_t *GB_debugger_find_symbol(GB_gameboy_t *gb, uint16_t addr);
|
||||
void GB_debugger_add_symbol(GB_gameboy_t *gb, uint16_t bank, uint16_t address, const char *symbol);
|
||||
#endif /* GB_DISABLE_DEBUGGER */
|
||||
#endif
|
||||
|
||||
|
213
Core/gb.c
213
Core/gb.c
@ -296,6 +296,219 @@ int GB_load_rom(GB_gameboy_t *gb, const char *path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GB_load_isx(GB_gameboy_t *gb, const char *path)
|
||||
{
|
||||
FILE *f = fopen(path, "rb");
|
||||
if (!f) {
|
||||
GB_log(gb, "Could not open ISX file: %s.\n", strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
char magic[4];
|
||||
#define READ(x) if (fread(&x, sizeof(x), 1, f) != 1) goto error
|
||||
fread(magic, 1, sizeof(magic), f);
|
||||
|
||||
bool extended = *(uint32_t *)&magic == htonl('ISX ');
|
||||
|
||||
fseek(f, extended? 0x20 : 0, SEEK_SET);
|
||||
|
||||
|
||||
uint8_t *old_rom = gb->rom;
|
||||
uint32_t old_size = gb->rom_size;
|
||||
gb->rom = NULL;
|
||||
gb->rom_size = 0;
|
||||
|
||||
while (true) {
|
||||
uint8_t record_type = 0;
|
||||
if (fread(&record_type, sizeof(record_type), 1, f) != 1) break;
|
||||
switch (record_type) {
|
||||
case 0x01: { // Binary
|
||||
uint16_t bank;
|
||||
uint16_t address;
|
||||
uint16_t length;
|
||||
uint8_t byte;
|
||||
READ(byte);
|
||||
bank = byte;
|
||||
if (byte >= 0x80) {
|
||||
READ(byte);
|
||||
bank |= byte << 8;
|
||||
}
|
||||
|
||||
READ(address);
|
||||
#ifdef GB_BIG_ENDIAN
|
||||
address = __builtin_bswap16(address);
|
||||
#endif
|
||||
address &= 0x3FFF;
|
||||
|
||||
READ(length);
|
||||
#ifdef GB_BIG_ENDIAN
|
||||
length = __builtin_bswap16(length);
|
||||
#endif
|
||||
|
||||
size_t needed_size = bank * 0x4000 + address + length;
|
||||
if (needed_size > 1024 * 1024 * 32)
|
||||
goto error;
|
||||
|
||||
if (gb->rom_size < needed_size) {
|
||||
gb->rom = realloc(gb->rom, needed_size);
|
||||
memset(gb->rom + gb->rom_size, 0, needed_size - gb->rom_size);
|
||||
gb->rom_size = needed_size;
|
||||
}
|
||||
|
||||
if (fread(gb->rom + (bank * 0x4000 + address), length, 1, f) != 1)
|
||||
goto error;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x11: { // Extended Binary
|
||||
uint32_t address;
|
||||
uint32_t length;
|
||||
|
||||
READ(address);
|
||||
#ifdef GB_BIG_ENDIAN
|
||||
address = __builtin_bswap32(address);
|
||||
#endif
|
||||
|
||||
READ(length);
|
||||
#ifdef GB_BIG_ENDIAN
|
||||
length = __builtin_bswap32(length);
|
||||
#endif
|
||||
size_t needed_size = address + length;
|
||||
if (needed_size > 1024 * 1024 * 32)
|
||||
goto error;
|
||||
if (gb->rom_size < needed_size) {
|
||||
gb->rom = realloc(gb->rom, needed_size);
|
||||
memset(gb->rom + gb->rom_size, 0, needed_size - gb->rom_size);
|
||||
gb->rom_size = needed_size;
|
||||
}
|
||||
|
||||
if (fread(gb->rom + address, length, 1, f) != 1)
|
||||
goto error;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x04: { // Symbol
|
||||
uint16_t count;
|
||||
uint8_t length;
|
||||
char name[257];
|
||||
uint8_t flag;
|
||||
uint16_t bank;
|
||||
uint16_t address;
|
||||
uint8_t byte;
|
||||
READ(count);
|
||||
#ifdef GB_BIG_ENDIAN
|
||||
count = __builtin_bswap16(count);
|
||||
#endif
|
||||
while (count--) {
|
||||
READ(length);
|
||||
if (fread(name, length, 1, f) != 1)
|
||||
goto error;
|
||||
name[length] = 0;
|
||||
READ(flag); // unused
|
||||
|
||||
READ(byte);
|
||||
bank = byte;
|
||||
if (byte >= 0x80) {
|
||||
READ(byte);
|
||||
bank |= byte << 8;
|
||||
}
|
||||
|
||||
READ(address);
|
||||
#ifdef GB_BIG_ENDIAN
|
||||
address = __builtin_bswap16(address);
|
||||
#endif
|
||||
GB_debugger_add_symbol(gb, bank, address, name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x14: { // Extended Binary
|
||||
uint16_t count;
|
||||
uint8_t length;
|
||||
char name[257];
|
||||
uint8_t flag;
|
||||
uint32_t address;
|
||||
READ(count);
|
||||
#ifdef GB_BIG_ENDIAN
|
||||
count = __builtin_bswap16(count);
|
||||
#endif
|
||||
while (count--) {
|
||||
READ(length);
|
||||
if (fread(name, length + 1, 1, f) != 1)
|
||||
goto error;
|
||||
name[length] = 0;
|
||||
READ(flag); // unused
|
||||
|
||||
READ(address);
|
||||
#ifdef GB_BIG_ENDIAN
|
||||
address = __builtin_bswap32(address);
|
||||
#endif
|
||||
// TODO: How to convert 32-bit addresses to Bank:Address? Needs to tell RAM and ROM apart
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
done:;
|
||||
#undef READ
|
||||
if (gb->rom_size == 0) goto error;
|
||||
|
||||
size_t needed_size = (gb->rom_size + 0x3FFF) & ~0x3FFF; /* Round to bank */
|
||||
|
||||
/* And then round to a power of two */
|
||||
while (needed_size & (needed_size - 1)) {
|
||||
/* I promise this works. */
|
||||
needed_size |= needed_size >> 1;
|
||||
needed_size++;
|
||||
}
|
||||
|
||||
if (needed_size < 0x8000) {
|
||||
needed_size = 0x8000;
|
||||
}
|
||||
|
||||
if (gb->rom_size < needed_size) {
|
||||
gb->rom = realloc(gb->rom, needed_size);
|
||||
memset(gb->rom + gb->rom_size, 0, needed_size - gb->rom_size);
|
||||
gb->rom_size = needed_size;
|
||||
}
|
||||
|
||||
GB_configure_cart(gb);
|
||||
|
||||
// Fix a common wrong MBC error
|
||||
if (gb->rom[0x147] == 3) { // MBC1 + RAM + Battery
|
||||
if (gb->rom_size == 64 * 0x4000) {
|
||||
for (unsigned i = 63 * 0x4000; i < 64 * 0x4000; i++) {
|
||||
if (gb->rom[i]) {
|
||||
gb->rom[0x147] = 0x10; // MBC3 + RTC + RAM + Battery
|
||||
GB_configure_cart(gb);
|
||||
gb->rom[0x147] = 0x3;
|
||||
GB_log(gb, "ROM uses MBC1 but appears to use all 64 banks, assuming MBC3\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (old_rom) {
|
||||
free(old_rom);
|
||||
}
|
||||
|
||||
return 0;
|
||||
error:
|
||||
GB_log(gb, "Invalid or unsupported ISX file.\n");
|
||||
if (gb->rom) {
|
||||
free(gb->rom);
|
||||
gb->rom = old_rom;
|
||||
gb->rom_size = old_size;
|
||||
}
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void GB_load_rom_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t size)
|
||||
{
|
||||
gb->rom_size = (size + 0x3fff) & ~0x3fff;
|
||||
|
@ -721,6 +721,7 @@ int GB_load_boot_rom(GB_gameboy_t *gb, const char *path);
|
||||
void GB_load_boot_rom_from_buffer(GB_gameboy_t *gb, const unsigned char *buffer, size_t size);
|
||||
int GB_load_rom(GB_gameboy_t *gb, const char *path);
|
||||
void GB_load_rom_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t size);
|
||||
int GB_load_isx(GB_gameboy_t *gb, const char *path);
|
||||
|
||||
int GB_save_battery_size(GB_gameboy_t *gb);
|
||||
int GB_save_battery_to_buffer(GB_gameboy_t *gb, uint8_t *buffer, size_t size);
|
||||
|
@ -8,7 +8,7 @@ char *do_open_rom_dialog(void)
|
||||
NSWindow *key = [NSApp keyWindow];
|
||||
NSOpenPanel *dialog = [NSOpenPanel openPanel];
|
||||
dialog.title = @"Open ROM";
|
||||
dialog.allowedFileTypes = @[@"gb", @"gbc", @"sgb"];
|
||||
dialog.allowedFileTypes = @[@"gb", @"gbc", @"sgb", @"isx"];
|
||||
[dialog runModal];
|
||||
[key makeKeyAndOrderFront:nil];
|
||||
NSString *ret = [[[dialog URLs] firstObject] path];
|
||||
|
@ -82,6 +82,7 @@ char *do_open_rom_dialog(void)
|
||||
gtk_file_filter_add_pattern(filter, "*.gb");
|
||||
gtk_file_filter_add_pattern(filter, "*.gbc");
|
||||
gtk_file_filter_add_pattern(filter, "*.sgb");
|
||||
gtk_file_filter_add_pattern(filter, "*.isx");
|
||||
gtk_file_filter_set_name(filter, "Game Boy ROMs");
|
||||
gtk_file_chooser_add_filter(dialog, filter);
|
||||
|
||||
|
@ -10,7 +10,7 @@ char *do_open_rom_dialog(void)
|
||||
dialog.lStructSize = sizeof(dialog);
|
||||
dialog.lpstrFile = filename;
|
||||
dialog.nMaxFile = sizeof(filename);
|
||||
dialog.lpstrFilter = L"Game Boy ROMs\0*.gb;*.gbc;*.sgb\0All files\0*.*\0\0";
|
||||
dialog.lpstrFilter = L"Game Boy ROMs\0*.gb;*.gbc;*.sgb;*.isx\0All files\0*.*\0\0";
|
||||
dialog.nFilterIndex = 1;
|
||||
dialog.lpstrFileTitle = NULL;
|
||||
dialog.nMaxFileTitle = 0;
|
||||
|
@ -13,6 +13,7 @@
|
||||
<array>
|
||||
<string>com.github.liji32.sameboy.gb</string>
|
||||
<string>com.github.liji32.sameboy.gbc</string>
|
||||
<string>com.github.liji32.sameboy.isx</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <Core/gb.h>
|
||||
|
||||
#include "get_image_for_rom.h"
|
||||
@ -60,7 +61,22 @@ int get_image_for_rom(const char *filename, const char *boot_path, uint32_t *out
|
||||
GB_set_log_callback(&gb, log_callback);
|
||||
GB_set_color_correction_mode(&gb, GB_COLOR_CORRECTION_EMULATE_HARDWARE);
|
||||
|
||||
if (GB_load_rom(&gb, filename)) {
|
||||
size_t length = strlen(filename);
|
||||
char extension[4] = {0,};
|
||||
if (length > 4) {
|
||||
if (filename[length - 4] == '.') {
|
||||
extension[0] = tolower(filename[length - 3]);
|
||||
extension[1] = tolower(filename[length - 2]);
|
||||
extension[2] = tolower(filename[length - 1]);
|
||||
}
|
||||
}
|
||||
if (strcmp(extension, "isx") == 0) {
|
||||
if (GB_load_isx(&gb, filename)) {
|
||||
GB_free(&gb);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (GB_load_rom(&gb, filename)) {
|
||||
GB_free(&gb);
|
||||
return 1;
|
||||
}
|
||||
|
18
SDL/main.c
18
SDL/main.c
@ -1,6 +1,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
#include <OpenDialog/open_dialog.h>
|
||||
#include <SDL.h>
|
||||
#include <Core/gb.h>
|
||||
@ -526,8 +527,23 @@ restart:
|
||||
}
|
||||
|
||||
bool error = false;
|
||||
GB_debugger_clear_symbols(&gb);
|
||||
start_capturing_logs();
|
||||
error = GB_load_rom(&gb, filename);
|
||||
size_t length = strlen(filename);
|
||||
char extension[4] = {0,};
|
||||
if (length > 4) {
|
||||
if (filename[length - 4] == '.') {
|
||||
extension[0] = tolower(filename[length - 3]);
|
||||
extension[1] = tolower(filename[length - 2]);
|
||||
extension[2] = tolower(filename[length - 1]);
|
||||
}
|
||||
}
|
||||
if (strcmp(extension, "isx") == 0) {
|
||||
error = GB_load_isx(&gb, filename);
|
||||
}
|
||||
else {
|
||||
GB_load_rom(&gb, filename);
|
||||
}
|
||||
end_capturing_logs(true, error);
|
||||
|
||||
size_t path_length = strlen(filename);
|
||||
|
Loading…
Reference in New Issue
Block a user