Merge branch 'master' into timing

# Conflicts:
#	Core/gb.c
This commit is contained in:
Lior Halphon 2018-03-22 22:37:35 +02:00
commit 18e32d1755
4 changed files with 136 additions and 72 deletions

View File

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

View File

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

View File

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

View File

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