Merge branch 'master' into timing
# Conflicts: # Core/gb.c
This commit is contained in:
commit
18e32d1755
@ -476,7 +476,6 @@ void GB_reset(GB_gameboy_t *gb)
|
||||
|
||||
gb->is_cgb = true;
|
||||
gb->cgb_mode = true;
|
||||
gb->io_registers[GB_IO_OBP0] = gb->io_registers[GB_IO_OBP1] = 0x00;
|
||||
}
|
||||
else {
|
||||
gb->ram_size = 0x2000;
|
||||
@ -494,11 +493,14 @@ void GB_reset(GB_gameboy_t *gb)
|
||||
gb->sprite_palettes_rgb[7] = gb->sprite_palettes_rgb[3] = gb->background_palettes_rgb[3] =
|
||||
gb->rgb_encode_callback(gb, 0, 0, 0);
|
||||
}
|
||||
gb->io_registers[GB_IO_OBP0] = gb->io_registers[GB_IO_OBP1] = 0xFF;
|
||||
}
|
||||
/* The serial interrupt always occur on the 0xF7th cycle of every 0x100 cycle since boot. */
|
||||
gb->serial_cycles = 0x100-0xF7;
|
||||
gb->io_registers[GB_IO_SC] = 0x7E;
|
||||
|
||||
/* These are not deterministic, but 00 (CGB) and FF (DMG) are the most common initial values by far */
|
||||
gb->io_registers[GB_IO_DMA] = gb->io_registers[GB_IO_OBP0] = gb->io_registers[GB_IO_OBP1] = gb->is_cgb? 0x00 : 0xFF;
|
||||
|
||||
gb->magic = (uintptr_t)'SAME';
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ static GB_bus_t bus_for_addr(GB_gameboy_t *gb, uint16_t addr)
|
||||
|
||||
static bool is_addr_in_dma_use(GB_gameboy_t *gb, uint16_t addr)
|
||||
{
|
||||
if (!gb->dma_steps_left || (gb->dma_cycles < 0 && !gb->is_dma_restarting)) return false;
|
||||
if (!gb->dma_steps_left || (gb->dma_cycles < 0 && !gb->is_dma_restarting) || addr >= 0xFE00) return false;
|
||||
return bus_for_addr(gb, addr) == bus_for_addr(gb, gb->dma_current_src);
|
||||
}
|
||||
|
||||
@ -174,6 +174,7 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
|
||||
case GB_IO_WX:
|
||||
case GB_IO_SC:
|
||||
case GB_IO_SB:
|
||||
case GB_IO_DMA:
|
||||
return gb->io_registers[addr & 0xFF];
|
||||
case GB_IO_TIMA:
|
||||
if (gb->tima_reload_state == GB_TIMA_RELOADING) {
|
||||
@ -232,9 +233,6 @@ static uint8_t read_high_memory(GB_gameboy_t *gb, uint16_t addr)
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
case GB_IO_DMA:
|
||||
/* Todo: is this documented? */
|
||||
return gb->is_cgb? 0x00 : 0xFF;
|
||||
case GB_IO_UNKNOWN2:
|
||||
case GB_IO_UNKNOWN3:
|
||||
return gb->is_cgb? gb->io_registers[addr & 0xFF] : 0xFF;
|
||||
@ -516,21 +514,18 @@ static void write_high_memory(GB_gameboy_t *gb, uint16_t addr, uint8_t value)
|
||||
return;
|
||||
|
||||
case GB_IO_DMA:
|
||||
if (value <= 0xE0) {
|
||||
if (gb->dma_steps_left) {
|
||||
/* This is not correct emulation, since we're not really delaying the second DMA.
|
||||
One write that should have happened in the first DMA will not happen. However,
|
||||
since that byte will be overwritten by the second DMA before it can actually be
|
||||
read, it doesn't actually matter. */
|
||||
gb->is_dma_restarting = true;
|
||||
}
|
||||
gb->dma_cycles = -7;
|
||||
gb->dma_current_dest = 0;
|
||||
gb->dma_current_src = value << 8;
|
||||
gb->dma_steps_left = 0xa0;
|
||||
if (gb->dma_steps_left) {
|
||||
/* This is not correct emulation, since we're not really delaying the second DMA.
|
||||
One write that should have happened in the first DMA will not happen. However,
|
||||
since that byte will be overwritten by the second DMA before it can actually be
|
||||
read, it doesn't actually matter. */
|
||||
gb->is_dma_restarting = true;
|
||||
}
|
||||
/* else { what? } */
|
||||
|
||||
gb->dma_cycles = -7;
|
||||
gb->dma_current_dest = 0;
|
||||
gb->dma_current_src = value << 8;
|
||||
gb->dma_steps_left = 0xa0;
|
||||
gb->io_registers[GB_IO_DMA] = value;
|
||||
return;
|
||||
case GB_IO_SVBK:
|
||||
if (!gb->cgb_mode) {
|
||||
@ -708,7 +703,14 @@ void GB_dma_run(GB_gameboy_t *gb)
|
||||
/* Todo: measure this value */
|
||||
gb->dma_cycles -= 4;
|
||||
gb->dma_steps_left--;
|
||||
gb->oam[gb->dma_current_dest++] = GB_read_memory(gb, gb->dma_current_src);
|
||||
if (gb->dma_current_src < 0xe000) {
|
||||
gb->oam[gb->dma_current_dest++] = GB_read_memory(gb, gb->dma_current_src);
|
||||
}
|
||||
else {
|
||||
/* Todo: Not correct on the CGB */
|
||||
gb->oam[gb->dma_current_dest++] = GB_read_memory(gb, gb->dma_current_src & ~0x2000);
|
||||
}
|
||||
|
||||
/* dma_current_src must be the correct value during GB_read_memory */
|
||||
gb->dma_current_src++;
|
||||
if (!gb->dma_steps_left) {
|
||||
|
@ -161,7 +161,7 @@ CFLAGS += -Wall -D__LIBRETRO__ $(fpic) $(INCFLAGS) -std=gnu11 -D_GNU_SOURCE -D
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(CORE_DIR)/libretro/%_boot.c: $(CORE_DIR)/BootROMs/prebuilt/%_boot.bin
|
||||
$(CORE_DIR)/libretro/%_boot.c: $(CORE_DIR)/build/bin/BootROMs/%_boot.bin
|
||||
echo "/* AUTO-GENERATED */" > $@
|
||||
echo "const unsigned char $(notdir $(@:%.c=%))[] = {" >> $@
|
||||
ifneq ($(findstring Haiku,$(shell uname -s)),)
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
@ -81,7 +82,7 @@ static retro_input_poll_t input_poll_cb;
|
||||
static retro_input_state_t input_state_cb;
|
||||
|
||||
static unsigned emulated_devices = 1;
|
||||
static unsigned pre_init = 1;
|
||||
static bool initialized = false;
|
||||
static unsigned screen_layout = 0;
|
||||
static unsigned audio_out = 0;
|
||||
|
||||
@ -116,6 +117,25 @@ static void fallback_log(enum retro_log_level level, const char *fmt, ...)
|
||||
|
||||
static struct retro_rumble_interface rumble;
|
||||
|
||||
static void extract_basename(char *buf, const char *path, size_t size)
|
||||
{
|
||||
const char *base = strrchr(path, '/');
|
||||
if (!base)
|
||||
base = strrchr(path, '\\');
|
||||
if (!base)
|
||||
base = path;
|
||||
|
||||
if (*base == '\\' || *base == '/')
|
||||
base++;
|
||||
|
||||
strncpy(buf, base, size - 1);
|
||||
buf[size - 1] = '\0';
|
||||
|
||||
char *ext = strrchr(buf, '.');
|
||||
if (ext)
|
||||
*ext = '\0';
|
||||
}
|
||||
|
||||
static void GB_update_keys_status(GB_gameboy_t *gb, unsigned port)
|
||||
{
|
||||
|
||||
@ -201,40 +221,43 @@ static uint32_t rgb_encode(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b)
|
||||
|
||||
static retro_environment_t environ_cb;
|
||||
|
||||
static const struct retro_variable vars[] = {
|
||||
{ "sameboy_dual", "Dual Game Boy Mode (restart); disabled|enabled" },
|
||||
{ "sameboy_color_correction_mode", "Color Correction; off|correct curves|emulate hardware|preserve brightness" },
|
||||
{ "sameboy_high_pass_filter_mode", "High Pass Filter; off|accurate|remove dc offset" },
|
||||
{ "sameboy_model", "Emulated Model; Game Boy Color|Game Boy Advance|Auto|Game Boy" },
|
||||
/* variables for single cart mode */
|
||||
static const struct retro_variable vars_single[] = {
|
||||
{ "sameboy_dual", "Single cart dual mode (reload); disabled|enabled" },
|
||||
{ "sameboy_color_correction_mode", "Color correction; off|correct curves|emulate hardware|preserve brightness" },
|
||||
{ "sameboy_high_pass_filter_mode", "High-pass filter; off|accurate|remove dc offset" },
|
||||
{ "sameboy_model", "Emulated model (reload); Game Boy Color|Game Boy Advance|Auto|Game Boy" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static const struct retro_variable vars_sameboy_dual[] = {
|
||||
{ "sameboy_dual", "Dual Game Boy Mode (restart); disabled|enabled" },
|
||||
{ "sameboy_link", "Link Cable Emulation; enabled|disabled" },
|
||||
/* variables for single cart dual gameboy mode */
|
||||
static const struct retro_variable vars_single_dual[] = {
|
||||
{ "sameboy_dual", "Single cart dual mode (reload); disabled|enabled" },
|
||||
{ "sameboy_link", "Link cable emulation; enabled|disabled" },
|
||||
/*{ "sameboy_ir", "Infrared Sensor Emulation; disabled|enabled" },*/
|
||||
{ "sameboy_screen_layout", "Screen Layout; top-down|left-right" },
|
||||
{ "sameboy_screen_layout", "Screen layout; top-down|left-right" },
|
||||
{ "sameboy_audio_output", "Audio output; Game Boy #1|Game Boy #2" },
|
||||
{ "sameboy_model_1", "Emulated Model for Game Boy #1; Game Boy Color|Game Boy Advance|Auto|Game Boy" },
|
||||
{ "sameboy_model_2", "Emulated Model for Game Boy #2; Game Boy Color|Game Boy Advance|Auto|Game Boy" },
|
||||
{ "sameboy_color_correction_mode_1", "Color Correction for Game Boy #1; off|correct curves|emulate hardware|preserve brightness" },
|
||||
{ "sameboy_color_correction_mode_2", "Color Correction for Game Boy #2; off|correct curves|emulate hardware|preserve brightness" },
|
||||
{ "sameboy_high_pass_filter_mode_1", "High Pass Filter for Game Boy #1; off|accurate|remove dc offset" },
|
||||
{ "sameboy_high_pass_filter_mode_2", "High Pass Filter for Game Boy #2; off|accurate|remove dc offset" },
|
||||
{ "sameboy_model_1", "Emulated model for Game Boy #1 (reload); Game Boy Color|Game Boy Advance|Auto|Game Boy" },
|
||||
{ "sameboy_model_2", "Emulated model for Game Boy #2 (reload); Game Boy Color|Game Boy Advance|Auto|Game Boy" },
|
||||
{ "sameboy_color_correction_mode_1", "Color correction for Game Boy #1; off|correct curves|emulate hardware|preserve brightness" },
|
||||
{ "sameboy_color_correction_mode_2", "Color correction for Game Boy #2; off|correct curves|emulate hardware|preserve brightness" },
|
||||
{ "sameboy_high_pass_filter_mode_1", "High-pass filter for Game Boy #1; off|accurate|remove dc offset" },
|
||||
{ "sameboy_high_pass_filter_mode_2", "High-pass filter for Game Boy #2; off|accurate|remove dc offset" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static const struct retro_variable vars_link_dual[] = {
|
||||
{ "sameboy_link", "Link Cable Emulation; enabled|disabled" },
|
||||
/* variables for dual cart dual gameboy mode */
|
||||
static const struct retro_variable vars_dual[] = {
|
||||
{ "sameboy_link", "Link cable emulation; enabled|disabled" },
|
||||
/*{ "sameboy_ir", "Infrared Sensor Emulation; disabled|enabled" },*/
|
||||
{ "sameboy_screen_layout", "Screen Layout; top-down|left-right" },
|
||||
{ "sameboy_screen_layout", "Screen layout; top-down|left-right" },
|
||||
{ "sameboy_audio_output", "Audio output; Game Boy #1|Game Boy #2" },
|
||||
{ "sameboy_model_1", "Emulated Model for Game Boy #1; Game Boy Color|Game Boy Advance|Auto|Game Boy" },
|
||||
{ "sameboy_model_2", "Emulated Model for Game Boy #2; Game Boy Color|Game Boy Advance|Auto|Game Boy" },
|
||||
{ "sameboy_color_correction_mode_1", "Color Correction for Game Boy #1; off|correct curves|emulate hardware|preserve brightness" },
|
||||
{ "sameboy_color_correction_mode_2", "Color Correction for Game Boy #2; off|correct curves|emulate hardware|preserve brightness" },
|
||||
{ "sameboy_high_pass_filter_mode_1", "High Pass Filter for Game Boy #1; off|accurate|remove dc offset" },
|
||||
{ "sameboy_high_pass_filter_mode_2", "High Pass Filter for Game Boy #2; off|accurate|remove dc offset" },
|
||||
{ "sameboy_model_1", "Emulated model for Game Boy #1 (reload); Game Boy Color|Game Boy Advance|Auto|Game Boy" },
|
||||
{ "sameboy_model_2", "Emulated model for Game Boy #2 (reload); Game Boy Color|Game Boy Advance|Auto|Game Boy" },
|
||||
{ "sameboy_color_correction_mode_1", "Color correction for Game Boy #1; off|correct curves|emulate hardware|preserve brightness" },
|
||||
{ "sameboy_color_correction_mode_2", "Color correction for Game Boy #2; off|correct curves|emulate hardware|preserve brightness" },
|
||||
{ "sameboy_high_pass_filter_mode_1", "High-pass filter for Game Boy #1; off|accurate|remove dc offset" },
|
||||
{ "sameboy_high_pass_filter_mode_2", "High-pass filter for Game Boy #2; off|accurate|remove dc offset" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@ -418,10 +441,6 @@ static void check_variables(bool link)
|
||||
else
|
||||
new_model = MODEL_AUTO;
|
||||
|
||||
if (GB_is_inited(&gameboy[0]) && new_model != model[0]) {
|
||||
model[0] = new_model;
|
||||
init_for_current_model();
|
||||
}
|
||||
model[0] = new_model;
|
||||
}
|
||||
}
|
||||
@ -492,11 +511,7 @@ static void check_variables(bool link)
|
||||
new_model = MODEL_AGB;
|
||||
else
|
||||
new_model = MODEL_AUTO;
|
||||
|
||||
if (GB_is_inited(&gameboy[0]) && new_model != model[0]) {
|
||||
model[0] = new_model;
|
||||
init_for_current_model();
|
||||
}
|
||||
|
||||
model[0] = new_model;
|
||||
}
|
||||
|
||||
@ -513,11 +528,7 @@ static void check_variables(bool link)
|
||||
new_model = MODEL_AGB;
|
||||
else
|
||||
new_model = MODEL_AUTO;
|
||||
|
||||
if (GB_is_inited(&gameboy[1]) && new_model != model[1]) {
|
||||
model[1] = new_model;
|
||||
init_for_current_model();
|
||||
}
|
||||
|
||||
model[1] = new_model;
|
||||
}
|
||||
|
||||
@ -715,9 +726,10 @@ void retro_reset(void)
|
||||
|
||||
void retro_run(void)
|
||||
{
|
||||
|
||||
bool updated = false;
|
||||
|
||||
if (pre_init)
|
||||
if (!initialized)
|
||||
geometry_updated = false;
|
||||
|
||||
if (geometry_updated) {
|
||||
@ -727,8 +739,6 @@ void retro_run(void)
|
||||
environ_cb(RETRO_ENVIRONMENT_SET_GEOMETRY, &info.geometry);
|
||||
}
|
||||
|
||||
pre_init = 0;
|
||||
|
||||
if (!frame_buf)
|
||||
return;
|
||||
|
||||
@ -769,17 +779,19 @@ void retro_run(void)
|
||||
|
||||
video_cb(frame_buf_copy, VIDEO_WIDTH * emulated_devices, VIDEO_HEIGHT, VIDEO_WIDTH * emulated_devices * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
bool retro_load_game(const struct retro_game_info *info)
|
||||
{
|
||||
environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void *)vars);
|
||||
environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void *)vars_single);
|
||||
check_variables(false);
|
||||
if (sameboy_dual)
|
||||
{
|
||||
emulated_devices = 2;
|
||||
mode = MODE_SINGLE_GAME_DUAL;
|
||||
environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void *)vars_sameboy_dual);
|
||||
environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void *)vars_single_dual);
|
||||
check_variables(true);
|
||||
}
|
||||
else
|
||||
@ -821,11 +833,36 @@ bool retro_load_game(const struct retro_game_info *info)
|
||||
log_cb(RETRO_LOG_INFO, "Rumble environment not supported\n");
|
||||
|
||||
check_variables(emulated_devices == 2 ? true : false);
|
||||
|
||||
/* hack: use upstream's file based I/O for Game Boy 2 battery in single cart mode */
|
||||
if (mode == MODE_SINGLE_GAME_DUAL)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
char file[PATH_MAX];
|
||||
|
||||
extract_basename(file, retro_game_path, sizeof(file));
|
||||
snprintf (path, sizeof(path), "%s%c%s.srm.2", retro_save_directory, slash, file);
|
||||
log_cb(RETRO_LOG_INFO, "Loading battery for Game Boy 2 from: %s\n", path);
|
||||
GB_load_battery(&gameboy[1], path);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void retro_unload_game(void)
|
||||
{
|
||||
/* hack: use upstream's file based I/O for Game Boy 2 battery in single cart mode */
|
||||
if (mode == MODE_SINGLE_GAME_DUAL)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
char file[PATH_MAX];
|
||||
|
||||
extract_basename(file, retro_game_path, sizeof(file));
|
||||
snprintf (path, sizeof(path), "%s%c%s.srm.2", retro_save_directory, slash, file);
|
||||
log_cb(RETRO_LOG_INFO, "Saving battery for Game Boy 2 to: %s\n", path);
|
||||
GB_save_battery(&gameboy[1], path);
|
||||
}
|
||||
|
||||
for (int i = 0; i < emulated_devices; i++)
|
||||
GB_free(&gameboy[i]);
|
||||
}
|
||||
@ -846,7 +883,7 @@ bool retro_load_game_special(unsigned type, const struct retro_game_info *info,
|
||||
else
|
||||
return false; /* all other types are unhandled for now */
|
||||
|
||||
environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void *)vars_link_dual);
|
||||
environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void *)vars_dual);
|
||||
check_variables(true);
|
||||
|
||||
frame_buf = (uint32_t*)malloc(emulated_devices * VIDEO_PIXELS * sizeof(uint32_t));
|
||||
@ -897,18 +934,21 @@ size_t retro_serialize_size(void)
|
||||
|
||||
bool retro_serialize(void *data, size_t size)
|
||||
{
|
||||
if (pre_init == 1)
|
||||
|
||||
if (!initialized)
|
||||
return false;
|
||||
|
||||
void* save_data[2];
|
||||
size_t state_size[2];
|
||||
size_t offset = 0;
|
||||
|
||||
for (int i = 0; i < emulated_devices; i++)
|
||||
{
|
||||
state_size[i] = GB_get_save_state_size(&gameboy[i]);
|
||||
save_data[i] = (uint8_t*)malloc(state_size[i]);
|
||||
GB_save_state_to_buffer(&gameboy[i], (uint8_t*) save_data[i]);
|
||||
memcpy(data + (state_size[i] * i), save_data[i], state_size[i]);
|
||||
memcpy(data + offset, save_data[i], state_size[i]);
|
||||
offset += state_size[i];
|
||||
free(save_data[i]);
|
||||
}
|
||||
|
||||
@ -973,7 +1013,7 @@ void *retro_get_memory_data(unsigned type)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MODE_DUAL_GAME: /* todo: hook up other memory types */
|
||||
case MODE_DUAL_GAME:
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
@ -989,6 +1029,18 @@ void *retro_get_memory_data(unsigned type)
|
||||
else
|
||||
data = NULL;
|
||||
break;
|
||||
case RETRO_MEMORY_GAMEBOY_1_RTC:
|
||||
if(gameboy[0].cartridge_type->has_battery)
|
||||
data = &gameboy[0].rtc_real;
|
||||
else
|
||||
data = NULL;
|
||||
break;
|
||||
case RETRO_MEMORY_GAMEBOY_2_RTC:
|
||||
if(gameboy[1].cartridge_type->has_battery)
|
||||
data = &gameboy[1].rtc_real;
|
||||
else
|
||||
data = NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1033,7 +1085,7 @@ size_t retro_get_memory_size(unsigned type)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MODE_DUAL_GAME: /* todo: hook up other memory types */
|
||||
case MODE_DUAL_GAME:
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
@ -1049,8 +1101,16 @@ size_t retro_get_memory_size(unsigned type)
|
||||
else
|
||||
size = 0;
|
||||
break;
|
||||
case RETRO_MEMORY_GAMEBOY_1_RTC:
|
||||
if(gameboy[0].cartridge_type->has_battery)
|
||||
size = sizeof (gameboy[0].rtc_real);
|
||||
break;
|
||||
case RETRO_MEMORY_GAMEBOY_2_RTC:
|
||||
if(gameboy[1].cartridge_type->has_battery)
|
||||
size = sizeof (gameboy[1].rtc_real);
|
||||
break;
|
||||
default:
|
||||
break;;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user